commit bdff548a085ee6280737442684f3dc02e57ac8ea Author: Daniel Bulant Date: Tue Jul 20 18:02:45 2021 +0200 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f40fbd8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +_site +.sass-cache +.jekyll-cache +.jekyll-metadata +vendor diff --git a/404.html b/404.html new file mode 100644 index 0000000..086a5c9 --- /dev/null +++ b/404.html @@ -0,0 +1,25 @@ +--- +permalink: /404.html +layout: default +--- + + + +
+

404

+ +

Page not found :(

+

The requested page could not be found.

+
diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..fb57eff --- /dev/null +++ b/Gemfile @@ -0,0 +1,37 @@ +source "https://rubygems.org" +# Hello! This is where you manage which Jekyll version is used to run. +# When you want to use a different version, change it below, save the +# file and run `bundle install`. Run Jekyll with `bundle exec`, like so: +# +# bundle exec jekyll serve +# +# This will help ensure the proper Jekyll version is running. +# Happy Jekylling! +gem "jekyll", "~> 4.2.0" +# This is the default theme for new Jekyll sites. You may change this to anything you like. +gem "minima", "~> 2.5" +# If you want to use GitHub Pages, remove the "gem "jekyll"" above and +# uncomment the line below. To upgrade, run `bundle update github-pages`. +# gem "github-pages", group: :jekyll_plugins +# If you have any plugins, put them here! +group :jekyll_plugins do + gem "jekyll-feed", "~> 0.12" +end + +# Table of contents plugin +gem 'jekyll-toc' +# Seo tag from minima +gem 'jekyll-seo-tag' + +# Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem +# and associated library. +platforms :mingw, :x64_mingw, :mswin, :jruby do + gem "tzinfo", "~> 1.2" + gem "tzinfo-data" +end + +# Performance-booster for watching directories on Windows +gem "wdm", "~> 0.1.1", :platforms => [:mingw, :x64_mingw, :mswin] + + +gem "webrick", "~> 1.7" diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..9634ac7 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,90 @@ +GEM + remote: https://rubygems.org/ + specs: + addressable (2.8.0) + public_suffix (>= 2.0.2, < 5.0) + colorator (1.1.0) + concurrent-ruby (1.1.9) + em-websocket (0.5.2) + eventmachine (>= 0.12.9) + http_parser.rb (~> 0.6.0) + eventmachine (1.2.7) + ffi (1.15.3) + forwardable-extended (2.6.0) + http_parser.rb (0.6.0) + i18n (1.8.10) + concurrent-ruby (>= 1.0) + jekyll (4.2.0) + addressable (~> 2.4) + colorator (~> 1.0) + em-websocket (~> 0.5) + i18n (~> 1.0) + jekyll-sass-converter (~> 2.0) + jekyll-watch (~> 2.0) + kramdown (~> 2.3) + kramdown-parser-gfm (~> 1.0) + liquid (~> 4.0) + mercenary (~> 0.4.0) + pathutil (~> 0.9) + rouge (~> 3.0) + safe_yaml (~> 1.0) + terminal-table (~> 2.0) + jekyll-feed (0.15.1) + jekyll (>= 3.7, < 5.0) + jekyll-sass-converter (2.1.0) + sassc (> 2.0.1, < 3.0) + jekyll-seo-tag (2.7.1) + jekyll (>= 3.8, < 5.0) + jekyll-toc (0.17.1) + jekyll (>= 3.9) + nokogiri (~> 1.11) + jekyll-watch (2.2.1) + listen (~> 3.0) + kramdown (2.3.1) + rexml + kramdown-parser-gfm (1.1.0) + kramdown (~> 2.0) + liquid (4.0.3) + listen (3.5.1) + rb-fsevent (~> 0.10, >= 0.10.3) + rb-inotify (~> 0.9, >= 0.9.10) + mercenary (0.4.0) + minima (2.5.1) + jekyll (>= 3.5, < 5.0) + jekyll-feed (~> 0.9) + jekyll-seo-tag (~> 2.1) + nokogiri (1.11.7-x86_64-linux) + racc (~> 1.4) + pathutil (0.16.2) + forwardable-extended (>= 2.6) + public_suffix (4.0.6) + racc (1.5.2) + rb-fsevent (0.11.0) + rb-inotify (0.10.1) + ffi (>= 1.0) + rexml (3.2.5) + rouge (3.26.0) + safe_yaml (1.0.5) + sassc (2.4.0) + ffi (~> 1.9) + terminal-table (2.0.0) + unicode-display_width (~> 1.1, >= 1.1.1) + unicode-display_width (1.7.0) + webrick (1.7.0) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + jekyll (~> 4.2.0) + jekyll-feed (~> 0.12) + jekyll-seo-tag + jekyll-toc + minima (~> 2.5) + tzinfo (~> 1.2) + tzinfo-data + wdm (~> 0.1.1) + webrick (~> 1.7) + +BUNDLED WITH + 2.2.24 diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000..45f09f7 --- /dev/null +++ b/_config.yml @@ -0,0 +1,54 @@ +# Welcome to Jekyll! +# +# This config file is meant for settings that affect your whole blog, values +# which you are expected to set up once and rarely edit after that. If you find +# yourself editing this file very often, consider using Jekyll's data files +# feature for the data you need to update frequently. +# +# For technical reasons, this file is *NOT* reloaded automatically when you use +# 'bundle exec jekyll serve'. If you change this file, please restart the server process. +# +# If you need help with YAML syntax, here are some quick references for you: +# https://learn-the-web.algonquindesign.ca/topics/markdown-yaml-cheat-sheet/#yaml +# https://learnxinyminutes.com/docs/yaml/ +# +# Site settings +# These are used to personalize your new site. If you look in the HTML files, +# you will see them accessed via {{ site.title }}, {{ site.email }}, and so on. +# You can create any custom variable you would like, and they will be accessible +# in the templates via {{ site.myvariable }}. + +title: text.danbulant.eu +email: danbulant@danbulant.eu +description: >- # this means to ignore newlines until "baseurl:" + Online gist viewer for my text files. +baseurl: "" # the subpath of your site, e.g. /blog +url: "" # the base hostname & protocol for your site, e.g. http://example.com +twitter_username: danbulant +github_username: danbulant + +# Build settings +plugins: + - jekyll-feed + - jekyll-toc + - jekyll-seo-tag + +# Exclude from processing. +# The following items will not be processed, by default. +# Any item listed under the `exclude:` key here will be automatically added to +# the internal "default list". +# +# Excluded items can be processed by explicitly listing the directories or +# their entries' file path in the `include:` list. +# +# exclude: +# - .sass-cache/ +# - .jekyll-cache/ +# - gemfiles/ +# - Gemfile +# - Gemfile.lock +# - node_modules/ +# - vendor/bundle/ +# - vendor/cache/ +# - vendor/gems/ +# - vendor/ruby/ diff --git a/_includes/head.html b/_includes/head.html new file mode 100644 index 0000000..2d27e0b --- /dev/null +++ b/_includes/head.html @@ -0,0 +1,12 @@ + + + + + {%- seo -%} + + {%- feed_meta -%} + {%- if jekyll.environment == 'production' and site.google_analytics -%} + {%- include google-analytics.html -%} + {%- endif -%} + + \ No newline at end of file diff --git a/_layouts/default.html b/_layouts/default.html new file mode 100644 index 0000000..60f94c0 --- /dev/null +++ b/_layouts/default.html @@ -0,0 +1,32 @@ + + + + {%- include head.html -%} + + + + {% unless page.isTop %} + + Go back | {{ page.dir }} + + {% endunless %} +
+
+ {{ content }} +
+ +
+ + + + + diff --git a/assets/main.css b/assets/main.css new file mode 100644 index 0000000..7222766 --- /dev/null +++ b/assets/main.css @@ -0,0 +1,292 @@ +--- +# Frontmatter needed +--- +.reset{} /* Reset coding errors */ +a.heading-link { + visibility: hidden; + padding-right: 6px; + vertical-align: middle; + position: absolute; + top: 0; + top: calc((0.7em - 10px)/2); + left: -0.8em; + left: calc(-0.7em - 3px); + background: url("/link.svg"); + display: inline-block; + text-decoration: none; + background-repeat: no-repeat; + width: 0.7em; + width: calc(0.7em - 2px); + height: 0.7em; + height: calc(0.7em - 2px); +} +h1, h2, h3, h4, h5, h6 { + position: relative; +} +h1:hover a, h2:hover a, h3:hover a, h4:hover a, h5:hover a, h6:hover a { + visibility: visible; +} +.hljs { + background: inherit; +} +html { + color: #bfbfbf; + filter: contrast(100%) brightness(100%) saturate(100%); + color: rgb(180, 188, 202) !important; + background: rgb(31, 31, 31) !important; +} + +body { + background-image: none !important; + margin: 0 auto; + font-family: Roboto, Georgia, Palatino, serif; + line-height: 1; + max-width: 600px; + padding: 30px; + display: flex; + flex-direction: column; + min-height: calc(100vh - 60px); +} +.content { + flex-grow: 1; +} +@media(min-width: 675px) { + body { + margin-left: calc((100vw - 660px)/3); + } +} +@media(max-width: 1000px) and (min-width: 660px) { + body { + margin-left: calc((100vw - 660px)/4); + } +} +h1, h2, h3, h4 { + color: rgb(191, 191, 191); + font-weight: 400; +} +h1, h2, h3, h4, h5, p { + margin-bottom: 24px; + padding: 0; +} +h1 { + font-size: 48px; +} +h2 { + font-size: 36px; + margin: 24px 0 6px; +} +h3 { + font-size: 24px; +} +h4 { + font-size: 21px; +} +h5 { + font-size: 18px; +} +a { + color: rgb(157, 157, 231); + margin: 0; + padding: 0; + vertical-align: baseline; +} +a.active { + color: rgb(188, 221, 255); +} +ul, ol { + padding: 0; + margin: 0; +} +li { + line-height: 24px; +} +li ul, li ul { + margin-left: 24px; +} +p, ul, ol { + font-size: 16px; + line-height: 24px; + max-width: 540px; +} +pre { + padding: 0px 24px; + max-width: 600px; + white-space: pre-wrap; +} +code { + font-family: Consolas, Monaco, Andale Mono, monospace; + line-height: 1.5; + font-size: 13px; +} +aside { + display: block; + float: right; + width: 390px; +} +blockquote { + margin: 0; + border-left: 2px solid rgb(180, 188, 202); + padding: 0em 2em; + max-width: 476px; +} +blockquote p { + color: rgb(180, 188, 202); + max-width: 460px; +} +hr { + width: 540px; + text-align: left; + margin: 0 auto 0 0; + color: #999; +} +table { + border-collapse: collapse; + margin: 1em 1em; + border: 1px solid #CCC; +} +table thead td { + color: #666; +} +table td { + padding: 0.5em 1em; + border: 1px solid #CCC; +} +footer { + margin-top: 30px; +} + +*::-webkit-scrollbar-track-piece { + background-color: rgba(255, 255, 255, 0.2) !important; +} + +*::-webkit-scrollbar-track { + background-color: rgba(255, 255, 255, 0.3) !important; +} + +*::-webkit-scrollbar-thumb { + background-color: rgba(255, 255, 255, 0.5) !important; +} +input, +select, +textarea, +button { + color: #bfbfbf; + background-color: #1f1f1f; +} + +font { + color: #bfbfbf; +} + +aside { + position: fixed; + top: 10px; + right: 10px; + width: calc((100vw - 660px)/3*2); + height: calc(100vh - 20px); + overflow-x: auto; +} +@media (max-width: 1000px) { + aside { + width: calc((100vw - 660px)/4*3); + } +} +@media (max-width: 910px) { + aside { + display: none; + } +} + +.blue { + color: rgb(153, 153, 230); +} + +.red { + color: red; +} + +.purple { + color: rgb(230, 153, 230); +} + +::selection { + background: #338ccc; + color: #fff; +} + +::-moz-selection { + background: #338ccc; + color: #fff; +} + +::-webkit-scrollbar { + width: 14px; + height: 14px; +} + +::-webkit-scrollbar-button { + background-color: #3e4346 !important; +} + +::-webkit-scrollbar-track { + background-color: #646464 !important; +} + +::-webkit-scrollbar-track-piece { + background-color: #3e4346 !important; +} + +::-webkit-scrollbar-thumb { + height: 50px; + background-color: #242424 !important; + border: 2px solid #3e4346 !important; +} + +::-webkit-scrollbar-corner {} + +::-webkit-resizer {} + +::-webkit-scrollbar-button:vertical:start:decrement { + background: + linear-gradient(130deg, #696969 40%, rgba(255, 0, 0, 0) 41%), + linear-gradient(230deg, #696969 40%, rgba(0, 0, 0, 0) 41%), + linear-gradient(0deg, #696969 40%, rgba(0, 0, 0, 0) 31%); + background-color: #b6b6b6; +} + +::-webkit-scrollbar-button:vertical:end:increment { + background: + linear-gradient(310deg, #696969 40%, rgba(0, 0, 0, 0) 41%), + linear-gradient(50deg, #696969 40%, rgba(0, 0, 0, 0) 41%), + linear-gradient(180deg, #696969 40%, rgba(0, 0, 0, 0) 31%); + background-color: #b6b6b6; +} + +::-webkit-scrollbar-button:horizontal:end:increment { + background: + linear-gradient(210deg, #696969 40%, rgba(0, 0, 0, 0) 41%), + linear-gradient(330deg, #696969 40%, rgba(0, 0, 0, 0) 41%), + linear-gradient(90deg, #696969 30%, rgba(0, 0, 0, 0) 31%); + background-color: #b6b6b6; +} + +::-webkit-scrollbar-button:horizontal:start:decrement { + background: + linear-gradient(30deg, #696969 40%, rgba(0, 0, 0, 0) 41%), + linear-gradient(150deg, #696969 40%, rgba(0, 0, 0, 0) 41%), + linear-gradient(270deg, #696969 30%, rgba(0, 0, 0, 0) 31%); + background-color: #b6b6b6; +} + +.hljs{display:block;overflow-x:auto;padding:.5em;color:#abb2bf;} +.hljs-comment,.hljs-quote{color:#9199a7;font-style:italic} +.hljs-doctag,.hljs-formula,.hljs-keyword{color:#c678dd} +.hljs-deletion,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-subst{color:#e06c75} +.hljs-literal{color:#56b6c2} +.hljs-addition,.hljs-attribute,.hljs-meta-string,.hljs-regexp,.hljs-string{color:#98c379} +.hljs-built_in,.hljs-class .hljs-title{color:#e6c07b} +.hljs-attr,.hljs-number,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-pseudo,.hljs-template-variable,.hljs-type,.hljs-variable{color:#d19a66} +.hljs-bullet,.hljs-link,.hljs-meta,.hljs-selector-id,.hljs-symbol,.hljs-title{color:#61aeee} +.hljs-emphasis{font-style:italic} +.hljs-strong{font-weight:700} +.hljs-link{text-decoration:underline} \ No newline at end of file diff --git a/ids.company/igni_actions.md b/ids.company/igni_actions.md new file mode 100644 index 0000000..8e61cef --- /dev/null +++ b/ids.company/igni_actions.md @@ -0,0 +1,528 @@ +--- +layout: default +toc: true +footer: (c) ids.company 2021 +--- +# igni actions proposal + +Actions are a way for developers to extend igni on a per-server basis. Actions: +* are part of modules (each action must belong to a module) +* can have settings (for member, user, or server), settings may or may not be editable from the website (as defined by [module.json](#module.json)) +* can have a service, which consists of at least one event listener and/or intervals +* must have at least one command + +## SDK + +Modules and actions are to be developed using our SDK. The SDK consists of Commando (the main library for commands and services, edited to serve our needs) and the command-line utility (imm). + +### Commando + +Commando should work nearly identically to [`@iceprod/discord.js-commando`](https://github.com/iceproductions/commando), with its differences being: +* Commands and event handlers MUST await all its promises, as the process may be killed at __any__ time after the function returns. +* Collectors are not to be passed a function directly, instead, you should pass a name of the function __in the same class__. +* There's no guilds property on the client, the only guild available is the one the event originated from. +* Embeds MUST be used when sending direct messages, sending plain text is not supported. +* Footers will be ignored when sending direct messages, instead, the following is used: `via , `. +* Direct messages are rate limited to 5 *total* per event run. Edits don't count, deleted messages will still count towards the total (as this state isn't shared). +* New settings function: getSettingsFromModule accepting `module`, `setting` and (optionally) `default` value. Used for getting public settings of other modules. Throws an error if module doesn't exist or if setting is private. +* New method on guild: isModuleInstalled accepting `module` (string). + +### IMM (igni module manager) + +#### Installation + +To install, you can run `npm i -g imm` as administrator (or using `sudo` on Linux) or use the `npx imm setup` command which will also create a bare project to get started with. + +#### module.json + +Module file is used for setting properties of the module bundle. + +Required fields: +* **name** - The code name to be used for the module. It will appear in URLs and can be used to get help. Must be unique in the account. Must be of the following RegEx: `[A-Za-z][0-9a-zA-Z_-]{2,15}` +* **display_name** - The display name of the module, will be used for UI (in help, in module listing...). Can be any character (must be a valid text to get verified, emoji must not be used in public modules.) +* **lang** - Language to use, currently only supported is `node`. + +Optional fields +* **team** - Not used, reserved for future use. +* **version** - The version of language, defaults to `latest`. Semantic versioning accepted. +* **entry** - The entry file to start, defaults to the default entry file of selected language. +* **settings** - An array of objects with `name`, `type`, `description` and optionally `default`. +* **public** - Array of settings that are readable by other modules. + +##### Module settings + +* `name` - must be a valid settings name, will directly be saved into guild settings as-is. Must pass the following RegEx: `[a-z][a-z0-9-_]{2,15}` +* `type` - must be one of the following (case insensitive): `string`, `text` (multiline), `switch` (alias `bool` and `boolean`; results in boolean), `integer`, `float` (alias `number`), `range` (alias `integer-range`), `float-range` and `date`. +* `from` - Optionally, only allowed for number types. Specifies the minimum number. Must be valid to that type. +* `to` - Same as previous. +* `oneOf` - Optional array of possible values, if set `from`, and `to` are ignored. Not usable for `switch` and `range`s. +* `default` - Specifies the default value, makes it optional (when a required setting is not filed, the module will not be active). As long as it's set, it makes the setting optional (you can use `null` as the default variable too). + +Ranges are returned in the format of an array with 2 elements. Dates are returned as a stringified Date object (`(new Date).toString()`). + +###### Example + +```json +{ + "name": "example-module", + "display_name": "Example module", + "lang": "node" +} +``` + +### Commands + +#### `setup` + +Setups the project from start (interactively). Creates a `package.json` for npm, installs the required dependencies, creates `module.json`, and attempts (or guides you how) to install `imm` globally. Can be used directly from `npx`. + +#### `init` + +Will initialize the `module.json` file with specified options. `-y` (alias `--yes`) flag to use default values. + +#### `publish` + +Uploads the module to igni. Requires user to be logged in. + +#### `login` (alias `connect`) + +Creates a link to login via discord. + +#### `logout` (alias `disconnect`) + +Logs out the current user. + +#### `run` (alias `test`) + +Runs the test bot. Uses token from `DISCORD_TOKEN` environmental variable (also uses `.env` file), `token.txt` or `--token` (`--token `) flag. +No settings are preserved during restarts. Uses lots of debugging statements, so performance may be lower than on igni. + +### Supported languages + +#### Node + +The latest long-term support (LTS) release supported, backward compatibility is on the best effort basis. Entry file is `index.js`. + +##### Getting started with node + +To start with node, run `npx imm setup node`. It will create a folder with all the required files while installing imm globally (if needed). + +A sample `index.js` file to use: +```js +const igni = require("igni"); + +igni + .registerCommandsIn("cmd") + .registerDefaultTypes() + .registerServicesIn("services"); +``` + +A sample folder structure: +```plaintext +project/ + cmd/ + services/ + index.js + module.json + package.json +``` + +Command folder (`cmd`) expects to directly have files (folder structure is flattened, so you can group commands). +Service folder (`services`) expects to directly have files or grouped files (Grouped services can be managed per group or per service). Further levels are flattened. + +> **optional:** Use eslint with `require-await` rule. It's recommended as it's needed for getting verified (there can't be any side-effect promise functions). + +### .immignore file + +`.immignore` file is used for ignoring files to be uploaded. Its format is identical to `.gitignore` and `.npmignore`. + +IMM ignores by default the folder `node_modules` and the file `package-lock.json`. + +### Maximum size + +The file system allows 32MB of space (including dependencies). Trying to use more will result in an error and the module failing to start. Verification increases the limit (per case). + +## Modules + +Modules are a bundle of actions. Its properties are defined by [module.json](#module.json) in the top directory of the module. + +Global variables will not work. + +### Commands + +Commands are defined similarly to normal commando commands. Nearly any command working in commando will work in igni actions. + +For collectors, you need to refactor the code to be stateless (the process may get restarted before the collector handler is started) and to use a method in the command class instead of directly passing a callback function. +Await reactions/messages will not work (and are not defined). Filters are needed to be passed as method names too. Collectors now accept a third parameter, ID which is used to share state id. Must be short, you can usually use message ID. +ID must be a string or number (`toString` method will be used). + +```js +module.exports = class Command extends commando.Command { + // ... constructor + run(msg) { + var collector = this.createMessageCollector( + msg.channel, + "collectFilter", + { + time: 15000, + errors: ["time"] + } + ); + collector.collect("collect", msg.id); + collector.error("collectError", msg.channel.id); + return msg.reply("Reply with any message"); + } + + async collectError(error, id) { + var channel = await client.channels.fetch(id); + channel.reply("No message was sent"); + } + + collectFilter(msg, id) { + return true; // accept any message + } + + async collect(msg, id) { + var original = await msg.channel.messages.fetch(id); + msg.reply("You replied with " + msg.content + " to `" + original.content + "`."); + } +} +``` + +### Services + +Services are a set of event handlers and intervals. Most events will be used, except for those that cannot be linked to guilds (thus the action runner can't see which actions to run). + +Intervals have a requirement of being static (you can't change the interval length or add intervals while the action is running, only in the service definition.). Services must have a name where the same rules as for command names apply (must be unique across services). + +For message event, do NOT use it if you can write a RegEx for it - it will be much faster to create a command with a pattern set (e.g. to create `owo` counter, create a command where its pattern is `\bowo\b`.). +It will also use less CPU time, thus actions may be cheaper. Event handlers now also allow third parameter - options, which may specify a rule for the event. Again, it's to make things as fast as possible, so we want to run the handler the least possible times. + +Both intervals and event handlers require all promises to be awaited (in the same way as commands). + +```js +module.exports = class Service extends commando.Service { + name = "test-service"; + load() { + this.on("guildMemberAdd", "memberAdd", { + settings: { + guild: { + "join-channel": true // requires join-channel to be set and non-falsy. Use null to allow falsy values. Use false to require the setting NOT to be set. + } + } + }) + } + + async memberAdd(member) { + var channelID = await member.guild.settings.get("join-channel"); + try { + var channel = await member.guild.channels.fetch(channelID); + } catch(e) { // if channel gets deleted, fail silently + await member.guild.sendNotification({ // send notification to guild administrators + type: "warning", + content: "Test service cannot find channel " + channelID + }); + await member.guild.settings.set("join-channel"); // setting to undefined removes the setting, thus disabling this service + return; + } + try { + await channel.send(`${member.displayName} joined the server!`); + } catch(e) { + await member.guild.sendNotification({ + type: "warning", + content: "Test service cannot send messages to channel " + channel.name + }); + await member.guild.settings.set("join-channel"); + } + } +} +``` + +#### Alternate services format idea + +Have services use callbacks (like currently in commando) and instead of callback names just use the service name and find it in a map (then each map would have an array of callbacks to call). + +#### Event rules + +Event rules are an object that's used as 3rd parameter in event handlers. It's properties are `settings`, containing object with `guild`, `member` and/or `user` that each contain setting name mapped to `true` (set and non-falsy), `null` (set) or `false` (not set). + +Another property is `clientPermissions`, which is an array of permissions that are needed for the handler to be usable and `userPermissions`, ignored by events where action runner can't get a user, for an array of permissions a user needs to have. + +It also haves a property `manageable`, which specified if the dashboard should allow enabling/disabling the event handler. This requires another property, `name` to be set (display name for event handler), and allowing +optional property `description`. + +**Example:** +```js +{ + settings: { + member: { + allowLevelup: true + } + }, + clientPermissions: ["EMBED_LINKS"], + manageable: true, + name: "Level up messages", + description: "Sends a level up message to specified channel whenever a user levels up." +} +``` + + +#### Intervals + +Intervals need to be at least 30 minutes apart and are NOT guaranteed to be in exact times (action runner may be few seconds to minutes late/too fast or the interval may not be run at all). +You cannot set multiple intervals to the same handler and each service is limited to 2 intervals. The interval handler is run for every guild separately. + +They need to be static (intervals cannot change their time once they're defined) and cannot be added on runtime. You can disable intervals using the `disableInterval` method and enable them back by using the `enableInterval` method, +you cannot add new handlers once the service is loaded (you can only use this on the already-enabled intervals). Those methods exist on the client, so you can use them in commands as well (they're saved into `-interval-` setting). + +You can check the next scheduled time for an interval by `getInterval` which returns the next `Date` object, representing the time at which the handler should be called. + +Intervals allow a 3rd parameter similar to event rules, except `userPermissions`, member settings, and user settings are ignored. Guild settings are moved directly into settings. + +```js + +module.exports = class Service extends commando.Service { + name = "test-interval-service"; + load() { + this.setInterval("bumpNotification", 2 * 60 * 1000, { + settings: { + "bump-channel": true + }, + name: "Bump notification", + mamageable: true, + description: "Sends a message every 2 hours to specified channel." + }); // ran every two hours + } + + async bumpNotification(guild) { + var channelID = await guild.settings.get("bump-channel"); + try { + var channel = await guild.channels.fetch(channelID); + } catch(e) { + await guild.settings.set("bump-channel"); + return await guild.sendNotification({ // send notification to guild administrators + type: "warning", + content: "Test interval service cannot find channel " + channelID + }); + } + try { + await channel.send({ + embed: { + title: "Bump", + description: "You can use the `bump` command now." + } + }); + } catch(e) { + await guild.settings.set("bump-channel"); + await guild.sendNotification({ // send notification to guild administrators + type: "warning", + content: "Test interval service cannot send messages to " + channel.name + }); + } + } +} +``` + +### Getting started + +To get started, create a node project with commando, init `imm` and start working on commands and services. To ease this process, you can use `npx imm setup` to guide you on how to set up your project. + +## Timeouts + +* initial run (loading services and commands) **10 seconds** +* types (validating and parsing arguments) **2 seconds** each, **5 seconds** total +* command run **30 seconds** +* interval **15 seconds** +* event handler **30 seconds**, max 2 simultaneously of the same type, others will be buffered +* collectors **1 minute** (after that, they will be canceled and error callback will be run if `time` is in error array), one per command run simultaneously of the same type (you can have reaction and message collector at the same time) + +## Verification + +Module verification will be needed for the module to be available publicly on igni. The requirements are as follows: + +* No errors - the bot should not ever respond with an error. If the command showing an error is optional, it may not prevent the verification but the command will be disabled. +* Checks permissions - when the bot performs an operation that normally requires permissions, the command should check the user has given permissions (using the `userPermissions` property). +* Timeouts are not exceeded - the timeouts must be fulfilled to be verified, favorably with some time margin. Timeouts may be increased when given a good enough reason. +* No side-effect promises - promises must be awaited (at least in the end before returning using the `await Promise.all` method) before the command/service returns. +* The module accomplishes something - set a goal and fulfill it, don't have just some empty commands. +* Doesn't break any TOS or laws, including copyright. Using a free API (or paid one with a legally obtained token) is fine, scraping sites that explicitly forbid it is not. +* Has a description - this means that the module has a semi-unique name and a description describing most (if not all) of its features and that each command has its own description. +* Name must have readable characters - that's not limited to English (if you're making a module for the Chinese market, you can use Chinese characters) but it doesn't include emojis. Emojis can be in the name, but limit them to two maximum. + +## Pricing + +Github actions-like pricing might be used, i.e. per-minute pricing for each run. Each server could have a set of minutes for free (might be set on member range so bigger servers would have a bit more free minutes). + +Github pricing: +| Plan | Disk space (settings space?) | Minutes | +| ---- | ---------------------------- | ------- | +| GitHub Free | 500 MB | 2,000 | +| GitHub Pro (4$/month) | 1 GB | 3,000 | + +## Implementation details + +### Initial run + +* load all commands and services +* save their metadata into the database (for help, dashboard, and info needed for running) +* exit + +### Cold start + +When the module is started after some time of inactivity. + +The module should listen on the port specified by IGNI_PORT (defaulting to 3000). + +* load commands or services based on what's needed first +* run the required services/commands +* load the rest + +### Warm start + +* run the required services/commands + +### Context + +In the node context, setTimeout, setInterval, and setImmediate should be undefined. Instead, `awaitTimeout` should return a promise that resolves after *x* ms. + +Promises could be proxied so that whenever a promise doesn't return before the command returns, a warning/error would be shown. We could also recommend using the `require-await` eslint rule. + +### Communication + +Communication should be done by WebSockets. Port TBD. + +Types should be similar to API returned (using the `toJSON` method). + +#### Nonces + +Nonces are optional for requests, in which case the server should respond with the same nonce. + +#### Command runs + +```json +{ + "type": "commandRun", + "message": { + "content": "command-name arg1 arg2", + ... + }, + "guild": { ... }, + "member": { ... }, + "author": { ... } +} +``` + +#### Event runs + +Params contain the same fields as in discord.js event handlers. +```json +{ + "type": "...", + "params": [ ... ] +} +``` + +#### Settings + +Request: +```json +{ + "type": "settings", + "sub": "guild", + "nonce": "xxx" +} +``` + +Data: +```json +{ + "type": "settings", + "sub": "guild", + "nonce": "xxx", + "data": { ... } +} +``` + +Setting data in request results in updating settings. + +#### Fetching objects + +Responses should be the same as using default API, using the `toJSON` method. + +```json +{ + "type": "channel", + "id": "287158" +} +{ + "type": "user", // alias member + "id": "177013" +} +{ + "type": "channels" +} +{ + "type": "members", + "query": "..." +} +``` + +#### Registering collector + +```json +{ + "type": "collector", + "sub": "message", // or reaction + "channel": "287158", + "options": { + "time": 15000, + "errors": ["time"] + }, + "callbacks": { + "filter": "command:collectFilter", + "collect": "command:collect", + "error": "collect:collectError" + } +} +``` + +#### Running callbacks + +If the filter passes, the action runner should automatically run the callback while replying. +```json +{ + "type": "collectorError", + "sub": "command:collectError", + "id": "123456", + "error": { + "reason": "time", + ... + } +} +{ + "type": "collectorFilter", + "sub": "command:collectFilter", + "callback": "command:collect", + "id": "123456", + "message": { ... } +} +``` + +#### Collector filter reply + +Sent to action runner. +```json +{ + "type": "collectorFilterReply", + "id": "123456", + "message": "123457", // message id + "value": true // boolean +} +``` + +## Revisions + +**Rev 1** +* Added `public` optional field to [module.json](#module.json). +* Added functions `getSettingFromModule` and `isModuleInstalled` to [commando](#commando). +* Added `nonce`s to [Communication](#communication). \ No newline at end of file diff --git a/ids.company/index.md b/ids.company/index.md new file mode 100644 index 0000000..6dd5ac5 --- /dev/null +++ b/ids.company/index.md @@ -0,0 +1,11 @@ +--- +layout: default +toc: true +footer: (c) ids.company 2021 +--- +# ids.company + +## Project ideas + +* [igni actions](./igni_actions) +* [profiles](./profiles) \ No newline at end of file diff --git a/ids.company/profiles.md b/ids.company/profiles.md new file mode 100644 index 0000000..87f9e2d --- /dev/null +++ b/ids.company/profiles.md @@ -0,0 +1,41 @@ +--- +layout: default +toc: true +footer: (c) ids.company 2021 +--- +# Profiles + +## General info + +Profiles should be saved into Jem (which should then be used for connecting other services to user account). + +They should contain the following: + +* name (directly tied to discord tag, possibly just have option to include the discriminator) +* description (some sort if public bio) +* viewable (so users can choose who can view their profile) +* avatar (might as well be tied to discord avatar) +* possibly background (depends on the style of profile pages; possibly premium only) +* badges (for verified developers, igni developers, bug hunters...) + +And other optional fields (e.g. birth date, gender...) that may or may not be public. + +## Finding friends + +The bot could be used for finding friends or people with similar interests - the base function could be searching for people in same server who have a game account connected to their jem/discord one. Additionally, the bot could also search for people of a set gender or around given age (not exact). + +### Skill level + +For games, the bot could also save "skill level" of sorts (for games where it's possible, their global rank) and then could sort people who have similar skill levels. + +## Moderation + +Profiles should be also used for global moderation of sorts - when user gets banned in a server, it could broadcast that ban and it's reason to other servers (and could be visible in user's history). + +This function should be controlled to not be abused, so for example only servers with member count above a certain treshold would broadcast their bans/kicks/warns. + +It should be also usable in automoderation (for example if the user is frequently flagged as a bot, igni should require higher verification minimum, or when a user is frequently warned for spamming igni should give higher sanctions). + +## Privacy + +Actions should have access to these profiles only limited and as per settings. Only the discord info itself (name, avatar), description (if profile set to public or if action ran from user) and the banner. Other fields only when action explicitly requests and is verified (and are allowed to do so). diff --git a/igni/README.md b/igni/README.md new file mode 100644 index 0000000..416518a --- /dev/null +++ b/igni/README.md @@ -0,0 +1,2799 @@ +--- +layout: default +toc: true +footer: (c) Copyright ids.company 2021. +--- + +# Igni + +**We highly recommend reading through this description before inviting the bot to see how it works.** + +Igni is a universal all-in-one bot. It's the next generation of bots, starting with a unique command handling - if you make a typo, for most commands, you can just edit the command and the bot will update it's reply, even if the previous message didn't start with a correct prefix. That means it's easier as you don't have to type out the entire command, and also less messages in chat so you can stay focused on having a nice conversation rather than typing commands. + +## Things to know + +* Prefix can have spaces after, so for example `!` will also match `! `. Make sure to not use `>` as that's how quotes start. +* The bot will ask for arguments, use cancel if you don't want to reply (or wait the default 30s timeout). + +## No more pings + +Any command that requires a user to be selected can be called without a ping - just type the users name, nickname or tag. + +## No more retyping commands + +If you missed a required parameter for a command, the bot will just ask for it. Just send the parameter as a message instead of retyping the whole command. + +## Many commands + +You don't need 20 bots, each doing their own thing. In past, you had to because the universal bots did many things, but most of them poorly. Igni does many things as well, but we focused on one thing at a time so you (the user) have a pleasant experience. + +## Aztec user? + +Igni is the reincarnation of Aztec. As such, we had done a way to move all your data to igni (we didn't move any data without your consent). Simply use the **aztec** command `deprecated` to get all the steps required to move. + +## More to come soon + +We didn't stop on the development of the bot! We're still working on features such as web dashboard, custom commands, templates and more. Be sure to join our support server for any news we might have! + +## Testing + +We have a separate server for testing the bot and talking about it's development. If you want to be more involved, you can join [here](https://discord.gg/EJujSYv). + +These features are not stable and/or have known bugs: +* Music playback +* investments + +## Temporary features + +Some features are still in testing and may **be reset at any time**. +* Tickets - we're currenlty working on a much better ticket system than the current one that will be at *least* on the same level as bots dedicated to tickets (might mean that the tickets created before the change may not be manageable by the bot). +* Ranks - We're experimenting with the values for ranking system, and as such the data may be reset to be more fair. +* Auto reactions - this feature is in public testing, but may be altered to allow for more features which may lead to losing settings (meaning the bot won't react to messages). + +## FAQ + +| Question | Answer | +| -------- | ------ | +| The bot is sending messages asking me for something. How to stop it? | This is part of the unique command system. When a required argument is missing, the bot will ask. There's a timeout of 30 seconds after last question, so by the team you're reading this the bot already stopped asking. Else, you could've just read what the bot said and responded with the message of "cancel" (without quotes) | +| How to change prefix? | Use the prefix command with an argument of the new prefix. Put it in quotes to force spaces. | +| What's the prefix? | Default prefix is `!`, you can get the one simply by pinging the bot (with nothing else in the message). Pinging the bot is a valid prefix too. | +| Is there a global prefix? | Yes there is, pinging the bot works as a prefix anywhere. | +| How do I disable the unknown command message? | Unknown command is a command too - `unknown-command`. Disable it (using the `disable` command) and the bot will stop replying with unknown command | +| How do I disable specific channels? | You can use the `channels` command to manage which channels are allowed. See `help channels`. | +| How do I manage who can use the bot? | For now, best would be to wait for dashboard. There's a way using `alter-perms` but it's hard to manage in chat and can yield unexpected results. If you enable a role to use a command, it will bypass the permission check. Proceed at your own risk! | +| How do I select which commands/groups can be used? | You can use the `enable` and `disable` commands to do just that. | + +# Commands + +- [Igni](#igni) + - [Things to know](#things-to-know) + - [No more pings](#no-more-pings) + - [No more retyping commands](#no-more-retyping-commands) + - [Many commands](#many-commands) + - [Aztec user?](#aztec-user) + - [More to come soon](#more-to-come-soon) + - [Testing](#testing) + - [Temporary features](#temporary-features) + - [FAQ](#faq) +- [Commands](#commands) + - [animals](#animals) + - [birb](#birb) + - [cat](#cat) + - [dog](#dog) + - [fox](#fox) + - [kangaroo](#kangaroo) + - [koala](#koala) + - [panda](#panda) + - [racoon](#racoon) + - [redpanda](#redpanda) + - [anime](#anime) + - [awooify](#awooify) + - [baguette](#baguette) + - [cry](#cry) + - [ddlc](#ddlc) + - [declare](#declare) + - [drink-coffee](#drink-coffee) + - [gah](#gah) + - [hug](#hug) + - [kanna](#kanna) + - [kannagen](#kannagen) + - [kemonomimi](#kemonomimi) + - [kiss](#kiss) + - [lick](#lick) + - [lolice](#lolice) + - [neko](#neko) + - [pout](#pout) + - [quote](#quote) + - [safebooru](#safebooru) + - [shrug](#shrug) + - [sip](#sip) + - [slap](#slap) + - [smug](#smug) + - [sofurry](#sofurry) + - [waifu](#waifu) + - [dev](#dev) + - [apm](#apm) + - [caniuse](#caniuse) + - [chart](#chart) + - [code](#code) + - [color](#color) + - [djs](#djs) + - [dstatus](#dstatus) + - [embed](#embed) + - [emotes](#emotes) + - [format](#format) + - [is-emoji](#is-emoji) + - [logme](#logme) + - [lolcode](#lolcode) + - [npm](#npm) + - [php](#php) + - [pip](#pip) + - [request](#request) + - [uptime](#uptime) + - [economy](#economy) + - [balance](#balance) + - [beg](#beg) + - [invest](#invest) + - [investments](#investments) + - [leaderboard](#leaderboard) + - [mine](#mine) + - [pay](#pay) + - [rank](#rank) + - [rich](#rich) + - [search-internet](#search-internet) + - [top-counters](#top-counters) + - [top-inviters](#top-inviters) + - [withdraw-investment](#withdraw-investment) + - [xp](#xp) + - [essentials](#essentials) + - [achievements](#achievements) + - [afk](#afk) + - [avatar](#avatar) + - [close-tunnel](#close-tunnel) + - [convert](#convert) + - [count](#count) + - [covid](#covid) + - [fact](#fact) + - [flags](#flags) + - [invite](#invite) + - [last-ping](#last-ping) + - [math](#math) + - [oldest](#oldest) + - [random-avatar](#random-avatar) + - [randomcolor](#randomcolor) + - [reddit](#reddit) + - [reddituser](#reddituser) + - [request-tunnel](#request-tunnel) + - [stats](#stats) + - [subinfo](#subinfo) + - [translate](#translate) + - [voted](#voted) + - [wttr](#wttr) + - [fun](#fun) + - [ascii](#ascii) + - [catfact](#catfact) + - [clap](#clap) + - [coinflip](#coinflip) + - [cool](#cool) + - [cow](#cow) + - [dab](#dab) + - [dadjoke](#dadjoke) + - [impostor](#impostor) + - [joke](#joke) + - [kill](#kill) + - [leetify](#leetify) + - [lenny](#lenny) + - [reversetext](#reversetext) + - [rps](#rps) + - [say](#say) + - [snipe](#snipe) + - [snipelist](#snipelist) + - [spoiler](#spoiler) + - [subscript](#subscript) + - [superscript](#superscript) + - [throw](#throw) + - [topic](#topic) + - [vaporwave](#vaporwave) + - [games](#games) + - [apexuser](#apexuser) + - [mastermind](#mastermind) + - [mc](#mc) + - [osuuser](#osuuser) + - [pokedex](#pokedex) + - [skin](#skin) + - [trivia](#trivia) + - [wouldyourather](#wouldyourather) + - [giveaway](#giveaway) + - [end-giveaway](#end-giveaway) + - [reroll-giveaway](#reroll-giveaway) + - [start-giveaway](#start-giveaway) + - [image](#image) + - [facepalm](#facepalm) + - [pat](#pat) + - [wink](#wink) + - [achievement](#achievement) + - [blurpify](#blurpify) + - [captcha](#captcha) + - [changemymind](#changemymind) + - [clyde](#clyde) + - [coffee](#coffee) + - [deepfry](#deepfry) + - [endtask](#endtask) + - [fone](#fone) + - [food](#food) + - [gay](#gay) + - [glass](#glass) + - [iphonex](#iphonex) + - [jpeg](#jpeg) + - [lookingback](#lookingback) + - [magik](#magik) + - [makeameme](#makeameme) + - [phcomment](#phcomment) + - [qr](#qr) + - [salty](#salty) + - [sauce](#sauce) + - [stickbug](#stickbug) + - [tenor](#tenor) + - [threats](#threats) + - [trap](#trap) + - [trash](#trash) + - [triggered](#triggered) + - [trumptweet](#trumptweet) + - [wasted](#wasted) + - [whowouldwin](#whowouldwin) + - [xkcd](#xkcd) + - [ytcomment](#ytcomment) + - [mod](#mod) + - [alias](#alias) + - [alter-automod](#alter-automod) + - [alter-perms](#alter-perms) + - [announce](#announce) + - [auto-react](#auto-react) + - [automod](#automod) + - [ban](#ban) + - [case](#case) + - [channels](#channels) + - [clear-perms](#clear-perms) + - [clearsettings](#clearsettings) + - [counting](#counting) + - [edit-embed](#edit-embed) + - [history](#history) + - [import](#import) + - [info](#info) + - [kick](#kick) + - [lock](#lock) + - [logs](#logs) + - [media-lock](#media-lock) + - [media-locks](#media-locks) + - [mute](#mute) + - [perms](#perms) + - [poll](#poll) + - [purge](#purge) + - [random-member](#random-member) + - [reaction-roles](#reaction-roles) + - [reason](#reason) + - [removewarn](#removewarn) + - [role](#role) + - [rrm](#rrm) + - [settings](#settings) + - [softban](#softban) + - [stats-channels](#stats-channels) + - [unban](#unban) + - [unlock](#unlock) + - [unmute](#unmute) + - [warn](#warn) + - [welcomechannel](#welcomechannel) + - [music](#music) + - [clear-queue](#clear-queue) + - [jump](#jump) + - [leave](#leave) + - [loop](#loop) + - [move](#move) + - [now](#now) + - [pause](#pause) + - [play](#play) + - [queue](#queue) + - [remove](#remove) + - [resume](#resume) + - [save-song](#save-song) + - [seek](#seek) + - [shuffle](#shuffle) + - [skip](#skip) + - [stop](#stop) + - [volume](#volume) + - [scircles](#scircles) + - [invited](#invited) + - [profile](#profile) + - [scircles-description](#scircles-description) + - [set-timezone](#set-timezone) + - [timezones](#timezones) + - [tz-list](#tz-list) + - [search](#search) + - [bang](#bang) + - [discogs](#discogs) + - [google](#google) + - [lastfm](#lastfm) + - [spotify](#spotify) + - [stackoverflow](#stackoverflow) + - [urban](#urban) + - [wiki](#wiki) + - [youtube](#youtube) + - [special](#special) + - [add-flag](#add-flag) + - [blacklist](#blacklist) + - [error](#error) + - [guilds](#guilds) + - [list-bugs](#list-bugs) + - [make-tunnel](#make-tunnel) + - [reloadservice](#reloadservice) + - [reloadstructures](#reloadstructures) + - [restart](#restart) + - [set-afk](#set-afk) + - [set-status](#set-status) + - [simulate](#simulate) + - [update-bug](#update-bug) + - [update](#update) + - [view-bug](#view-bug) + - [tickets](#tickets) + - [ticket](#ticket) + - [util](#util) + - [feature-request](#feature-request) + - [groups](#groups) + - [help](#help) + - [how-to](#how-to) + - [message-preview](#message-preview) + - [null](#null) + - [ping](#ping) + - [report-bug](#report-bug) + - [unknown-command](#unknown-command) + - [Collected data](#collected-data) + +## animals + +### birb + +Shows an image of a birb + +### cat + +Shows an image of a cat + +### dog + +Shows an image of a dog + +### fox + +Shows an image of a fox + +### kangaroo + +Shows an image of a kangaroo + +### koala + +Shows an image of a koala + +### panda + +Shows an image of a panda + +### racoon + +Aliases: `raccoon`, `raccon` + +Shows an image of a racoon + +### redpanda + +Aliases: `red-panda` + +Shows an image of a redpanda + +## anime + +### awooify + +Aliases: `awoo` + +Awooifies someone + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| text | user | who to awooify? | + +### baguette + +Eats a baguette. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | user | who shall eat the baguette? | + +### cry + +Cries. + +### ddlc + +Aliases: `dokidokiliteratureclub`, `ddlcscene` + +Creates a DDLC scene. Body can be 1 or 2 for monika, 1/1b/2/2b for others. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| character | string | which character to use? | +| background | string | which background to use? One of `bedroom`, `class`, `closet`, `club`, `corridor`, `house`, `kitchen`, `residential` and `sayori_bedroom`. | +| face | string | which face to use? A-R for monika, A-Z for natsuki, A-Y for sayori and A-X for yuri. | +| text | string | what should the character say? | + +### declare + +Declares communism. + +### drink-coffee + +Aliases: `drinkcoffee`, `animecoffee`, `anime-coffee` + +Someone enjoying warm coffee. + +### gah + +gah image + +### hug + +Hugs someone. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | member | who do you want to hug? | + +### kanna + +kanna image + +### kannagen + +Generates a kannagen image + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| text | string | what to kannafy? | + +### kemonomimi + +Kemonomimi image + +### kiss + +Kisses someone. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | member | who do you want to kiss? | + +### lick + +Licks someone. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | member | who do you want to lick? | + +### lolice + +Aliases: `loli`, `lolies` + +Lolice rules + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| lolice | user | who's the lolice? | + +### neko + +Neko image + +### pout + +Pouts + +### quote + +Shows random anime quote + +### safebooru + +Random safebooru image. + +### shrug + +Shrugs. + +### sip + +Sips + +### slap + +Slaps someone. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | member | who do you want to slap? | + +### smug + +Feelin smug. + +### sofurry + +Random image from sofurry + +### waifu + +Shows random non-existent waifu generated by AI + +## dev + +### apm + +Gets info about Atom Text Editor package + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| pkg | string | Which Atom package to get info about? | + +Usage: `apm ` + +### caniuse + +Searches caniuse.com for support + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| name | string | Which feature to search for? | + +### chart + +Generates a simple chart. Uses quickchart.io + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| args | string | what data to visualize? | + +### code + +Aliases: `http-code`, `error-code` + +Explanation for given http status code. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| code | integer | What code to get info about? | + +Usage: `code ` + +### color + +Aliases: `colour`, `color-preview`, `colour-preview` + +Preview what a color looks like. Accepts HEX, RGB(A) and predefined HTML colors + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| value | string | What color do you want to view? | + +Usage: `color ` + +### djs + +Searches in discord.js docs + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| query | string | Enter query to search for | +| source | string | Source version to use | + +Usage: `djs [source]` + +### dstatus + +Shows status of discord services. + +### embed + +Sends a thumbnail based on given JSON + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| embed | string | JSON embed to show | + +### emotes + +Aliases: `emoji`, `emote` + +Shows info about an emoji + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| emote | string | Emote to get info about | + +### format + +Aliases: `markdown` + +Shows information about formatting messages + +### is-emoji + +Returns if given message has an emoji or not + +### logme + +Shows properties of sent image + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| argument | string | string :) | + +### lolcode + +EXECUTEZ GIVEN LOLCODE CODE. STDIN IZ EMPTY + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| code | string | WUTS TEH CODE 2 EVAL? | + +### npm + +Gets info about NPM package + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| pkg | string | Which NPM package to get info about? | + +Usage: `npm ` + +### php + +Shows information from PHP documentation. Use either `php ` or `php ::`. Use object oriented style when available. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| php | string | Which class/function to get info about? | + +Usage: `php help` + +### pip + +Gets info about Python Package on PIP Package + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| pkg | string | Which PIP package to get info about? | + +Usage: `pip ` + +### request + +Aliases: `req` + +Makes a new HTTP request + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| method | string | Which method to use? Type `help` for more info. | +| url | string | Which URL to make request on? | +| format | string | What's the format to use? `json` or `text`. | + +Usage: `req get http://danbulant.eu/ text` + +### uptime + +Aliases: `up-time` + +Shows uptime of igni + +## economy + +### balance + +Aliases: `bal` + +Shows yours BBS balance. More in `info user` + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| target | member | Which user to get balance from? | + +### beg + +Begs users to give you BBS + +### invest + +Invest BBS into the economy + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| sum | float | How much to invest? | + +### investments + +Aliases: `investment` + +Shows your investments. Use `investment ` to see details of single investment. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| investment | integer | Which investment to show? | + +### leaderboard + +Aliases: `top`, `ranks` + +Shows the users with top rank. + +### mine + +Mines BBS, once per 12 hours. + +### pay + +Pays someone BBS + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | user | Who to pay? | +| amount | float | What amount to pay? | + +### rank + +Aliases: `level`, `lvl` + +Shows your or someone else's current rank and rank points. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | member | which user to get level from? | + +### rich + +Aliases: `richest`, `baltop` + +Shows rich people + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| page | integer | Page to look at | + +### search-internet + +Aliases: `search-places`, `search-net`, `net-search` + +Searches virtual internet for BBS + +### top-counters + +Aliases: `counting-top` + +Lists the top counters + +### top-inviters + +Shows top inviters. + +### withdraw-investment + +Withdraws an investment + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| id | integer | What's the number of investment? See `investments` command for more. | + +### xp + +Aliases: `exp` + +Shows your or someone else's current level and experience + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | user | which user to get level from? | + +## essentials + +### achievements + +List all your achievements + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | user | What's the user you want to list achievements of? | + +### afk + +Set a message to display when someone pings you. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| message | string | What message to display? | + +### avatar + +Aliases: `av`, `pfp` + +Shows yours (or someone else's) avatar + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | member | User to check on? | + +### close-tunnel + +Closes existing tunnel + +### convert + +Converts a currency to another one + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| number | float | How much to convert? | +| source | string | What currency to convert from? | +| target | string | What currency to convert to? | + +### count + +Aliases: `user-count`, `member-count` + +Shows information about members of this server + +### covid + +Aliases: `covid19`, `corona`, `coronavirus`, `covidinfo`, `coronainfo` + +Shows recent information about COVID-19 + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| country | string | which countrys stats do you want to see? | + +Usage: `covid [country]` + +### fact + +Shows random useless fact + +### flags + +Aliases: `badges` + +Shows list of user flags + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| member | member | which user to get flags from? | + +### invite + +Shows bot invite link + +### last-ping + +Aliases: `pong`, `ponged` + +Shows who last pinged you. + +### math + +Aliases: `calc`, `calculator` + +Calculates given math expression + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| expression | string | What expression to calculate? | + +### oldest + +Aliases: `old` + +Shows oldest users on discord + +### random-avatar + +Aliases: `random-pfp`, `random-av` + +Shows a random avatar + +### randomcolor + +Aliases: `random-color` + +Shows a random color + +### reddit + +Aliases: `meme`, `memes`, `puppy`, `dankmeme`, `dankmemes`, `cursedimage`, `cursedimages`, `foodporn` + +Gets random image from given subreddit. Can be used with or without r/ + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| reddit | string | Which subreddit to get the image from? | + +### reddituser + +Aliases: `ru` + +Fetch information about a reddit user + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | string | which reddit user to fetch info from? | + +### request-tunnel + +Aliases: `contact-developers` + +Requests a message tunnel to devs. DM only. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| context | string | Why do you want to contact developers? | + +### stats + +Aliases: `statistics`, `about`, `status` + +Statistics and information about igni + +### subinfo + +Aliases: `sub`, `subreddit` + +Fetch information about a subreddit + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| sub | string | which subreddit to fetch info from? | + +### translate + +Aliases: `t` + +Translate string or previous message + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| target | string | What language to translate to? Use 2 letter language code. | +| text | string | What text to translate? | + +### voted + +Aliases: `vote` + +Checks your vote status + +### wttr + +Aliases: `weather`, `wttr.in` + +Shows current weather + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| city | string | What's the city to show weather info for? | + +## fun + +### ascii + +Aliases: `figlet` + +Makes ascii text. For list of fonts, see [figlet.js](https://github.com/patorjk/figlet.js/). + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| text | string | What text should the bot render? | + +Usage: `ascii [font] ` + +Examples: + +- ascii Hello there +- ascii Bloody Booo + +### catfact + +Aliases: `cat-fact`, `catfacts` + +Shows a random fact about cats. + +### clap + +Aliases: `clapify` + +Clapify given text + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| string | string | Text to clapify | + +### coinflip + +Aliases: `cf` + +Flips a coin. + +### cool + +Cool up something + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| cool | string | What do you want to cool? | + +### cow + +Ascii cow saying or thinking whatever you want + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| variant | string | Variant to use, think or say? | +| text | string | Text to make cow say/think: | + +### dab + +DAB + +### dadjoke + +Shows random dad joke + +### impostor + +Who was the impostor? + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | member | Who was the impostor? | + +### joke + +Shows random joke + +### kill + +Kills user + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | member | which user to kill? | + +### leetify + +Aliases: `leet` + +Leetify your text + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| string | string | Text to leetify: | + +### lenny + +Everyone knows what's lenny + +### reversetext + +Aliases: `reverse` + +Reverses given text + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| text | string | What text to reverse? | + +### rps + +Aliases: `rockpaperscissors`, `rock-paper-scissors` + +Plays rock paper scissors game with bot. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| chose | string | What do you choose? One of `rock`, `paper` and `scissors` | + +### say + +Make the bot say what you want + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| string | string | What do you want bot to say? | + +### snipe + +Display a recently deleted message + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| number | integer | Which number of recently deleted messages should the bot show? | + +Usage: `snipe [msg number]` + +### snipelist + +Aliases: `snipes` + +Display list of channels with recently deleted messages + +Usage: `snipelist` + +### spoiler + +Aliases: `spoil` + +Make the bot say something in annoying spoilers + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| string | string | What to say: | + +### subscript + +Converts text to subscript + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| text | string | What text to convert? | + +### superscript + +Converts text to superscript + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| text | string | What text to convert? | + +### throw + +Throws a random object at someone + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | member-lax | Who to throw at? | + +### topic + +Shows a random topic + +### vaporwave + +Aliases: `vaporify` + +Vaporify given text + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| string | string | What to vaporify? | + +## games + +### apexuser + +Aliases: `au` + +Fetches info about given Apex legends player + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| player | string | which player to fetch? | +| platform | string | which platform to use (PC, PS4 or X1)? | + +### mastermind + +Starts a game of mastermind. + +### mc + +Aliases: `mcnick`, `mcnickname`, `minecraftname` + +Shows history of mc username + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| name | string | What minecraft username to get info about? | + +### osuuser + +Aliases: `ou`, `osu` + +Shows information about osu user + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | string | which user to search for? | +| type | string | what mode to use? | + +### pokedex + +Aliases: `pokemon` + +Finds pokémon in pokedex + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| poke | string | What pokemon do you want to find? | + +### skin + +Shows skin of given user + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| username | string | Enter username of the minecraft player to show skin of: | + +### trivia + +Aliases: `quiz` + +Asks a question + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| type | string | What difficulty to use? Use `any` for any difficulty and `stats` to show your statistics. | +| fast | boolean | Do you want to end the trivia after you respond? This will disable the multiplayer. | + +### wouldyourather + +Aliases: `wyr` + +Shows a would you rather question/ + +## giveaway + +### end-giveaway + +Aliases: `g-end`, `giveaway-end` + +Ends a giveaway + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| message | string-integer | What's the message ID of giveaway? | +| channel | channel | What's the channel of giveaway? | + +### reroll-giveaway + +Aliases: `g-reroll`, `giveaway-reroll` + +Rerolls a giveaway + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| message | string-integer | What's the message ID of giveaway? | +| channel | integer | What's the channel of giveaway? | + +### start-giveaway + +Aliases: `g-start`, `giveaway-start` + +Starts a giveaway + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| time | time-length | After how long should the giveaway end? 0 for manual ending. (Example: 1hour, 2mins) | +| item | string | What item do you intend to giveaway? 200 characters maximum. | +| channel | text-channel | Which channel to send the giveaway to? | +| winners | integer | How many winners should be selected? | +| messages | natural-number|optional | How many messages does the user need to have sent to be able to apply? `skip` if no requirement. | +| invites | natural-number|optional | How many people does the user need to have invited to be able to apply? `skip` if no requirement. | +| roles | role-list|optional | What roles does the user need to have to be able to apply? Reply with role names or IDs, separated by space. `skip` if no requirement. | +| server | invite|optional | What server does the user need to have to join to be able to apply? Reply with invite link. `skip` if no requirement | + +## image + +### facepalm + +Aliases: `face-palm` + +Facepalms + +### pat + +Pats someone + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | member | Who to pat? | + +### wink + +Winks to someone + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | member | Who to wink to? | + +### achievement + +Creates a minecraft-like achievement, thanks to alexflipnote.dev + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| text | string | What achievement did you get? | + +### blurpify + +Blurpifies an image + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| image | image | what to blurpify? | + +### captcha + +Captchifies someone. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | user | who shall be in captcha? | +| text | string | what is in the captcha? | + +### changemymind + +Aliases: `mind` + +Try and change my mind. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| text | string | what are you sure about? | + +### clyde + +Aliases: `clydify` + +Make clyde say something. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| text | string | what to say? | + +### coffee + +Random coffee image from alexflipnote.dev + +### deepfry + +Deepfries an image + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| image | image | what to deepfry? | + +### endtask + +Aliases: `stopworking`, `sw` + +Ends a task + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| text | string | what task to end? | + +### fone + +Shows random image from happy fone api + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| type | string | Enter type of resource | + +### food + +food image + +### gay + +Makes image or someone more gay + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| image | image | What image/Who to make gay? | + +### glass + +Makes image or someone more glass + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| image | url|user | What image/Who to glassify? | + +### iphonex + +Puts an image into iphonex + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| url | image | what to put into iPhone X? | + +### jpeg + +Aliases: `jpg`, `jpegify` + +JPEG-ify someone + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| character | user | who to jpegify? | + +### lookingback + +Aliases: `lookback`, `lookingbackat`, `lookbackat` + +How dare he look at her. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user2 | user | who do you want to look at? | +| user | user | who is looking back? | + +### magik + +Aliases: `magikify` + +Magikifies an image + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| image | image | what to magikify? | +| intensity | integer | what's the intensity to use? | + +### makeameme + +Aliases: `makememe`, `genmeme` + +Make a meme using imageurl/avatar toptext botomtext + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| url | user|url | Image URL to make meme of: | +| top | string | Top text of meme: | +| bottom | string | Bottom text of meme: | + +### phcomment + +Makes an phcomment + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| text | string | what to comment? | + +### qr + +Aliases: `qrcode` + +Makes a QRCode from given text + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| text | string | Text to encode into QRCode | + +Usage: `qr ` + +### salty + +Makes an image more salty, thanks to alexflipnote.dev + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| image | url|user | What image to salty? You can also send a username. | + +### sauce + +Aliases: `saucenao`, `source`, `sourceimage` + +I need the sauce. Nao! + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| image | url | Which image to search for? | + +### stickbug + +Stickbugs an image + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| url | image | What to stickbug? | + +### tenor + +Shows a tenor GIF. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| title | string | what should be the title? | +| type | string | What should the bot search for? | +| description | string | What should be the description? | + +### threats + +Aliases: `threat` + +Shows 3 biggest threats. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | user | who's the 3rd thread? | + +### trap + +Traps someone + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | member | who to trap? | + +### trash + +Shows trash waifus + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| image | user | Who's the trash here? | + +### triggered + +Aliases: `trigger` + +Triggers an image or someone + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| image | url|user | What image/Who to trigger? | + +### trumptweet + +Aliases: `tweet`, `trump` + +So what did trump tweet today? + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| text | string | what did trump tweet?? | + +### wasted + +Makes image/user wasted + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| image | url|user | What image/Who to waste? | + +### whowouldwin + +Aliases: `whowins`, `wouldwin`, `whowin` + +Compares who would win. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user2 | user | who do you want to compare? | +| user | user | who should be the other one to compare? | + +### xkcd + +Aliases: `comic` + +Shows todays xkcd comic. + +### ytcomment + +Makes a youtube comment + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| text | string | What to comment? Max 999 characters | + +## mod + +### alias + +Aliases: `add-alias` + +Adds an alias to a command + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| target | command | What command to alias to? | +| source | string | What alias to add? Must contain only non-whitespace characters. | + +### alter-automod + +Edits automod configuration + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| option | string | Which option to change? One of bannedWords, mentions, regexes, invites, links, emojis, spoilers and selfbots. | +| action | string|optional | What action should the bot take? `skip` to remove the rule. One of kick, ban, warn, softban and messageDelete. | +| settings | string | What are the additional settings? List of words separated by space for bannedWords, number for emojis or mentions. | + +### alter-perms + +Aliases: `edit-perms`, `alter-permissions`, `edit-permissions` + +Edits permissions + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| role | role | What role to edit? | +| channel | channel|optional | What text channel or category to edit? Skip to edit global permissions. | +| cmd | command|group|optional | What command or group to edit? Skip to edit all commands. | +| value | boolean|string | Enable the command? Yes, no or message to show instead of the generic permission denied. | + +### announce + +Aliases: `announcement` + +Make the bot announce what you want. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| title | string | What's the title of announcement? | +| string | string | What do you want to announce? | +| color | string | What's the color you want to use? | +| showAuthor | boolean | Do you want to show you as author? | + +Examples: + +- announce "Title" "Description" blue + +### auto-react + +Creates, updates or removes auto reactions + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| channel | text-channel|optional | What channel to auto react in? `skip` for current. | +| reactions | emojis|optional | What reactions to react with? `skip` to remove auto reactions. If multiple, split them by space (` `). | + +### automod + +Shows automod configuration + +### ban + +Bans a user + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | member | which user do you want to ban? | +| reason | string | why do you want to ban this user? | + +Usage: `ban ` + +### case + +Shows an offender case + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| case | integer | which case do you want to view? | + +### channels + +Lists allowed channels or sets/removes them + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| option | string | Please select an option: `` | +| channels | channel | Which channels to add/remove? | + +### clear-perms + +Aliases: `clear-permissions` + +Clears all the servers permission overwrites + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| confirmation | string | WARNING - this will delete all the servers permission overwrites! Are you sure? Type `confirm` to confirm. | + +### clearsettings + +Clears all the guilds settings + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| confirmation | string | WARNING - this will delete all the guilds cases and other settings! Are you sure? Type `confirm` to confirm. | + +### counting + +Aliases: `counting-channel` + +Creates or deletes counting channel + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| channel | text-channel | Which channel to use? | +| remove | boolean | Do you want to remove the channel as counting channel? | + +### edit-embed + +Aliases: `embed-edit` + +Edits given command + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| message | message | What's the message id of the embed to edit? Only bots messages can be edited. | +| type | string | What to edit? | +| value | string | What's the new value to set? | + +### history + +Shows on offenders history + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | user | which users offense history do you want to view? | + +### import + +Imports data from aztec + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| code | string | What's the code from aztec? Use the `igni` command in Aztec to get the code. | + +### info + +Aliases: `roleinfo`, `ri`, `channelinfo`, `chi`, `channel`, `serverinfo`, `si`, `server`, `guildinfo` + +Gets information + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| command | string | Which resource you want to get info about? | +| pointer | role|channel | which role/channel to get info about? | + +Usage: `info help` + +### kick + +Kicks a user + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | member | which user do you want to kick? | +| reason | string | why do you want to kick this user? | + +### lock + +Locks channel + +### logs + +Aliases: `log` + +Log settings. See `help` subcommand for more info. When altering, use +option to add, -option to remove and !option to toggle log options + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| command | string | Which action to do? Send `help` if not sure. | +| channel | channel | Which channel to add/remove? | +| settings | string | | + +### media-lock + +Aliases: `medialock` + +Updates media lock for given channel + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| channel | channel|optional | Which channel to media lock? `skip` for this. | +| options | options | Which media lock options to use? `clear` to remove media lock. | + +### media-locks + +Aliases: `medialocks`, `list-media-locks` + +List all enabled media locks + +### mute + +Mutes a user + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| member | member | which user do you want to mute? | +| reason | string | why do you want to mute this user? | + +### perms + +Aliases: `permissions` + +Views permissions for current or given channel + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| channel | text-channel|category-channel | Which channel to view permissions of (text or category channels only)? | + +### poll + +Create simple polls with igni. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| title | string | what is the title of the poll? | +| args | string | what should be the options? Use format ` option`. Duplicates will be ignored. | + +### purge + +Deletes a certain amount of message in channel. + +Examples: + +- purge 10 +- purge 15min +- purge bots 50 +- purge embeds 10h + +### random-member + +Aliases: `randommember`, `random` + +Selects random member + +### reaction-roles + +Aliases: `rr` + +Creates a reaction role + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| channel | text-channel|optional | In which channel is the message? `skip` to use this. | +| message | string | What's the message ID to check? | +| reaction | emoji | What's the reaction to accept? | +| role | role | What's the role to give/remove? | + +### reason + +Aliases: `editreason` + +Warns a user + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| case | integer | which case do you want to edit? | +| reason | string | what should the new reason be? | + +### removewarn + +Remove a warn from a user + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| case | integer | which warn case do you want to remove? | + +### role + +Aliases: `r`, `roles` + +Add, remove or toggle a role on a user + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| option | string | Please select an option: `` | +| user | member | Which user would you like to select? | +| role | role | Which role would you like to select? | + +### rrm + +Aliases: `reaction-roles-message` + +Creates a reaction roles message + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| channel | text-channel|optional | What's the channel to send the message to? `skip` to use this. | +| reactions | | What are the reaction roles? Reply in format of ` `. Send multiple entries each in it's own message. | + +### settings + +Manages bot settings. User settings in DMs, otherwise server settings. Replace spaces in setting names with dashes (-) or quote them. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| group | string | What's the setting group to show? | +| setting | string | Which setting to show? | +| value | string | What to set the setting's value to? | + +### softban + +Softbans a user + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | member | which user do you want to softban? | +| reason | string | why do you want to softban this user? | + +Usage: `softban ` + +### stats-channels + +Aliases: `statistics-channels`, `stats-channel` + +Sets statistics channels. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| operation | string | What operation do you want to comence? Use list to show stats channels. | +| channel | channel | What channel to update? | +| name | string | What to set as the name of channel? | + +Usage: `Use list to view all set up channels. Add to add a channel (and set it's name as 3rd argument). Remove to remove a channel from updating, clear to remove all.` + +### unban + +Unbans a user + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | string-integer | which user do you want to unban? | +| reason | string | why do you want to unban this user? | + +Usage: `unban ` + +### unlock + +Unlocks channel + +### unmute + +Unmutes a user + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| member | member | which user do you want to unmute? | +| reason | string | why do you want to unmute this user? | + +### warn + +Warns a user + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | member | which user do you want to warn? | +| reason | string | why do you want to warn this user? | + +### welcomechannel + +Aliases: `leavechannel`, `joinchannel`, `welcome-channel`, `welcome-messages` + +Sets welcome and leave channels. Overwrites previous settings. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| channel | channel | which channel to log into? | +| type | string | which actions to log (both, leave or join)? `clear` to remove the channel. | + +## music + +### clear-queue + +Clears the music queue + +### jump + +Aliases: `skip-to` + +Jumps to selected position in queue + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| number | integer | To which position in queue to jump to? | + +### leave + +Aliases: `disconnect`, `dc`, `fuckoff` + +Leaves the voice channel. + +### loop + +Aliases: `lq`, `loop-queue`, `loop-song`, `loop-off` + +Loops queue or current song + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| mode | string | What to loop? One of `song`, `queue` and `off`. | + +### move + +Moves a song in the queue + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| song | integer | Which song number to move? | +| target | integer | To which position to move the song to? | + +### now + +Aliases: `np`, `now-playing` + +Show current playing song + +### pause + +Pauses playback + +### play + +Aliases: `p`, `fuckon`, `pt`, `play-next`, `join` + +Add given music into queue + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| url | string | What music to add? | + +### queue + +Aliases: `q` + +List current queue + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| selected | integer | Which song to get info about? | + +### remove + +Remove song from queue + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| selected | integer | Which song to remove from queue? | +| length | integer | How many songs to delete? | + +### resume + +Resumes playback + +### save-song + +Sends you the current song details into DMs + +### seek + +Seeks playback + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| seek | integer | How much to seek? Use `h:m:s` format (hours and minutes are optional) | +| absolute | boolean | Seek from start? yes/no. | + +### shuffle + +Shuffles the queue + +### skip + +Skips currently playing song(s) + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| number | integer | How many songs to skip? | + +### stop + +Stops the music player + +### volume + +Aliases: `vol` + +Sets music volume + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| volume | integer | What to set the new volume to? | + +## scircles + +### invited + +Aliases: `invites` + +Shows the user you or mentioned user invited. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | member | Which user should be used for searching? | + +### profile + +Aliases: `user`, `member`, `who-am-i`, `who-is`, `user-info` + +Shows user profile + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | member | What user to get info about? | + +### scircles-description + +Aliases: `set-description` + +Sets your description + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| text | string | What's your new description? | + +### set-timezone + +Sets your timezone + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| timezone | timezone | What's your timezone? | + +### timezones + +Shows an image heatmap of timezones used + +### tz-list + +Aliases: `timezones-list` + +Lists timezones and their users. + +## search + +### bang + +Aliases: `ddg`, `duckduckgo` + +Shows link to duckduckgo bang or shows instant answer + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| string | string | What to try searching on DDG instant answers / bangs? | + +### discogs + +Searches discogs + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| text | string | What to search for? | + +### google + +Shows link to search given text on google + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| string | string | What to google? | + +### lastfm + +Aliases: `lfm` + +Searches LastFM + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| text | string | What to search for? | + +### spotify + +Searches spotify + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| search | string | What to search? | + +### stackoverflow + +Aliases: `stack`, `so` + +Searches in StackOverflow. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| filter | string | What to search for? | + +### urban + +Aliases: `ud`, `define`, `df` + +Find the meaning in the Urban Dictionary + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| text | string | What is the word do you want to look up? | + +Usage: `urban ` + +### wiki + +Aliases: `wikipedia` + +Extracts some information from Wikipedia page. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| page | string | Which page to extract information? | + +### youtube + +Searches youtube for videos + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| url | string | What to search for? | + +## special + +### add-flag + +Aliases: `toggle-flag` + +Add flag to user + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | user | which user to give flag to? | +| flag | string | which flag to add? | + +### blacklist + +Prohibit a user from using this bot + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| option | string | Please select an option: `` | +| users | user | Which users to add/remove? | + +### error + +Shows details about an error/leave + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| code | user|string | which error code/user to get info about? | + +### guilds + +Lists guilds igni is in + +### list-bugs + +Lists known bugs + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| type | string | Which bugs to list? | + +### make-tunnel + +Creates a tunnel in this server to selected user. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| user | user | What user to connect this channel to? | + +### reloadservice + +Aliases: `reload-service`, `service-reload` + +Reloads service + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| service | string | which service to reload? | + +### reloadstructures + +Reloads structures - useful when structures were updated during update + +### restart + +Restarts the bot + +### set-afk + +Toggles the bots afk status + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| afk | boolean | Please select an AFK option? (true/false) | + +### set-status + +Set the bots activity/status + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| type | string | Which kind of status? | +| name | string | What should the status be? | + +### simulate + +Simulates given event + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| event | string | which event to start? | + +### update-bug + +Updates given bug. Accepts shell arguments + +### update + +Updates the bot + +### view-bug + +Views given bug report. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| bug | string | Which bug report to view? | + +## tickets + +### ticket + +Aliases: `tickets` + +Create or manage a ticket. Use `create` to create a new ticket (or with no arguments). Use `close`, `save`, `open` or `delete` in the ticket channel. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| subcommand | string | which subcommand would you like to use? | +| ticket | string | what's the ticket id? | + +## util + +### feature-request + +Aliases: `feature-request` + +Requests a feature for the bot + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| feature | string | What feature to request? Be as precise as possible. | + +### groups + +Aliases: `list-groups`, `show-groups` + +Lists all command groups. + +### help + +Aliases: `man`, `commands` + +Displays a list of available commands, or detailed information for a specified command + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| command | group-or-command | Which command or command group do you want details about? | + +Usage: `help [command | command group]` + +Examples: + +- help +- help prefix + +### how-to + +Aliases: `usage` + +Shows information about how to use the bot + +### message-preview + +Previews a message. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| url | url|message | What's the message link? | + +### null + +Aliases: `d` + +Does nothing, can be used as a target for aliases + +### ping + +Checks the bot's ping to the Discord server. + +### report-bug + +Aliases: `bug-report` + +Reports a bug in igni. + +**Arguments**: + +| Name | Type | Prompt | +| --- | --- | ----- | +| bug | string | What bug to report? Be as precise as possible. | + +### unknown-command + +Displays help information for when an unknown command is used. + +Examples: + +- unknown-command kickeverybodyever + +## Collected data + +The bot requires some data to be recorded to it's databases. Apart from settings you explicitly set using commands, the following data is recorded: +* Guild name, id, join date and member count (used for statistics and possibly propagation, once we will start using it for propagation we will add a way to disable it) +* Member message count (used for rank) - contains just the total message count and bot-generated values like level +* Invites (used for invite tracking) - Contains user ID, server ID, invite code, expiration date and uses +* Error logs when an error is triggered in a command (users will see an error message) - message ID, their tag, channel ID and server ID +* Anonymized public statistics - total servers added and removed each day (just the numbers). This is the only data that's always public. + +By adding the bot, you allow the collection of data specified above as well as any command used. We're also not liable for any data saved into the bot. + +To delete all data of a server, you can use the `clearsettings` command. To delete data of a user or member, contact the devs via the support server. To request a dump of your data, contact developers via the support server. The bot is operated from United States and hosted in NYC. \ No newline at end of file diff --git a/igni/aztec.md b/igni/aztec.md new file mode 100644 index 0000000..88a5255 --- /dev/null +++ b/igni/aztec.md @@ -0,0 +1,18 @@ +--- +layout: default +toc: true +footer: (c) Copyright ids.company 2021. +--- +# Aztec deprecation + +Aztec is currently in the deprecation process and will be shut down soon. To continue using Aztec, you can instead [invite](https://top.gg/bot/739864286775738399) igni, which can replace Aztec fully while also improving the overall experience. You can learn more about igni [here](README.md). + +## Just to name a few improvements + +* Giveaways now work longer than just few hours and can have rules like number of messages +* Message number counting +* Working invite manager +* Counting channels +* More log events +* Custom aliases +* Less bugs \ No newline at end of file diff --git a/igni/discogs.md b/igni/discogs.md new file mode 100644 index 0000000..cf1aeba --- /dev/null +++ b/igni/discogs.md @@ -0,0 +1,8 @@ +--- +layout: default +toc: true +footer: (c) Copyright ids.company 2021. +--- +# Discogs integration + +igni can search in discogs using the `discogs` command in the `search` module. \ No newline at end of file diff --git a/igni/index.md b/igni/index.md new file mode 100644 index 0000000..c6b87b6 --- /dev/null +++ b/igni/index.md @@ -0,0 +1,10 @@ +--- +layout: default +toc: true +footer: (c) Copyright ids.company 2021. +--- +# Igni + +* [About igni](./README) +* [Aztec users](./aztec) +* [logs](./logs) \ No newline at end of file diff --git a/igni/lastfm.md b/igni/lastfm.md new file mode 100644 index 0000000..d07c092 --- /dev/null +++ b/igni/lastfm.md @@ -0,0 +1,10 @@ +--- +layout: default +toc: true +footer: (c) Copyright ids.company 2021. +--- +# Last.fm integration + +You can search last.fm using the `lastfm` command (aliased `lfm`) from `search` module. + +The command searches in artists, tracks and albums and selects the one with the closest name (and sends it as embed). \ No newline at end of file diff --git a/igni/logs.md b/igni/logs.md new file mode 100644 index 0000000..be13e24 --- /dev/null +++ b/igni/logs.md @@ -0,0 +1,98 @@ +--- +layout: default +toc: true +footer: (c) Copyright ids.company 2021. +--- +# Logs + +igni has advanced logs, but that comes with a compromise - they're a bit harder to setup in text chat (on our dashboard with UI, it will be much simpler). + +## Adding channel to logs + +To add channel to logs, simply call `logs add` or `logs set` with channel name, like +``` +!logs add #logs +``` + +## Editing rules for logs + +To edit rules, call `logs alter` with channel name and rule alterations. + +### List of rules + +Aztec uses minecraft-permissions-like rules for logs. A list of all rules can be seen here: + + * `*` - Wildcard, any event (default) + * `*.*` - Alias to `*` + * `user.*` - Any user related event + * `channel.*` - Any channel related event (messages aren't part of it) + * `category.*` - Any category related event (category create/update/delete) + * `message.*` - Message related event (excluding new messages) + * `guild.*` - Server related events (rename, ban, region change etc) + * `roles.*` - Roles related events + * `config.*` - Bot config related events + * `emoji.*` - Emoji create/rename/delete + * `invite.*` - Invite related events + + * `user.join` - When user joins the server + * `user.leave` - When user leaves the serevr + * `user.update` - User update (avatar change, rename etc) [doesn't work] + * `user.presenceUpdate` - On user presence change. Can be enabled only by bot owner. + + * `channel.create` - When new channel is created + * `channel.delete` - When channel is deleted + * `channel.pins` - When there's a new pinned message [doesn't work] + * `channel.update` - When channel is updated (currently excluding permission changes) + * `channel.name` - When channel is renamed + + * `category.create` - When category is created + * `category.delete` - When category is deleted + * `category.perms` - When permissions for category are changed [doesn't work] + * `category.name` - When category is renamed + + * `guild.update` - When guild is updated (excluding permission changes) + * `guild.boost` - When premium user boosts guild (bot boosting, not discord boost) + * `guild.ban` - When user gets banned + * `guild.removeBan` - When user gets unbanned + * `guild.integration` - When there's new integration [doesn't work] + * `guild.kick` - When user gets kicked + * `guild.warn` - When user gets warned **using igni** + * `guild.webhook` - When guild webhook settings changes [doesn't work] + + * `roles.create` - When role is created + * `roles.update` - When role is updated + + * `message.withLink` - When a message with link is posted [doesn't work, might be removed later] + * `message.withInvite` - When a message with invite to server is posted [doesn't work, might be removed later] + * `message.edit` - When message is edited + * `message.delete` - When message is deleted + * `message.purge` - When messages are purged (mass deleted) + + * `emoji.create` - When emoji is created [doesn't work] + * `emoji.delete` - When emoji is deleted [doesn't work] + * `emoji.update` - When emoji is updated [doesn't work] + + * `invite.create` - When invite is created + * `invite.delete` - When invite is deleted + + ### Alterations + + Channels are updated using `alterations` which is specified by a single character before rule - either `-` (remove), `+` (add) or `!` (toggle, invert). + + You can put as many alterations after each other as you want. + + **Example** + + *The following will log every message edit* + ``` + !logs alter #logs -* +message.edit + ``` + *Note that you need to remove wildcard first before other rules take effect* + + ## Removing channel from logs + + You can remove logs channel using `remove` subcommand: + + ``` + !logs remove #logs + ``` \ No newline at end of file diff --git a/igni/privacy.md b/igni/privacy.md new file mode 100644 index 0000000..cb80a83 --- /dev/null +++ b/igni/privacy.md @@ -0,0 +1,75 @@ +--- +layout: default +toc: true +footer: (c) Copyright ids.company 2021. +--- +# Privacy policy + +## Terms + +### ID + +ID is used for uniquely identifiying token, that doesn't contain any private data by itself (i.e. a number corresponding for specific user). + +When ID comes from discord (messages, users, servers, channels...), it also contains the date of when the item was created (or user registered). + +## Stored data + +The following information is stored: + +* invite link, their author ID and the usage count (for invite manager) +* server ID along with settings and data from commands (for the functionality of the bot) +* user ID along with user settings and data from commands (for the functionality of the bot) +* member ID, the number of users invited and the ID of inviter (for invite manager) + +No discord data (not listed in this privacy policy) is saved unless explicitly set via a command. Server data is deletable using the `clear-settings` command, user data can be deleted after contacting the developers in the support server found in `about` command. + +By using the bot, you allow access to the data specified here and all data specified in commands. + +### Statistics + +Following data is stored for statistical purposes (to be shown in website privately to members of server, or anyone, depending on privacy settings). +Data retention is 90 days unless specified otherwise. +This data will be recorded once (and after) website is publicly available. + +#### Messages + +* ID +* author ID +* channel ID +* Whether the message has attachments, images, embeds, is pinned or is by bot. + +#### User joins/leaves + +* Date and time +* user ID +* which user invited the user +* which invite was used +* Whether user left, joined, is a bot, was banned before and similar. + +#### Songs played + +Statistics about which songs the bot played in voice chat or using other ways. + +* Date and time +* requester ID (user that requested the song) +* song name +* source (youtube, spotify, soundcloud or similar link) +* metadata about song (it's name, length, author...) + +#### Voice chat activity + +Tracks users when they join and leave voice chat + +* Date and time +* user ID +* channel ID +* Whether they joined or left + +## Contact + +You can request DM from developers using the `request-tunnel` command (in DMs with the bot). You can also join the support server listed in `about` command. + +## Shared data + +We do not share your data with 3rd parties, unless specifically requested by user. diff --git a/igni/tips.md b/igni/tips.md new file mode 100644 index 0000000..c602ed6 --- /dev/null +++ b/igni/tips.md @@ -0,0 +1,21 @@ +--- +layout: default +toc: true +footer: (c) Copyright ids.company 2021. +--- +# Tip and tricks + +## Command edits + +Any message can be edited and the bot will take it as a new one. You can use this to "edit" commands and the bot will update it's reply. Works for 30 seconds after the message was sent. + +This can be used to update typos in announcements, fixing command name or fixing prefix (editing the message to use correct prefix will run the command). + +Another way to use this to your advantage is to traverse the `settings` command, like (each line can be an edit just adding content): + +* `settings` - lists all the groups +* `settings moderation` - lists all settings in `moderation` group +* `settings moderation muterole` - shows current value for the setting +* `settings moderation muterole muted` - Sets the setting to new value (sets `muterole` setting in `moderation` to the role `muted`) + +**Keep in mind that every message edit is like running a new command.** Remember it especially when banning or doing other destructive actions. diff --git a/index.markdown b/index.markdown new file mode 100644 index 0000000..4733f65 --- /dev/null +++ b/index.markdown @@ -0,0 +1,14 @@ +--- +# Feel free to add content and custom Front Matter to this file. +# To modify the layout, see https://jekyllrb.com/docs/themes/#overriding-theme-defaults + +layout: default +isTop: true +--- +# Index + +This subdomain is used for as a text-sharing of sorts for my personal use (basically like github gists but on my own domain). + +The following are available groups: + +* [igni](/igni) - All-in-one discord bot