├── .editorconfig ├── .github └── workflows │ └── deploy.yml ├── .gitignore ├── .markdownlint.json ├── .vscode └── extensions.json ├── LICENSE ├── README.md ├── book.toml ├── docs ├── README.md ├── SUMMARY.md ├── contributing.md ├── discord_webhook.md ├── epilogue.md ├── examples │ ├── reddit.md │ ├── spotify.md │ ├── twitch.md │ ├── twitter.md │ └── youtube.md ├── img │ ├── examples │ │ ├── reddit.png │ │ ├── reddit_filter_image.png │ │ ├── reddit_filter_text.png │ │ ├── reddit_image.png │ │ ├── reddit_link.png │ │ ├── reddit_text.png │ │ ├── spotify.png │ │ ├── twitch.png │ │ ├── twitch_custom.png │ │ ├── twitch_filter_code.png │ │ ├── twitter.png │ │ ├── twitter_custom.png │ │ ├── youtube.png │ │ └── youtube_custom.png │ ├── other │ │ ├── discord_markdown.png │ │ ├── discord_markdown_2.png │ │ ├── insomnia.png │ │ ├── insomnia_2.png │ │ ├── postman.png │ │ └── postman_2.png │ ├── structure │ │ ├── avatar_url.png │ │ ├── content.png │ │ ├── embed │ │ │ ├── author.png │ │ │ ├── color.png │ │ │ ├── description.png │ │ │ ├── fields.png │ │ │ ├── footer.png │ │ │ ├── image.png │ │ │ ├── thumbnail.png │ │ │ ├── timestamp.png │ │ │ ├── title.png │ │ │ └── url.png │ │ ├── embeds.png │ │ ├── embeds_2.png │ │ ├── file.png │ │ ├── file_2.png │ │ ├── poll.png │ │ └── username.png │ └── webhook_example.png ├── json.md ├── other │ ├── discord_markdown.md │ ├── edit_webhook_message.md │ ├── field_limits.md │ ├── rate_limits.md │ └── slack_formatting.md ├── services │ ├── ifttt.md │ └── ifttt_platform.md ├── structure │ ├── allowed_mentions.md │ ├── avatar_url.md │ ├── content.md │ ├── embed │ │ ├── author.md │ │ ├── color.md │ │ ├── description.md │ │ ├── fields.md │ │ ├── footer.md │ │ ├── image.md │ │ ├── thumbnail.md │ │ ├── timestamp.md │ │ ├── title.md │ │ └── url.md │ ├── embeds.md │ ├── file.md │ ├── poll.md │ ├── tts.md │ └── username.md └── tools │ ├── curl.md │ ├── httpie.md │ ├── insomnia.md │ ├── postman.md │ └── python.md ├── package.json ├── pnpm-lock.yaml └── scripts ├── highlight.sh └── minify.sh /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy docs 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | name: Generate docs 12 | runs-on: ubuntu-24.04 13 | 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v4 17 | 18 | - name: Install pnpm 19 | uses: pnpm/action-setup@v4 20 | with: 21 | version: 10.x 22 | 23 | - name: Setup Node.js 24 | uses: actions/setup-node@v4 25 | with: 26 | node-version: 22.x 27 | cache: pnpm 28 | 29 | - name: Install dependencies 30 | run: |- 31 | pnpm install --frozen-lockfile 32 | 33 | - name: Generate highlight.js file 34 | run: |- 35 | ./scripts/highlight.sh 36 | 37 | - name: Install latest mdBook 38 | run: |- 39 | tag="$(curl -sS 'https://api.github.com/repos/rust-lang/mdBook/releases/latest' | jq -r '.tag_name')" 40 | url="https://github.com/rust-lang/mdBook/releases/download/${tag}/mdbook-${tag}-x86_64-unknown-linux-gnu.tar.gz" 41 | mkdir -p mdBook 42 | curl -sSL "$url" | tar -xz -C mdBook 43 | echo "$PWD/mdBook" >> $GITHUB_PATH 44 | 45 | - name: Build docs 46 | run: |- 47 | mdbook build 48 | 49 | - name: Minify docs 50 | run: |- 51 | ./scripts/minify.sh 52 | 53 | - name: Publish docs 54 | uses: peaceiris/actions-gh-pages@v4 55 | with: 56 | github_token: ${{ secrets.GITHUB_TOKEN }} 57 | publish_dir: ./book 58 | force_orphan: true 59 | full_commit_message: deploy 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # build output 2 | /book/ 3 | 4 | # highlight.js 5 | /theme/highlight.js 6 | 7 | # node 8 | /node_modules/ 9 | .pnpm-debug.log* 10 | -------------------------------------------------------------------------------- /.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "MD013": false, 3 | "MD026": false 4 | } 5 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "editorconfig.editorconfig", 4 | "davidanson.vscode-markdownlint" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-2024 Birdie0 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Discord Webhooks Guide 2 | 3 | ## Requirements 4 | 5 | * [mdBook](https://github.com/rust-lang/mdBook) 6 | 7 | ## Live mode 8 | 9 | ```sh 10 | mdbook serve 11 | ``` 12 | 13 | ## Additional scripts 14 | 15 | * `highlight.sh` - generate theme/highlight.js (the one provided by mdBook doesn't include some languages used in the guide) 16 | * `minify.sh` - minify generated `html/js/css/svg` files 17 | -------------------------------------------------------------------------------- /book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | title = "Discord Webhooks Guide" 3 | authors = ["Birdie0"] 4 | description = "Comprehensive Guide about using Discord Webhooks" 5 | src = "docs" 6 | language = "en" 7 | 8 | [output.html] 9 | default-theme = "rust" 10 | preferred-dark-theme = "ayu" 11 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Discord Webhooks Guide 2 | 3 | This guide includes: 4 | 5 | * Structure of Discord Webhook 6 | * How to send Webhooks with 7 | * [IFTTT](services/ifttt.md) and [IFTTT Platform](services/ifttt_platform.md) 8 | * [Postman](tools/postman.md) 9 | * [Insomnia](tools/insomnia.md) 10 | * [curl](tools/curl.md) 11 | * [HTTPie](tools/httpie.md) 12 | * [Python](tools/python.md) 13 | * Examples 14 | * Other things :) 15 | 16 | ## Translations 17 | 18 | * [Russian translation by DarkPro1337#4304](https://darkpro1337.github.io/discord-webhooks/) 19 | -------------------------------------------------------------------------------- /docs/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | * [Introduction](README.md) 4 | * [JSON](json.md) 5 | * [Discord Webhook](discord_webhook.md) 6 | 7 | # Discord Webhook structure 8 | 9 | * [username](structure/username.md) 10 | * [avatar_url](structure/avatar_url.md) 11 | * [content](structure/content.md) 12 | * [embeds](structure/embeds.md) 13 | * [color](structure/embed/color.md) 14 | * [author](structure/embed/author.md) 15 | * [title](structure/embed/title.md) 16 | * [url](structure/embed/url.md) 17 | * [description](structure/embed/description.md) 18 | * [fields](structure/embed/fields.md) 19 | * [image](structure/embed/image.md) 20 | * [thumbnail](structure/embed/thumbnail.md) 21 | * [footer](structure/embed/footer.md) 22 | * [timestamp](structure/embed/timestamp.md) 23 | * [poll](structure/poll.md) 24 | * [tts](structure/tts.md) 25 | * [allowed_mentions](structure/allowed_mentions.md) 26 | * [file](structure/file.md) 27 | 28 | # Integrate with 29 | 30 | * [IFTTT](services/ifttt.md) 31 | * [IFTTT Platform / Filter Code](services/ifttt_platform.md) 32 | 33 | # Use with 34 | 35 | * [Postman](tools/postman.md) 36 | * [Insomnia](tools/insomnia.md) 37 | * [curl](tools/curl.md) 38 | * [HTTPie](tools/httpie.md) 39 | * [Python](tools/python.md) 40 | 41 | # Examples 42 | 43 | * [Spotify](examples/spotify.md) 44 | * [Twitch](examples/twitch.md) 45 | * [Reddit](examples/reddit.md) 46 | * [Twitter](examples/twitter.md) 47 | * [YouTube](examples/youtube.md) 48 | 49 | # Additional info 50 | 51 | * [Edit Webhook Message](other/edit_webhook_message.md) 52 | * [Rate Limits](other/rate_limits.md) 53 | * [Discord Markdown](other/discord_markdown.md) 54 | * [Slack formatting](other/slack_formatting.md) 55 | * [Field Limits](other/field_limits.md) 56 | 57 | --- 58 | 59 | * [Epilogue](epilogue.md) 60 | * [Contributing](contributing.md) 61 | -------------------------------------------------------------------------------- /docs/contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Repo is public now, if you have any suggestions, fixes or improvements, feel free to open issue or create pull request. 4 | 5 | Feel free to contact me on Discord, my Discord tag is `birdie0` (was `Birdie♫#6017`). 6 | If you have no mutual servers with me you can always find me on [the r/IFTTT Discord server](https://discord.gg/ifttt). 7 | 8 | Things that are planned, but not in progress at the moment: 9 | 10 | * Guide in pictures (some people understand visual information better) 11 | * Guides for [Pipedream](https://pipedream.com/), [Zapier](https://zapier.com/) and [Make](https://www.make.com/en) (formerly Integromat) services 12 | * Guides for [Advanced REST Client](https://install.advancedrestclient.com/install), including mobile clients and iOS Shortcuts 13 | * Common mistakes and solutions 14 | * More examples 15 | * Translations (if you want to make or made one already, please, let me know) 16 | -------------------------------------------------------------------------------- /docs/discord_webhook.md: -------------------------------------------------------------------------------- 1 | # Structure of Webhook 2 | 3 | Before using Webhooks you have to know the structure. All elements listed here are *optional* but request body should contain `content`, `embeds`, `poll` or attachments, otherwise request will fail. 4 | 5 | * `username` - overrides the predefined username of the webhook 6 | * `avatar_url` - overrides the predefined avatar of the webhook 7 | * `content` - text message, can contain up to 2000 characters 8 | * `embeds` - array of embed objects. In comparison with bots, webhooks can have more than one custom embed 9 | * `color` - color code of the embed. You have to use Decimal numeral system, not Hexadecimal. You can use [SpyColor](https://www.spycolor.com/) for that. It has decimal number converter. 10 | * `author` - embed author object 11 | * `name` - name of author 12 | * `url` - url of author. If `name` was used, it becomes a hyperlink 13 | * `icon_url` - url of author icon 14 | * `title` - title of embed 15 | * `url` - url of embed. If `title` was used, it becomes hyperlink 16 | * `description` - description text 17 | * `fields` - array of embed field objects 18 | * `name` - name of the field 19 | * `value` - value of the field 20 | * `inline` - if true, fields will be displayed in the same line, 3 per line, 4th+ will be moved to the next line 21 | * `thumbnail` - embed thumbnail object 22 | * `url` - url of thumbnail 23 | * `image` - embed image object 24 | * `url` - image url 25 | * `footer` - embed footer object 26 | * `text` - footer text, doesn't support Markdown 27 | * `icon_url` - url of footer icon 28 | * `timestamp` - ISO8601 timestamp (`yyyy-mm-ddThh:mm:ss.msZ`) 29 | * `poll` - poll object 30 | * `question` - poll question object 31 | * `text` - poll question text 32 | * `answers` - array of poll answer objects 33 | * `poll_media` - poll answer object 34 | * `text` - poll answer text 35 | * `emoji` - emoji object (optional) 36 | * `id` - id of emoji (if custom) 37 | * `name` - name of emoji (if built-in) 38 | * `duration` - duration of the poll in hours 39 | * `allow_multiselect` - if true, allows to select multiple answers 40 | * `tts` - makes message to be spoken as with `/tts` command 41 | * `allowed_mentions` - object allowing to control who will be mentioned by message 42 | * `parse` - array, can include next values: `"roles"`, `"users"` and `"everyone"`, depends on which decides which mentions work. If empty, none mention work. 43 | * `roles` - array, lists ids of roles which can be mentioned with message, remove `"roles"` from `parse` when you use this one. 44 | * `users` - array, lists ids of roles which can be mentioned with message, remove `"users"` from `parse` when you use this one. 45 | 46 | ## Webhook example 47 | 48 | ```json 49 | { 50 | "username": "Webhook", 51 | "avatar_url": "https://i.imgur.com/4M34hi2.png", 52 | "content": "Text message. Up to 2000 characters.", 53 | "embeds": [ 54 | { 55 | "author": { 56 | "name": "Birdie♫", 57 | "url": "https://www.reddit.com/r/cats/", 58 | "icon_url": "https://i.imgur.com/R66g1Pe.jpg" 59 | }, 60 | "title": "Title", 61 | "url": "https://google.com/", 62 | "description": "Text message. You can use Markdown here. *Italic* **bold** __underline__ ~~strikeout~~ [hyperlink](https://google.com) `code`", 63 | "color": 15258703, 64 | "fields": [ 65 | { 66 | "name": "Text", 67 | "value": "More text", 68 | "inline": true 69 | }, 70 | { 71 | "name": "Even more text", 72 | "value": "Yup", 73 | "inline": true 74 | }, 75 | { 76 | "name": "Use `\"inline\": true` parameter, if you want to display fields in the same line.", 77 | "value": "okay..." 78 | }, 79 | { 80 | "name": "Thanks!", 81 | "value": "You're welcome :wink:" 82 | } 83 | ], 84 | "thumbnail": { 85 | "url": "https://upload.wikimedia.org/wikipedia/commons/3/38/4-Nature-Wallpapers-2014-1_ukaavUI.jpg" 86 | }, 87 | "image": { 88 | "url": "https://upload.wikimedia.org/wikipedia/commons/5/5a/A_picture_from_China_every_day_108.jpg" 89 | }, 90 | "footer": { 91 | "text": "Woah! So cool! :smirk:", 92 | "icon_url": "https://i.imgur.com/fKL31aD.jpg" 93 | } 94 | } 95 | ] 96 | } 97 | ``` 98 | 99 | ## And how it looks 100 | 101 | ![webhook result example](img/webhook_example.png) 102 | -------------------------------------------------------------------------------- /docs/epilogue.md: -------------------------------------------------------------------------------- 1 | # Epilogue 2 | 3 | I hope this guide will help you make cool things for your server. I spent on this guide a lot of time with checking Discord API documentation and testing webhooks with different parameters. The main reason why I made this guide is there was no detailed guide about using webhooks. Existing ones describe using webhooks with known services with pre-made json body without showing how flexible settings are. 4 | Existing ones were like *copy & paste* and nothing more. I do not like that. 5 | 6 | If you wanna suggest something, like Applet recipe or something fancy, please, let me know. My Discord tag is `birdie0` (was `Birdie♫#6017`). 7 | 8 | Also I want to say thank next people: 9 | 10 | * `legioncabal` (`LEGION#0240`) - grammar fixes and pre-release testing 11 | * `woody5728` (`Delta#5728`) - pre-release testing 12 | * `wolfgang1710` (`WolfGang1710#6782`) - pre-release testing 13 | * `darkpro1337` (`DarkPro1337#4304`) - Russian translation 14 | 15 | Thank you all, you are awesome!!! 16 | -------------------------------------------------------------------------------- /docs/examples/reddit.md: -------------------------------------------------------------------------------- 1 | # Reddit 2 | 3 | Tip: 4 | 5 | > To filter out text posts it's recommended to use `New post from search` trigger and `subreddit:XYZ self:no` query, where `XYZ` is subreddit name. 6 | 7 | ## Reddit embed 8 | 9 | ```json 10 | { 11 | "content": "{{PostURL}}" 12 | } 13 | ``` 14 | 15 | ![Reddit embed example](../img/examples/reddit.png) 16 | 17 | ## Embed with text 18 | 19 | Image preview won't be shown and if content has more than 2048 characters, request will fail. 20 | 21 | ```json 22 | { 23 | "embeds": [{ 24 | "color": 16729344, 25 | "author": { 26 | "name": "u/{{Author}}", 27 | "url": "https://www.reddit.com/user/{{Author}}", 28 | "icon_url": "https://avatar-resolver.vercel.app/reddit/{{Author}}" 29 | }, 30 | "title": "<<<{{Title}}>>>", 31 | "url": "{{PostURL}}", 32 | "description": "<<<{{Content}}>>>", 33 | "footer": { "text": "r/{{Subreddit}} • Posted at {{PostedAt}}" } 34 | }] 35 | } 36 | ``` 37 | 38 | ![Embed with text example](../img/examples/reddit_text.png) 39 | 40 | ## Embed with image 41 | 42 | `"file not found"` placeholder will be shown on text posts. 43 | 44 | ```json 45 | { 46 | "embeds": [{ 47 | "color": 16729344, 48 | "author": { 49 | "name": "u/{{Author}}", 50 | "url": "https://www.reddit.com/user/{{Author}}", 51 | "icon_url": "https://avatar-resolver.vercel.app/reddit/{{Author}}" 52 | }, 53 | "title": "<<<{{Title}}>>>", 54 | "url": "{{PostURL}}", 55 | "image": { "url": "{{ImageURL}}" }, 56 | "footer": { "text": "r/{{Subreddit}} • Posted at {{PostedAt}}" } 57 | }] 58 | } 59 | ``` 60 | 61 | ![Embed with image example](../img/examples/reddit_image.png) 62 | 63 | ## Link embed 64 | 65 | Best with link post which are video or GIFs. `"allowed_mentions"` will disable everyone/here mentions in content if there any, user/role mentions will still work if you wish to add any. big text posts (over 1k characters). 66 | 67 | ```json 68 | { 69 | "content": "New Post in **r/{{Subreddit}}** by **u/{{Author}}**\n**<<<{{Title}}>>>**\n<<<{{Content}}>>>", 70 | "allowed_mentions": { "parse": ["users", "roles"] } 71 | } 72 | ``` 73 | 74 | ![Link embed example](../img/examples/reddit_link.png) 75 | 76 | ## Filter code 77 | 78 | Adds text to embed for text posts and image for link ones, shortens content so it doesn't break the body 79 | 80 | ```ts 81 | const body: any = { 82 | embeds: [{ 83 | color: 0xFF4500, 84 | author: { 85 | name: `u/${Trigger.Author}`, 86 | url: `https://www.reddit.com/user/${Trigger.Author}`, 87 | icon_url: `https://avatar-resolver.vercel.app/reddit/${Trigger.Author}` 88 | }, 89 | title: Trigger.Title, 90 | url: Trigger.PostURL, 91 | footer: { text: `r/${Trigger.Subreddit}` }, 92 | timestamp: Meta.triggerTime // returns null | use .currentUserTime for now 93 | }] 94 | }; 95 | if (/^http\S+$/.test(Trigger.Content)) { 96 | body.embeds[0].image = { url: Trigger.ImageURL }; 97 | } else { 98 | body.embeds[0].description = Trigger.Content.slice(0, 2048); 99 | } 100 | MakerWebhooks.makeWebRequest.setBody(JSON.stringify(body)); 101 | ``` 102 | 103 | ![Filter code image example](../img/examples/reddit_filter_image.png) 104 | 105 | ![Filter code text example](../img/examples/reddit_filter_text.png) 106 | -------------------------------------------------------------------------------- /docs/examples/spotify.md: -------------------------------------------------------------------------------- 1 | # Spotify 2 | 3 | ## If new saved track, then make a web request 4 | 5 | ```json 6 | { 7 | "embeds": [{ 8 | "color": 2021216, 9 | "title": "New song added!", 10 | "thumbnail": { 11 | "url": "{{AlbumCoverURL}}" 12 | }, 13 | "fields":[ 14 | { 15 | "name": "Track", 16 | "value": "[{{TrackName}}]({{TrackURL}})", 17 | "inline": true 18 | }, 19 | { 20 | "name": "Artist", 21 | "value": "{{ArtistName}}", 22 | "inline": true 23 | }, 24 | { 25 | "name": "Album", 26 | "value": "{{AlbumName}}", 27 | "inline": true 28 | } 29 | ], 30 | "footer": { 31 | "text": "Added {{SavedAt}}", 32 | "icon_url": "https://upload.wikimedia.org/wikipedia/commons/thumb/1/19/Spotify_logo_without_text.svg/200px-Spotify_logo_without_text.svg.png" 33 | } 34 | }] 35 | } 36 | ``` 37 | 38 | ![spotify example](../img/examples/spotify.png) 39 | -------------------------------------------------------------------------------- /docs/examples/twitch.md: -------------------------------------------------------------------------------- 1 | # Twitch 2 | 3 | ## Twitch embed 4 | 5 | ```json 6 | { 7 | "content": "{{ChannelUrl}}" 8 | } 9 | ``` 10 | 11 | ![Twitch example](../img/examples/twitch.png) 12 | 13 | ## Custom embed 14 | 15 | Preview will be cached and embeds will show same image. 16 | 17 | ```json 18 | { 19 | "embeds": [{ 20 | "color": 9520895, 21 | "author": { 22 | "name": "{{ChannelName}} is now streaming", 23 | "url": "{{ChannelUrl}}", 24 | "icon_url": "https://avatar-resolver.vercel.app/twitch/{{ChannelName}}" 25 | }, 26 | "fields": [ 27 | { 28 | "name": ":joystick: Game", 29 | "value": "<<<{{Game}}>>>\u200B", 30 | "inline": true 31 | }, 32 | { 33 | "name": ":busts_in_silhouette: Viewers", 34 | "value": "{{CurrentViewers}}", 35 | "inline": true 36 | } 37 | ], 38 | "image": { "url": "{{StreamPreview}}" } 39 | }] 40 | } 41 | ``` 42 | 43 | ![Twitch example](../img/examples/twitch_custom.png) 44 | 45 | ## Filter code 46 | 47 | Fixed issue with cached preview, added game box art. 48 | 49 | ```ts 50 | const body: any = { 51 | embeds: [{ 52 | color: 0x9146ff, 53 | author: { 54 | name: `${Trigger.ChannelName} is now streaming`, 55 | url: Trigger.ChannelUrl, 56 | icon_url: `https://avatar-resolver.vercel.app/twitch/${Trigger.ChannelName}` 57 | }, 58 | fields: [{ 59 | name: ':joystick: Game', 60 | value: Trigger.Game || 'No Game', 61 | inline: true 62 | }, { 63 | name: ':busts_in_silhouette: Viewers', 64 | value: Trigger.CurrentViewers, 65 | inline: true 66 | }], 67 | thumbnail: { url: `https://avatar-resolver.vercel.app/twitch-boxart/${encodeURIComponent(Trigger.Game || '')}` }, 68 | image: { url: `${Trigger.StreamPreview}?${+moment()}` }, 69 | timestamp: Meta.triggerTime 70 | }] 71 | }; 72 | MakerWebhooks.makeWebRequest.setBody(JSON.stringify(body)); 73 | ``` 74 | 75 | ![Twitch example](../img/examples/twitch_filter_code.png) 76 | -------------------------------------------------------------------------------- /docs/examples/twitter.md: -------------------------------------------------------------------------------- 1 | # Twitter 2 | 3 | ## Twitter embed 4 | 5 | ```json 6 | { 7 | "content": "{{LinkToTweet}}" 8 | } 9 | ``` 10 | 11 | ![Twitter embed example](../img/examples/twitter.png) 12 | 13 | ## Custom embed 14 | 15 | Custom embed won't show image or video. 16 | 17 | ```json 18 | { 19 | "embeds": [{ 20 | "color": 1942002, 21 | "author": { 22 | "name": "{{UserName}}", 23 | "url": "https://twitter.com/{{UserName}}", 24 | "icon_url": "https://avatar-resolver.vercel.app/twitter/{{UserName}}" 25 | }, 26 | "title": "Link", 27 | "url": "{{LinkToTweet}}", 28 | "description": "<<<{{Text}}>>>", 29 | "footer": { 30 | "text": "Posted at {{CreatedAt}}" 31 | } 32 | }] 33 | } 34 | ``` 35 | 36 | ![custom embed example](../img/examples/twitter_custom.png) 37 | -------------------------------------------------------------------------------- /docs/examples/youtube.md: -------------------------------------------------------------------------------- 1 | # YouTube 2 | 3 | ## YouTube embed 4 | 5 | ```json 6 | { 7 | "content": "{{Url}}" 8 | } 9 | ``` 10 | 11 | ![YouTube example](../img/examples/youtube.png) 12 | 13 | ## Custom embed 14 | 15 | Embed includes thumbnail without ability to watch it in Discord. 16 | 17 | ```json 18 | { 19 | "embeds": [{ 20 | "color": 16711680, 21 | "author": { 22 | "name": "<<<{{ChannelName}}>>>", 23 | "icon_url": "https://avatar-resolver.vercel.app/youtube-avatar/q?url={{Url}}" 24 | }, 25 | "title": "<<<{{Title}}>>>", 26 | "url": "{{Url}}", 27 | "description": "<<<{{Description}}>>>", 28 | "image": { "url": "https://avatar-resolver.vercel.app/youtube-thumbnail/q?url={{Url}}" }, 29 | "footer": { "text": "Published at {{PublishedAt}}" } 30 | }] 31 | } 32 | ``` 33 | 34 | ![YouTube example](../img/examples/youtube_custom.png) 35 | -------------------------------------------------------------------------------- /docs/img/examples/reddit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/examples/reddit.png -------------------------------------------------------------------------------- /docs/img/examples/reddit_filter_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/examples/reddit_filter_image.png -------------------------------------------------------------------------------- /docs/img/examples/reddit_filter_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/examples/reddit_filter_text.png -------------------------------------------------------------------------------- /docs/img/examples/reddit_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/examples/reddit_image.png -------------------------------------------------------------------------------- /docs/img/examples/reddit_link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/examples/reddit_link.png -------------------------------------------------------------------------------- /docs/img/examples/reddit_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/examples/reddit_text.png -------------------------------------------------------------------------------- /docs/img/examples/spotify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/examples/spotify.png -------------------------------------------------------------------------------- /docs/img/examples/twitch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/examples/twitch.png -------------------------------------------------------------------------------- /docs/img/examples/twitch_custom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/examples/twitch_custom.png -------------------------------------------------------------------------------- /docs/img/examples/twitch_filter_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/examples/twitch_filter_code.png -------------------------------------------------------------------------------- /docs/img/examples/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/examples/twitter.png -------------------------------------------------------------------------------- /docs/img/examples/twitter_custom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/examples/twitter_custom.png -------------------------------------------------------------------------------- /docs/img/examples/youtube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/examples/youtube.png -------------------------------------------------------------------------------- /docs/img/examples/youtube_custom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/examples/youtube_custom.png -------------------------------------------------------------------------------- /docs/img/other/discord_markdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/other/discord_markdown.png -------------------------------------------------------------------------------- /docs/img/other/discord_markdown_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/other/discord_markdown_2.png -------------------------------------------------------------------------------- /docs/img/other/insomnia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/other/insomnia.png -------------------------------------------------------------------------------- /docs/img/other/insomnia_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/other/insomnia_2.png -------------------------------------------------------------------------------- /docs/img/other/postman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/other/postman.png -------------------------------------------------------------------------------- /docs/img/other/postman_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/other/postman_2.png -------------------------------------------------------------------------------- /docs/img/structure/avatar_url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/structure/avatar_url.png -------------------------------------------------------------------------------- /docs/img/structure/content.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/structure/content.png -------------------------------------------------------------------------------- /docs/img/structure/embed/author.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/structure/embed/author.png -------------------------------------------------------------------------------- /docs/img/structure/embed/color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/structure/embed/color.png -------------------------------------------------------------------------------- /docs/img/structure/embed/description.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/structure/embed/description.png -------------------------------------------------------------------------------- /docs/img/structure/embed/fields.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/structure/embed/fields.png -------------------------------------------------------------------------------- /docs/img/structure/embed/footer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/structure/embed/footer.png -------------------------------------------------------------------------------- /docs/img/structure/embed/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/structure/embed/image.png -------------------------------------------------------------------------------- /docs/img/structure/embed/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/structure/embed/thumbnail.png -------------------------------------------------------------------------------- /docs/img/structure/embed/timestamp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/structure/embed/timestamp.png -------------------------------------------------------------------------------- /docs/img/structure/embed/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/structure/embed/title.png -------------------------------------------------------------------------------- /docs/img/structure/embed/url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/structure/embed/url.png -------------------------------------------------------------------------------- /docs/img/structure/embeds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/structure/embeds.png -------------------------------------------------------------------------------- /docs/img/structure/embeds_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/structure/embeds_2.png -------------------------------------------------------------------------------- /docs/img/structure/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/structure/file.png -------------------------------------------------------------------------------- /docs/img/structure/file_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/structure/file_2.png -------------------------------------------------------------------------------- /docs/img/structure/poll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/structure/poll.png -------------------------------------------------------------------------------- /docs/img/structure/username.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/structure/username.png -------------------------------------------------------------------------------- /docs/img/webhook_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Birdie0/discord-webhooks-guide/bf205c9f9fcb6a75c9736fc1669eef2d3104fd68/docs/img/webhook_example.png -------------------------------------------------------------------------------- /docs/json.md: -------------------------------------------------------------------------------- 1 | # JSON 2 | 3 | If you do not know anything about JSON, please, spend some time on learning JSON structure. 4 | 5 | ## `What is JSON?` 6 | 7 | **JSON** stands for 8 | 9 | * **J**ava 10 | * **S**cript 11 | * **O**bject 12 | * **N**otation 13 | 14 | N.B. Don't be scared. JSON is easy to learn and use! This is not a programming language!!! 15 | 16 | JSON is data-storing format that easy to read and write for humans and robots. 17 | 18 | * `key: value` - this is key-value pair. 19 | * Key and value are separated with semicolon (`:`), no exceptions. 20 | * Multiple key-values are separated with comma (`,`), no exceptions. 21 | * Spaces and line breaks are ok till they not the part of key or value. 22 | * The `key` is always text inserted between double quotes (`" "`). 23 | * But `value` can be different types: 24 | * **string** - `"sample text"`, `"cool\nthings"` 25 | * **number** - `42`, `-300`, `6.62e-34` 26 | * **object** - `{ "name": "Jason", "likes": ["apples", "oranges"] }` 27 | * **array** - `["apple", "banana", "orange"]`, `[1, true, 3, "meow"]` 28 | * **boolean** - `true`, `false` 29 | * **null** - `null` 30 | 31 | ### About strings 32 | 33 | Strings can store any characters you want, but some of them need to be escaped: 34 | 35 | * **double quote** - `\"` 36 | * **slash** - `\\` 37 | * **backslash** - `\/` (escaping is optional) 38 | * **newline** - `\n` (use this if you want to add newline to value) 39 | * **carriage return** - `\r` 40 | * **horizontal tab** - `\t` 41 | * **backspace** - `\b` 42 | * **form feed** - `\f` 43 | * **unicode character** - `\uxxxx` 44 | 45 | ### Example 46 | 47 | ```json 48 | { 49 | "name": "Pumpkin", 50 | "age": 7, 51 | "likes": [ 52 | "patting", 53 | "sleeping in a garden", 54 | "salmon" 55 | ], 56 | "appearance": "Orange Tabby", 57 | "owner_name": "Jane Doe", 58 | "phone_number": "+447712345678", 59 | "address": { 60 | "country": "England", 61 | "city": "London", 62 | "street": "Crown Street", 63 | "house": 38, 64 | "notes": null 65 | } 66 | } 67 | ``` 68 | 69 | ## Recommended sources 70 | 71 | * [Learn X in Y minutes, Where X=json](https://learnxinyminutes.com/docs/json/) - quick JSON tutorial 72 | * [JSON official site](https://www.json.org/) - official website that explains the format using flowcharts 73 | -------------------------------------------------------------------------------- /docs/other/discord_markdown.md: -------------------------------------------------------------------------------- 1 | # Discord Markdown 2 | 3 | ## Text formatting 4 | 5 | ![discord markdown example](../img/other/discord_markdown.png) 6 | 7 | [Markdown Text 101](https://support.discord.com/hc/en-us/articles/210298617-Markdown-Text-101-Chat-Formatting-Bold-Italic-Underline-) from Discord Support. 8 | Formatting works in all fields except `username`, embed's `title`, footer's `text`, that means `:emoji:` won't work there as well (except it's in Unicode). 9 | 10 | ## Discord tags 11 | 12 | 2 ways: 13 | 14 | 1. Using developer mode: `User settings` ➤ `Advanced` ➤ `Developer Mode` ➤ enable. 15 | Now you can find id of any user, message, channel or server with right click ➤ Copy ID 16 | 2. Using magic backslash `\` escaping: Put it before (or if you're on iOS, surround with \`\`) user mention, mentionable role, channel tag or custom emoji and you will get unformatted data 17 | 18 | ![discord tags example](../img/other/discord_markdown_2.png) 19 | 20 | This thing must be mentioned somewhere because some of you want to use this in messages. 21 | 22 | | How it writes | How it looks | 23 | | :-----------------------------: | :-------------------: | 24 | | `<@&role-id>` | `@role-name` | 25 | | `<#channel-id>` | `#channel-name` | 26 | | `<@user-id>` | `@mention` | 27 | | `<:custom_emoji_name:emoji-id>` | `:custom_emoji_name:` | 28 | 29 | [Discord API reference for available tags](https://discord.com/developers/docs/reference#message-formatting-formats) 30 | 31 | ## Discord timestamp 32 | 33 | Discord added support of dynamic timestamps that allow you to reference specific date and time so it will show dynamically for everyone depending on timezone they're in and Discord language setting. You can generate them by hand (need [Unix timestamp](https://www.unixtimestamp.com/)) or using one of these websites: 34 | 35 | - [r.3v.fi/discord-timestamps](https://r.3v.fi/discord-timestamps/) 36 | - [timestamps.app](https://www.timestamps.app/) 37 | 38 | Result string should look like this: `` or `` 39 | 40 | [Discord API reference for available formatting styles](https://discord.com/developers/docs/reference#message-formatting-timestamp-styles) 41 | -------------------------------------------------------------------------------- /docs/other/edit_webhook_message.md: -------------------------------------------------------------------------------- 1 | # Edit Webhook Message 2 | 3 | Identically to sending messages with webhooks you can edit previously sent ones. For that you need to have message id which can be copied with right-clicking on the message and selecting `Copy Message ID` from context menu (`Developer Mode` has to be enabled in user settings). Alternatively, id can be retrieved from response after webhook sending request (`wait=true` has to be present in query). 4 | 5 | * Request URL is `https://discord.com/api/webhooks/123/w3bh00k_t0k3n/messages/456`, where `456` is message id. 6 | * Request verb has to be set to `PATCH` instead of `POST`. 7 | * Request body is identical to the one we use for sending, but you have to consider next things: 8 | 9 | * Not providing `content` and `embeds` won't remove them from message, for that you have to pass empty string (`"content": ""`) and array (`"embeds": []`) respectively. 10 | * Attachments will be appended instead of replaced, to remove all attachments pass `attachments` with empty array in value (`"attachments": []`). If you want some of them to persist provide them in the same `attachments` array (attachment objects have to be retrieved from previous edit or send responses) 11 | 12 | [Discord API reference](https://discord.com/developers/docs/resources/webhook#edit-webhook-message) 13 | -------------------------------------------------------------------------------- /docs/other/field_limits.md: -------------------------------------------------------------------------------- 1 | # Field Limits 2 | 3 | | Field | Limit | 4 | | ---------------------------------- | ---------------- | 5 | | `username` | 1-80 characters | 6 | | `content` | 2000 characters | 7 | | `embeds` | 10 embed objects | 8 | | `title`* | 256 characters | 9 | | `description`* | 4096 characters | 10 | | `author.name`* | 256 characters | 11 | | `fields` | 25 field objects | 12 | | `field.name`* | 256 characters | 13 | | `field.value`* | 1024 characters | 14 | | `footer.text`* | 2048 characters | 15 | | `file` (not actual field name) | 10 files | 16 | | sum of characters in marked fields | 6000 characters | 17 | 18 | [Discord API reference](https://discord.com/developers/docs/resources/channel#embed-object-embed-limits) 19 | -------------------------------------------------------------------------------- /docs/other/rate_limits.md: -------------------------------------------------------------------------------- 1 | # Rate Limits 2 | 3 | Rate limits, or on other words limitation of request rate, allow to limit usage os specific APIs. 4 | In case you've been using IFTTT you'll likely encountered rate limit errors as updates from your triggers are sent in bulk with no rate limit handling. 5 | 6 | If to sum it up you can send **5** requests per **2** seconds per webhook, failed requests count towards rate limit same as successful ones. 7 | 8 | If you're writing or making some thing that would require sending big number of webhook messages you have to implement proper rate limit handling. 9 | All webhook links have separate webhooks, so if you have multiple created they won't affect each others. 10 | Thankfully, request responses include all needed headers: 11 | 12 | * `X-RateLimit-Limit` - number of requests that can be made during single rate limit window 13 | * `X-RateLimit-Remaining` - number of remaining requests that can be made (decreases with each request, when it reaches zero next request will likely fail) 14 | * `X-RateLimit-Reset` - Epoch time (seconds since 00:00:00 UTC on January 1, 1970) at which the rate limit resets 15 | * `X-RateLimit-Reset-After` - Total time (in seconds) of when the current rate limit bucket will reset. Can have decimals to match previous millisecond rate limit precision 16 | * `X-RateLimit-Bucket` - A unique string denoting the rate limit being encountered (non-inclusive of top-level resources in the path) 17 | 18 | So generally you have to save and check these values before sending new requests so your app won't run into rate limit issues. 19 | 20 | Another anti-request fail measure would be retrying request in case it failed, but still relying on response headers. 21 | 22 | So usual implementation should be queue to which requests for sending are being added, before each request we have to check response headers, 23 | if there's still space for another request (`X-RateLimit-Remaining` is greater than zero) perform one, otherwise wait `X-RateLimit-Reset-After` seconds or until after `X-RateLimit-Reset` time. 24 | 25 | [Discord API reference](https://discord.com/developers/docs/topics/rate-limits#header-format) 26 | -------------------------------------------------------------------------------- /docs/other/slack_formatting.md: -------------------------------------------------------------------------------- 1 | # Slack formatting 2 | 3 | Discord webhooks support [Slack](https://slack.com/) formatting too. 4 | Just append `/slack` to webhook url to start using it. 5 | 6 | ## First layer 7 | 8 | | Discord | Slack | Comment | 9 | | ---------- | ----------- | ------- | 10 | | username | username | | 11 | | avatar_url | icon_url | | 12 | | content | text | | 13 | | embeds | attachments | | 14 | 15 | ## embeds (attachments) 16 | 17 | | Discord | Slack | Comment | 18 | | ----------- | ---------- | ------------------------------------------------------------------------------------------------------------------- | 19 | | color | color | supports hex codes `"#4c73c7"` and has three predefined colors: `good`(green), `warning`(yellow) and `danger`(red). | 20 | | author | - | author block declares in different way. See the `author` table. | 21 | | title | title | | 22 | | url | title_link | | 23 | | description | text | | 24 | | fields | fields | | 25 | | image | - | image block declares in different way. See the [`image`](#image) table. | 26 | | thumbnail | - | thumbnail block declares in different way. See the [`thumbnail`](#thumbnail) table. | 27 | | footer | footer | not a block. See the [`footer`](#footer) table | 28 | | timestamp | ts | requires [unix timestamp](https://www.unixtimestamp.com/) format. | 29 | | - | fallback | embed summary for notifications. Not sure if Discord supports that. | 30 | | - | pretext | kinda broken atm. Should works as "content" before embed, but it just appends to "description". | 31 | 32 | ### author 33 | 34 | | Discord | Slack | Comment | 35 | | -------- | ----------- | ------------------------------------------------------------ | 36 | | name | author_name | just write them inside of `attachments` like `color` or etc. | 37 | | url | author_link | | 38 | | icon_url | author_icon | | 39 | 40 | ### fields 41 | 42 | | Discord | Slack | Comment | 43 | | ------- | ----- | ------- | 44 | | name | title | | 45 | | value | value | | 46 | | inline | short | | 47 | 48 | ### image 49 | 50 | | Discord | Slack | Comment | 51 | | ------- | --------- | ------------------------------------------------------------------------------ | 52 | | url | image_url | no `image` block. Just write them inside of `attachments` like `color` or etc. | 53 | 54 | ### thumbnail 55 | 56 | | Discord | Slack | Comment | 57 | | ------- | --------- | ---------------------------------------------------------------------------------- | 58 | | url | thumb_url | no `thumbnail` block. Just write them inside of `attachments` like `color` or etc. | 59 | 60 | ### footer 61 | 62 | | Discord | Slack | Comment | 63 | | ------- | ----------- | ------------------------------------------------------------------------------- | 64 | | text | footer | no `footer` block. Just write them inside of `attachments` like `color` or etc. | 65 | | icon | footer_icon | | 66 | 67 | ## Example 68 | 69 | Slack formatted example from [here](discord_webhook.md): 70 | 71 | ```json 72 | { 73 | "username": "Webhook", 74 | "icon_url": "https://i.imgur.com/4M34hi2.png", 75 | "text": "Text message. Up to 2000 characters.", 76 | "attachments": [ 77 | { 78 | "author_name": "Birdie♫", 79 | "author_link": "https://www.reddit.com/r/cats/", 80 | "author_icon": "https://i.imgur.com/R66g1Pe.jpg", 81 | "title": "Title", 82 | "title_link": "https://google.com/", 83 | "text": "Text message. You can use Markdown here. *Italic* **bold** __underline__ ~~strikeout~~ [hyperlink](https://google.com) `code`", 84 | "color": "#e8d44f", 85 | "fields": [ 86 | { 87 | "title": "Text", 88 | "value": "More text", 89 | "short": true 90 | }, 91 | { 92 | "title": "Even more text", 93 | "value": "Yup", 94 | "short": true 95 | }, 96 | { 97 | "title": "Use `\"inline\": true` parameter, if you want to display fields in the same line.", 98 | "value": "okay..." 99 | }, 100 | { 101 | "title": "Thanks!", 102 | "value": "You're welcome :wink:" 103 | } 104 | ], 105 | "thumb_url": "https://upload.wikimedia.org/wikipedia/commons/3/38/4-Nature-Wallpapers-2014-1_ukaavUI.jpg", 106 | "image_url": "https://upload.wikimedia.org/wikipedia/commons/5/5a/A_picture_from_China_every_day_108.jpg", 107 | "footer": "Woah! So cool! :smirk:", 108 | "footer_icon": "https://i.imgur.com/fKL31aD.jpg" 109 | } 110 | ] 111 | } 112 | ``` 113 | 114 | ### Additional info: 115 | 116 | * [Execute Slack-Compatible Webhook](https://discord.com/developers/docs/resources/webhook#execute-slackcompatible-webhook) 117 | * [Incoming Webhooks](https://api.slack.com/messaging/webhooks) 118 | * [Basic message formatting](https://api.slack.com/reference/surfaces/formatting) 119 | * [Attaching content and links to messages](https://api.slack.com/messaging/composing/layouts#attachments) 120 | -------------------------------------------------------------------------------- /docs/services/ifttt.md: -------------------------------------------------------------------------------- 1 | # IFTTT 2 | 3 | IFTTT is a very awesome service for connecting services. It supports Webhooks, so we can use it with Discord. 4 | 5 | ## Create an Account on IFTTT 6 | 7 | Visit [IFTTT](https://ifttt.com/) and create yourself an account (if you don't have one yet). 8 | 9 | ## Create Webhook on Discord 10 | 11 | 1. Go to **Server or Channel settings** ➤ **Integrations** ➤ **Webhooks** ➤ **Create Webhook** or **Click on existing one** if you created one already. 12 | 2. Setup name, avatar and the channel in which webhook messages will be sent. When ready, click **Save Changes** and **Copy Webhook URL**. 13 | 14 | 21 | 22 | **⚠️ Attention! Keep URL safe, don't share them with people you don't trust, don't post it in public channels, don't give your server mods Administrator or Manage Webhooks permission as it gives access to them as well. Webhooks are quite powerful and can cause some troubles, which including, but not limited to, @everyone/@here mentions (webhooks ignore channel permissions), message/image spam (webhooks have max 5 requests in 2 seconds window rate limit, but still it's 150 requests per minute) and requests can't be traced, so finding the guilty is pretty much impossible, so you're warned I guess... If something like this happen, remove webhook causing problems and it won't be able to send messages anymore.** 23 | 24 | ## Creating an Applet 25 | 26 | ### If `this` 27 | 28 | 1. Go to [**IFTTT website**](https://ifttt.com/) ➤ click **Create** ➤ [**Applets**](https://ifttt.com/create). 29 | 2. Click `[+]this`. 30 | 3. Choose a service you want accept updates/feeds from, use search to find it faster. 31 | 4. If you connect service in the first time it may ask you to authorize, just follow the steps. 32 | 5. Most of services have multiple triggers. Choose the one that fits your needs. 33 | 6. Fill the fields. Here can be more than one step. Read the descriptions and examples. 34 | 35 | ### Then `that` 36 | 37 | 1. Click `[+]that` 38 | 2. Search for **Webhooks** with the search bar. 39 | 3. Choose **Make a web request** as action. 40 | 4. Paste the **Webhook URL** in **URL** field. 41 | 5. Select **POST** as **Method**. 42 | 6. Select **application/json** as **Content Type**. 43 | 7. **Body** is the main part. there's couple of things you have to know: 44 | 45 | * Neither IFTTT nor Discord build the result message, you're the one responsible for it. 46 | * Request body is written in JSON, if you have no idea what it is, please check [JSON](../json.html) reference page first, then structure pages. 47 | * All available Ingredients are listed under **Add Ingredient** dropdown menu. If something Ingredient not listed means you can't use it and it will cause error on proceeding. Also, make sure you put spaces between `{{` `}}` which are not part of Ingredient, like here: `{"embeds": [{"image": {"url": "{{ImageUrl}}"}}]}` ➤ `{"embeds": [{"image": {"url": "{{ImageUrl}}"} }]}` otherwise they may be assumed as end of Ingredient name and break the validation. 48 | * Due to certain specifics of JSON format the Ingredients IFTTT provides may break the request. Because that escaping Ingredients is highly recommended! To escape Ingredient, add `<<<` & `>>>` around `{{Ingredient}}` ➤ `<<<{{Ingredient}}>>>` (website says `<<>>`, but that a typo). Only times when escaping rule may be ignored are when Ingredient is 100% URL and when Ingredient is part of URL and that Ingredient only consists of URL-safe characters, like: `https://twitter.com/{{Username}}` (in some cases escaping these were causing broken requests). 49 | * You probably noticed when you post link in channel the embed appears under the link, it works in the same way with Webhooks! (adding embeds to body or adding `<>` around links disables that behavior though). So sometimes, instead of building complex request body `{"content": "{{Url}}"}` (Url is placeholder, it may be called differently between services) can be more than enough! 50 | * Always check JSON for being valid! You can use text editors with JSON support, [Embed Visualizer by leovoel](https://leovoel.github.io/embed-visualizer/) which was made exclusively for previewing request bodies for Discord and provides better experience in editing them (default mode is bot mode and it has difference in embeds declaring, make sure **Webhook Mode** is enabled!), formatting/linting websites like [JSON Formatter](https://jsonformatter.org/) or [JSON Editor Online](https://jsoneditoronline.org/), etc. Although, this is not guarantee that request won't fail! 51 | * Certain fields have limit in length and content (url fields may contain only urls, otherwise request fail!), make sure you don't overflow them. 52 | 53 | 1. Click **Create Action** and then **Finish**. 54 | 2. Done! 55 | 56 | ### Troubleshooting 57 | 58 | If you suspect request failed, first check activity logs: **Applet** ➤ **Settings** ➤ **View Activity**. Ff there none errors, just messages about applet being created/updated means it wasn't triggered yet, give it some time, but if there's any please check this troubleshooting list: 59 | 60 | * `Action failure message: Rate limited by the remote server.` - means Discord rate limited this request because IFTTT sends it too frequently. Mostly happens when IFTTT tries to send requests in bulk on same webhook in short amount of time. Discord's webhook rate limit is 5 requests per 2 seconds, keep that in mind. 61 | * `Unable to make web request. Your server returned a 400.` - means request is invalid. Can be caused by: 62 | * wrong method verb (should be POST); 63 | * wrong content-type (should be application/json); 64 | * bad request body: 65 | * empty, non or invalid JSON 66 | * resulting JSON is broken (usually caused by newlines in ingredients (json doesn't support them in values) and unicode characters (rare, but happens sometimes)), can be fixed by escaping variables with <<<{{ingredient}} or unicode characters>>>; 67 | * error from server saying that one of fields hit limit (sadly, but ifttt doesn't show error that came from server). Check if json data follow limits [here](https://discord.com/developers/docs/resources/channel#embed-limits). Try replace ingredients with data from applet logs and send it through Postman, Insomnia, other REST Client. 68 | * `Error 401` - webhook url isn't full, try to copy it again. 69 | * `Error 404` - webhook you're using has been removed. Create new webhook and replace the old URL. 70 | * `Error 405` - happens when you use other than POST methods. 71 | * `There was a problem with the X service.` - and usually no data provided for this one. As it says, the problem is on service side, next check should be successful, if not - try reauthorize. 72 | 73 | ### Delay, checks and other stuff 74 | 75 | Some services provide close to realtime delay, some are up to 15 minutes, some even longer. Delay in applet description may be misleading and different for everyone, it's always better check by your own. Having multiple applets using same service may cause additional overall delay. Please bare with that as nothing much can be done. 76 | 77 | For example for Reddit you may try RSS service as Reddit supports it too (check [this](https://www.reddit.com/wiki/rss)), for Twitter/Instagram/etc. you may try services which convert to RSS feed. 78 | 79 | IFTTT doesn't have retrospective check, means posts created before applet will be ignored. **Check now** button performs force check, but for some services it may work differently and don't do any check until cooldown passes. 80 | 81 | Here's some services I made for own needs but I think others may find them useful too: 82 | 83 | * [Avatar resolver](https://avatar.glue-bot.xyz/) - some services don't provide avatars you might want be showed in webhook messages, now you can), multiple providers supported! 84 | * usage example: `{"avatar_url": "https://avatar.glue-bot.xyz/twitter/{{Username}}"}` 85 | * [discord-ifttt](https://discord-ifttt.vercel.app/) - use this if you keep receiving `Too many requests to this host` error, also applies rate limit so requests will less to fail, allows to use `text/plain` header, more info on the page! 86 | * [Multi webhook](https://multi-webhook.vercel.app/) - for times when you want to send request to multiple webhooks using one. 87 | * usage example: `URL: https://multi-webhook.vercel.app/api/multi`, `JSON: {links: [first_url, second_url], ...}` where first_url and second_url are webhook urls. 88 | -------------------------------------------------------------------------------- /docs/services/ifttt_platform.md: -------------------------------------------------------------------------------- 1 | # IFTTT Platform / Filter code 2 | 3 | [IFTTT Platform](https://platform.ifttt.com/) allows you to create and publish applets, so you can share it with the others. Also it allows to put script that will execute after applet being triggered, so you can modify output data and skip actions to custom conditions, that script is called Filter code. 4 | 5 | Filter code is written in TypeScript, but JavaScript code should work too. If you're relying on [type coercion](https://developer.mozilla.org/docs/Glossary/Type_coercion) you'll need to manually convert values to right types, code window has build-in linter, it will tell what's wrong. 6 | 7 | 👉 **Update:** Before, Filter code was exclusively IFTTT Platform feature, but now it can be used on main website too (Pro subscription required). 8 | 9 | * [JavaScript tutorial](https://learnxinyminutes.com/docs/javascript/) 10 | * [TypeScript tutorial](https://learnxinyminutes.com/docs/typescript/) 11 | 12 | * [IFTTT Platform Documentation](https://platform.ifttt.com/docs/applets) 13 | * [IFTTT Filter code cheat sheet](https://ifttt.com/explore/filter-code-cheat-sheet) 14 | 15 | ## Example 16 | 17 | ```ts 18 | // Building JSON body 19 | const body = { 20 | embeds: [{ 21 | author: { 22 | name: Trigger.UserName, // equals {{UserName}} 23 | url: Trigger.LinkToTweet // equals {{LinkToTweet}} 24 | }, 25 | description: `*${Trigger.Text}*`, // equals *{{Text}}* 26 | color: 0x1da1f2, // equals 1942002 (hex ➤ decimal value) 27 | timestamp: Meta.triggerTime // equals moment.js object but during JSON encoding will be turned to YYYY-MM-DDThh:mm:ss.msZ (discord compatible timestamp) 28 | }] 29 | }; 30 | 31 | // If you want to manually skip some triggers when some of ingredients match/not match something or allow to run only at certain time you can do this: 32 | if (Trigger.Text.indexOf('skip') > 0) { 33 | MakerWebhooks.makeWebRequest.skip('this reason will appear in activity logs!'); 34 | } 35 | 36 | // This action makes Web Request and sends webhook 37 | MakerWebhooks.makeWebRequest.setBody(JSON.stringify(body)); 38 | // Done! 39 | ``` 40 | 41 | ### TS/JS cheat sheet 42 | 43 | ```ts 44 | //== in ts/js quotes around keys can be omitted 45 | let body = {"content": "text"}; 46 | // equals 47 | let body = {content: "text"}; 48 | 49 | //== the difference between single and double quotes that you need to escape it between them own 50 | let text = ['what\'s up?', "*\"winks\"*"]; 51 | // equals 52 | let text = ["what's up?", '*"winks"*']; 53 | 54 | //== if you want to add value inside string use *template literals*: ` ` with ${} 55 | let message = 'hello, ' + name + '!'; 56 | // equals 57 | let message = `hello, ${name}!`; 58 | 59 | //== if variable is a string there's no need to use template literals 60 | let zzz = `${ccc}`; 61 | // equals 62 | let zzz = ccc; // if variable is not string but it should be call ccc.toString() on it! 63 | 64 | //== var/let/const 65 | // if value might be reassigned, use let 66 | let favoriteNumber = 42 67 | // otherwise use const 68 | const name = 'John' 69 | // using var is ok too, but less preferable 70 | var happy = true 71 | 72 | //== check if string includes substring 73 | let str = 'The quick brown fox jumps over the lazy dog'; 74 | let substr = 'fox'; 75 | let substr2 = 'cat'; 76 | let result = str.indexOf(substr) > -1; // equals true 77 | let result2 = str.indexOf(substr2) > -1; // equals false 78 | // explanation: IFTTT doesn't have str.includes(substr) method available 79 | // so we have to use str.indexOf(substr) > -1 instead, 80 | // which returns coordinates of substring and -1 if not found. 81 | // > -1 is in range [0..+inf), >= 0 will work the same way 82 | 83 | //== random value 84 | let random = Math.random(); // returns float value in range [0..1) (1 excluded) 85 | let random2 = Math.round(Math.random()); // returns 0 or 1 86 | let random3 = Math.floor(Math.random() * 10); // returns integer value in range [0..9] (10 excluded) 87 | let random4 = 5 + Math.floor(Math.random() * 45); // returns integer value in range [5..49] (50 excluded) 88 | 89 | //== random element in array 90 | let arr = ['one', 'two', 'three', 'four']; 91 | let picked = arr[Math.floor(Math.random() * arr.length)]; 92 | ``` 93 | 94 | ### Useful snippets 95 | 96 | ```ts 97 | // check if str is part of substr, optionally comparing them case-insensitively 98 | function includes(str: string, substr: string, caseInsensitive?: boolean): boolean { 99 | if (caseInsensitive) { 100 | str = str.toLowerCase(); 101 | substr = substr.toLowerCase(); 102 | } 103 | return str.indexOf(substr) > -1; 104 | } 105 | 106 | includes('watermelon', 'melon') // returns true 107 | includes('Watermelon', 'Melon') // returns false 108 | includes('Watermelon', 'Melon', true) // returns true 109 | 110 | // random integer number between min and max 111 | function random(min: number, max: number): number { 112 | return min + Math.floor(Math.random() * (max - min + 1)); 113 | } 114 | 115 | random(5, 10) // returns value between 5 and 10 116 | random(-5, 5) // returns value between -5 and 5 117 | 118 | // select random element of array 119 | function pick(arr: T[]): T { 120 | return arr[Math.floor(Math.random() * arr.length)]; 121 | } 122 | 123 | pick(['apple', 'banana', 'orange']) 124 | ``` 125 | -------------------------------------------------------------------------------- /docs/structure/allowed_mentions.md: -------------------------------------------------------------------------------- 1 | # allowed_mentions 2 | 3 | Allows to suppress pings by users, roles or everyone/here mentions. `allowed_mentions` object and can contain next parameters: 4 | 5 | * `parse` - array and can include next values: 6 | * "everyone" - if present everyone/here will ping. 7 | * "users" - if present user mentions will ping. 8 | * "roles" - if present role mentions will ping. 9 | * `users` - array with id of users, allows to limit which users may be pinged. 10 | * `roles` - array with id of roles, allows to limit which roles may be pinged. 11 | 12 | Don't include `users` and `roles` both in `allowed_mentions` and `parse`, , if you want 13 | 14 | Here's some examples: 15 | 16 | * nobody will be pinged by this message. 17 | 18 | ```json 19 | { 20 | "content": "@everyone <@&role-id> <@user-id>", 21 | "allowed_mentions": { "parse": [] } 22 | } 23 | ``` 24 | 25 | * only users that didn't suppress everyone/here mentions will be pinged. 26 | 27 | ```json 28 | { 29 | "content": "@everyone <@&role-id> <@user-id>", 30 | "allowed_mentions": { "parse": ["everyone"] } 31 | } 32 | ``` 33 | 34 | * only user with `user-id` will be pinged, in this case `@everyone` won't ping anyone. `user2` mention is not in content so no ping for them. 35 | 36 | ```json 37 | { 38 | "content": "@everyone <@&role-id> <@user-id>", 39 | "allowed_mentions": { "users": ["user-id", "user2-id"] } 40 | } 41 | ``` 42 | 43 | * similar for roles. 44 | 45 | ```json 46 | { 47 | "content": "@everyone <@&role-id> <@user-id>", 48 | "allowed_mentions": { "roles": ["role-id"] } 49 | } 50 | ``` 51 | 52 | * Will ping everyone with disabled everyone/here mention suppress, all users mentioned in message (i. e. `user-id` user) or with `role-id` role (unless enabled role mention suppress). 53 | 54 | ```json 55 | { 56 | "content": "@everyone <@&role-id> <@user-id>", 57 | "allowed_mentions": { 58 | "parse": ["everyone", "users"], 59 | "roles": ["role-id"] 60 | } 61 | } 62 | ``` 63 | 64 | [Discord API reference](https://discord.com/developers/docs/resources/channel#allowed-mentions-object) 65 | -------------------------------------------------------------------------------- /docs/structure/avatar_url.md: -------------------------------------------------------------------------------- 1 | # avatar_url 2 | 3 | Overrides webhook's avatar. Useful, if you're using the same Webhook URL for several things. 4 | 5 | Example: 6 | 7 | ```json 8 | { 9 | "avatar_url": "https://i.imgur.com/oBPXx0D.png", 10 | "content": "Woof-woof!" 11 | } 12 | ``` 13 | 14 | ![avatar url example](../img/structure/avatar_url.png) 15 | -------------------------------------------------------------------------------- /docs/structure/content.md: -------------------------------------------------------------------------------- 1 | # content 2 | 3 | Sets content for message sent by webhook. 4 | 5 | Example: 6 | 7 | ```json 8 | { 9 | "content": "*reads manual*" 10 | } 11 | ``` 12 | 13 | ![content example](../img/structure/content.png) 14 | -------------------------------------------------------------------------------- /docs/structure/embed/author.md: -------------------------------------------------------------------------------- 1 | # author 2 | 3 | Adds Author block to embed. `author` is an object which includes three values: 4 | 5 | * `name` - sets name. 6 | * `url` - sets link. Requires `name` value. If used, transforms `name` into hyperlink. 7 | * `icon_url` - sets avatar. Requires `name` value. 8 | 9 | Example: 10 | 11 | ```json 12 | { 13 | "embeds": [{ 14 | "author": { 15 | "name": "Delivery Girl", 16 | "url": "https://www.reddit.com/r/Pizza/", 17 | "icon_url": "https://i.imgur.com/V8ZjaMa.jpg" 18 | }, 19 | "description": "Your pizza is ready!\n:timer:ETA: 10 minutes." 20 | }] 21 | } 22 | ``` 23 | 24 | ![author example](../../img/structure/embed/author.png) 25 | -------------------------------------------------------------------------------- /docs/structure/embed/color.md: -------------------------------------------------------------------------------- 1 | # color 2 | 3 | Sets color for webhook's embed. It equals 0 (transparent) by default. Color requires number instead hex code, so you have to convert hexadecimal color code to decimal number. Color can be defined as number `65280` and as string `"65280"`. 4 | 5 | I recommend to use [SpyColor](https://www.spycolor.com/) for color picking, it provides decimal value. 6 | 7 | Example: 8 | 9 | ```json 10 | { 11 | "embeds": [ 12 | { 13 | "title": "Meow!", 14 | "color": 1127128 15 | }, 16 | { 17 | "title": "Meow-meow!", 18 | "color": "14177041" 19 | } 20 | ] 21 | } 22 | ``` 23 | 24 | ![color example](../../img/structure/embed/color.png) 25 | -------------------------------------------------------------------------------- /docs/structure/embed/description.md: -------------------------------------------------------------------------------- 1 | # description 2 | 3 | Sets description for webhook's embed. 4 | 5 | Example: 6 | 7 | ```json 8 | { 9 | "embeds": [{ 10 | "description": "*Hi!* **Wow!** I can __use__ hyperlinks [here](https://discord.com)." 11 | }] 12 | } 13 | ``` 14 | 15 | ![description example](../../img/structure/embed/description.png) 16 | -------------------------------------------------------------------------------- /docs/structure/embed/fields.md: -------------------------------------------------------------------------------- 1 | # fields 2 | 3 | Allows you to use multiple `title + description` blocks in embed. `fields` is an array of `field` objects. Each object includes three values: 4 | 5 | * `name` - sets name for field object. Required; 6 | * `value` - sets description for field object. Required; 7 | * `inline` - if `true` then sets field objects in same line, **but** if you have more than 3 objects with enabled `inline` or just too long you will get rows with 3 fields in each one or with 2 fields if you used `thumbnail` object. `false` by default. Optional. 8 | 9 | P.S. You can use up to 25 fields in same embed. `name` and `value` support [Discord Markdown](/markdown.md). 10 | 11 | Example: 12 | 13 | ```json 14 | { 15 | "embeds": [{ 16 | "fields": [ 17 | { 18 | "name": "Cat", 19 | "value": "Hi! :wave:", 20 | "inline": true 21 | }, 22 | { 23 | "name": "Dog", 24 | "value": "hello!", 25 | "inline": true 26 | }, 27 | { 28 | "name": "Cat", 29 | "value": "wanna play? join to voice channel!" 30 | }, 31 | { 32 | "name": "Dog", 33 | "value": "yay" 34 | } 35 | ] 36 | }] 37 | } 38 | ``` 39 | 40 | ![fields example](../../img/structure/embed/fields.png) 41 | -------------------------------------------------------------------------------- /docs/structure/embed/footer.md: -------------------------------------------------------------------------------- 1 | # footer 2 | 3 | Allows you to add footer to embed. `footer` is an object which includes two values: 4 | 5 | * `text` - sets name for author object. Markdown is disabled here!!! 6 | * `icon_url` - sets icon for author object. Requires `text` value. 7 | 8 | Example: 9 | 10 | ```json 11 | { 12 | "embeds": [{ 13 | "footer": { 14 | "text": "Woah! *So cool!* :smirk:", 15 | "icon_url": "https://i.imgur.com/fKL31aD.jpg" 16 | }, 17 | "description": "Your pizza is ready!\n:timer:ETA: 10 minutes." 18 | }] 19 | } 20 | ``` 21 | 22 | ![footer example](../../img/structure/embed/footer.png) 23 | -------------------------------------------------------------------------------- /docs/structure/embed/image.md: -------------------------------------------------------------------------------- 1 | # image 2 | 3 | Allows you to add image to the embed. Currently, there is no way to set width/height of the image. 4 | `url` value must be valid url that starts with `http(s)://` or `attachment://`, more info about the latter one can be found on the [file](../file.md#embedding-attachments) page. 5 | 6 | Example: 7 | 8 | ```json 9 | { 10 | "embeds": [{ 11 | "image": { 12 | "url": "https://i.imgur.com/ZGPxFN2.jpg" 13 | } 14 | }] 15 | } 16 | ``` 17 | 18 | ![image](../../img/structure/embed/image.png) 19 | -------------------------------------------------------------------------------- /docs/structure/embed/thumbnail.md: -------------------------------------------------------------------------------- 1 | # thumbnail 2 | 3 | Allows you to add thumbnail to the embed. Currently, there is no way to set width/height of the thumbnail. 4 | `url` value must be valid url that starts with `http(s)://` or `attachment://`, more info about the latter one can be found on the [file](../file.md#embedding-attachments) page. 5 | 6 | Example: 7 | 8 | ```json 9 | { 10 | "embeds": [{ 11 | "thumbnail": { 12 | "url": "https://upload.wikimedia.org/wikipedia/commons/3/38/4-Nature-Wallpapers-2014-1_ukaavUI.jpg" 13 | } 14 | }] 15 | } 16 | ``` 17 | 18 | ![thumbnail example](../../img/structure/embed/thumbnail.png) 19 | -------------------------------------------------------------------------------- /docs/structure/embed/timestamp.md: -------------------------------------------------------------------------------- 1 | # timestamp 2 | 3 | Allows you to add `timestamp` to embed. Time stores as String in the next format: `"YYYY-MM-DDTHH:MM:SS.MSSZ"`. If `footer` was used they will be separated with a bullet (•). Also, this is special field, because it can show different time based on user's device. 4 | 5 | P.S. Timestamp is not just text. This is formatted UTC time and date. It will show different time because timezones. Look on example below: I set 12pm but it shows 2pm because UTC+2 timezone. 6 | 7 | Example: 8 | 9 | ```json 10 | { 11 | "embeds": [{ 12 | "description": "Time travel!", 13 | "timestamp": "2015-12-31T12:00:00.000Z" 14 | }] 15 | } 16 | ``` 17 | 18 | ![timestamp example](../../img/structure/embed/timestamp.png) 19 | -------------------------------------------------------------------------------- /docs/structure/embed/title.md: -------------------------------------------------------------------------------- 1 | # title 2 | 3 | Sets title for webhook's embed. 4 | 5 | Example: 6 | 7 | ```json 8 | { 9 | "embeds": [{ 10 | "title": "Meow!" 11 | }] 12 | } 13 | ``` 14 | 15 | ![title example](../../img/structure/embed/title.png) 16 | -------------------------------------------------------------------------------- /docs/structure/embed/url.md: -------------------------------------------------------------------------------- 1 | # url 2 | 3 | Sets link for title in your webhook message. Requires `title` variable and turns it into hyperlink. 4 | 5 | Example: 6 | 7 | ```json 8 | { 9 | "embeds": [{ 10 | "title": "Google it!", 11 | "url": "https://google.com/" 12 | }] 13 | } 14 | ``` 15 | 16 | ![url example](../../img/structure/embed/url.png) 17 | -------------------------------------------------------------------------------- /docs/structure/embeds.md: -------------------------------------------------------------------------------- 1 | # embeds 2 | 3 | Sets custom embeds for message sent by webhook. `embeds` is an array of embeds and can contain up to 10 embeds in the same message. 4 | 5 | Examples: 6 | 7 | ```json 8 | { 9 | "embeds": [{ 10 | "title": "Hello!", 11 | "description": "Hi! :grinning:" 12 | }] 13 | } 14 | ``` 15 | 16 | ![embeds example](../img/structure/embeds.png) 17 | 18 | ```json 19 | { 20 | "embeds": [ 21 | { 22 | "title": "Meow!", 23 | "color": 1127128 24 | }, 25 | { 26 | "title": "Meow-meow!", 27 | "color": 14177041 28 | } 29 | ] 30 | } 31 | ``` 32 | 33 | ![embeds example](../img/structure/embeds_2.png) 34 | 35 | ## P.S. 36 | 37 | Adding embeds overrides url embeds. 38 | -------------------------------------------------------------------------------- /docs/structure/file.md: -------------------------------------------------------------------------------- 1 | # file 2 | 3 | Sending files using webhooks is only possible using `Content-Type: multipart/form-data` header. 4 | Using this method also means you have to set json body as value of `payload_json` parameter. 5 | 6 | Parameter names should have unique names otherwise they will collide and only first file from ones with identical names will be shown. 7 | 8 | Example: 9 | 10 | ```sh 11 | file1=@cat.jpg 12 | file2=@dog.jpg 13 | payload_json={"embeds":[{"title":"test"}]} 14 | ``` 15 | 16 | ![result example](../img/structure/file.png) 17 | 18 | ## Embedding attachments 19 | 20 | To put image attachment inside embed use `attachment://` with its filename (not field name). 21 | That will also hide attachment from the message. 22 | 23 | ```sh 24 | file1=@pizza.jpg 25 | payload_json={"embeds":[{"image":{"url":"attachment://pizza.jpg"}}]} 26 | ``` 27 | 28 | ![result example](../img/structure/file_2.png) 29 | 30 | ## How to send attachments using various tools explained on respective pages: 31 | 32 | * [curl](../tools/curl.md#sending-attachments) 33 | * [HTTPie](../tools/httpie.md#sending-attachments) 34 | * [Insomnia](../tools/insomnia.md#sending-attachments) 35 | * [Postman](../tools/postman.md#sending-attachments) 36 | * [Python](../tools/python.md#sending-attachments) 37 | -------------------------------------------------------------------------------- /docs/structure/poll.md: -------------------------------------------------------------------------------- 1 | # poll 2 | 3 | Allows to add poll to message. Poll always has a question (up to 300 characters) with at least 1 answer (up to 10 options total, up to 55 characters per each). Poll duration can be set to value between 1 and 768 hours (32 days), if omitted 24 hours are assumed. Additionally, multiple answers mode is available, but there's no way to limit how many can be selected at time when it's enabled. 4 | 5 | Structure can be a bit confusing at first, let's break it down: 6 | 7 | * `poll` - poll object 8 | * `question` - poll question object 9 | * `text` - poll question text value, up to 300 characters 10 | * `answers` - array of poll answer objects, up to 10 options can be specified, at least 1 is required 11 | * `poll_media` - poll answer object 12 | * `text` - poll answer text 13 | * `emoji` - emoji object, optional 14 | * `id` - id of emoji, should be provided as string, used when emoji is custom 15 | * `name` - name of emoji, should be written as Unicode character, used when emoji is built-in 16 | * `duration` - duration of the poll in hours (1-768), default is 24 hours 17 | * `allow_multiselect` - if true, allows to select multiple answers, optional, default is false 18 | 19 | Example: 20 | 21 | ```json 22 | { 23 | "poll": { 24 | "question": { 25 | "text": "Cat person or dog person?" 26 | }, 27 | "answers": [ 28 | { 29 | "poll_media": { 30 | "text": "meow!", 31 | "emoji": { 32 | "id": "1365720705324421202" 33 | } 34 | } 35 | }, 36 | { 37 | "poll_media": { 38 | "text": "woof!", 39 | "emoji": { 40 | "name": "🐶" 41 | } 42 | } 43 | } 44 | ], 45 | "allow_multiselect": true, 46 | "duration": 48 47 | } 48 | } 49 | ``` 50 | 51 | ![poll example](../img/structure/poll.png) 52 | 53 | ## Additional information 54 | 55 | By adding `wait=true` to the request query, you can get a response with the message structure, that will include all kind of data about message, including Message ID. Later on it can be used to get poll results using [Get Webhook Message](https://discord.com/developers/docs/resources/webhook#get-webhook-message) request, it allows to see number of votes, but not voters. Additionally there's no way to close poll as it's possible for users and bots (both can only close own polls only). 56 | 57 | [Discord API reference](https://discord.com/developers/docs/resources/poll#poll-create-request-object) 58 | -------------------------------------------------------------------------------- /docs/structure/tts.md: -------------------------------------------------------------------------------- 1 | # tts 2 | 3 | Enables text-to-speech for current message, so everyone who have tts enabled with hear it. 4 | 5 | Example: 6 | 7 | ```json 8 | { 9 | "content": "Hi", 10 | "tts": true 11 | } 12 | ``` 13 | -------------------------------------------------------------------------------- /docs/structure/username.md: -------------------------------------------------------------------------------- 1 | # username 2 | 3 | Overrides webhook's username. Useful, if you're using the same Webhook URL for several things. 4 | 5 | Example: 6 | 7 | ```json 8 | { 9 | "username": "Cat", 10 | "content": "Hello!" 11 | } 12 | ``` 13 | 14 | ![username example](../img/structure/username.png) 15 | -------------------------------------------------------------------------------- /docs/tools/curl.md: -------------------------------------------------------------------------------- 1 | # curl 2 | 3 | [curl](https://curl.se/) - command line tool for sending web requests. 4 | 5 | * [Windows] - preinstalled on Windows 10+, newer version can be installed with [Scoop](https://scoop.sh/) or [Chocolatey](https://chocolatey.org/). 6 | * [Linux] - can be installed with built-in package manager or [Homebrew](https://brew.sh/). 7 | * [macOS] - preinstalled, newer version can be installed with [Homebrew](https://brew.sh/) or [MacPorts](https://www.macports.org/). 8 | 9 | Also, you can download executable from their website and run it from a directory or make it discoverable through `PATH`, 10 | so it can be run from anywhere. Using a package manager is preferable as it simplifies the process of installing and updating the tool. 11 | 12 | ## Usage 13 | 14 | `curl -H "Content-Type: application/json" -d ` 15 | 16 | ### Bash/Zsh/etc. 17 | 18 | ```sh 19 | # Usually, request also includes `-X POST` to set request verb to POST, but using `-d` does that automatically. 20 | # -H "Content-Type: application/json" - adds header that tells server you're sending JSON data. 21 | # -d '{"username": "test", "content": "hello"}' - sets request data. 22 | curl -H "Content-Type: application/json" -d '{"username": "test", "content": "hello"}' "https://discord.com/api/webhooks/123/w3bh00k_t0k3n" 23 | 24 | # To make command more readable you can split it to multiple lines using backslash `\` 25 | # and/or set webhook url and body as variables. 26 | WEBHOOK_URL="https://discord.com/api/webhooks/123/w3bh00k_t0k3n" 27 | BODY='{"username": "test", "content": "hello"}' 28 | curl \ 29 | -H "Content-Type: application/json" \ 30 | -d $BODY \ 31 | $WEBHOOK_URL 32 | ``` 33 | 34 | ### PowerShell 35 | 36 | Note: Preinstalled PowerShell (<5.1) comes with `curl` command that's actually alias to `Invoke-WebRequest` when actual curl can be accessed with `curl.exe`. This collision has been resolved in PowerShell Core 6+. If you're unsure which version you're using run this command: 37 | 38 | ```ps1 39 | $PSVersionTable.PSVersion.ToString() 40 | ``` 41 | 42 | #### 5.1 and below (powershell.exe) 43 | 44 | ```ps1 45 | # In older version you have to escape " with \ inside strings, so body string be parsed correctly. 46 | curl.exe -H "Content-Type: application/json" -d '{\"username\": \"test\", \"content\": \"hello\"}' "https://discord.com/api/webhooks/123/w3bh00k_t0k3n" 47 | 48 | # To improve rediability you can split command with ` 49 | # and set webhook url and body to variables 50 | $WEBHOOK_URL = "https://discord.com/api/webhooks/123/w3bh00k_t0k3n" 51 | $BODY = '{\"username\": \"test\", \"content\": \"hello\"}' 52 | # Alternatively, we can use PowerShell hashtables with the ConvertTo-Json function 53 | $BODY = @{ username = "test"; content = "hello" } | ConvertTo-Json 54 | curl.exe ` 55 | -H "Content-Type: application/json" ` 56 | -d $BODY ` 57 | $WEBHOOK_URL 58 | ``` 59 | 60 | #### Core / 6 and above (pwsh.exe) 61 | 62 | ```ps1 63 | $WEBHOOK_URL = "https://discord.com/api/webhooks/123/w3bh00k_t0k3n" 64 | # In newer versions escaping \ with " is no longer necessary (and makes JSON invalid) 65 | $BODY = '{"username": "test", "content": "hello"}' 66 | # Alternatively, we can use PowerShell hashtables with the ConvertTo-Json function 67 | $BODY = @{ username = "test"; content = "hello" } | ConvertTo-Json 68 | curl.exe -H "Content-Type: application/json" -d $BODY $WEBHOOK_URL 69 | ``` 70 | 71 | ### Command Prompt (cmd.exe) 72 | 73 | Note: Unlike PowerShell, both `curl` and `curl.exe` point to the same binary. 74 | 75 | ```bat 76 | REM ^ is multiline splitter in cmd. 77 | curl ^ 78 | -H "Content-Type: application/json" ^ 79 | -d "{\"username\": \"test\", \"content\": \"hello\"}" ^ 80 | https://discord.com/api/webhooks/123/w3bh00k_t0k3n 81 | 82 | REM Notice double quotes around body and none around link. 83 | SET WEBHOOK_URL=https://discord.com/api/webhooks/123/w3bh00k_t0k3n 84 | SET BODY="{\"username\": \"test\", \"content\":\"hello\"}" 85 | curl -H "Content-Type: application/json" -d %BODY% %WEBHOOK_URL% 86 | ``` 87 | 88 | ## Sending attachments 89 | 90 | ```sh 91 | # Adding `-H "Content-Type: multipart/form-data"` is not required as `-F` sets it automatically. 92 | # -F 'payload_json={}' - when sending files JSON can provided with this field. 93 | # -F "file1=@cat.jpg" - adds cat.jpg file as attachment. 94 | # -F "file2=@images/dog.jpg" - adds dog.jpg file from images directory. 95 | curl \ 96 | -F 'payload_json={"username": "test", "content": "hello"}' \ 97 | -F "file1=@cat.jpg" \ 98 | -F "file2=@images/dog.jpg" \ 99 | $WEBHOOK_URL 100 | ``` 101 | 102 | [Windows]: https://curl.se/windows/microsoft.html 103 | [Linux]: https://everything.curl.dev/install/linux.html 104 | [macOS]: https://everything.curl.dev/install/macos.html 105 | -------------------------------------------------------------------------------- /docs/tools/httpie.md: -------------------------------------------------------------------------------- 1 | # HTTPie 2 | 3 | [HTTPie](https://httpie.io/) is a command line HTTP client, just like [curl](curl.md) but more user friendly. 4 | 5 | * Windows - can be installed with `pip` (requires Python 3.x installed). By the way, this is cross-platform solution. 6 | * Linux - can be installed with built-in package manager or [Homebrew](https://brew.sh/). 7 | * macOS - can be installed with [Homebrew](https://brew.sh/) or [MacPorts](https://www.macports.org/). 8 | 9 | Check [docs](https://httpie.io/docs/cli/installation) for installation details. 10 | 11 | ## Usage 12 | 13 | `http ` 14 | 15 | ### for Bash/Zsh/etc. 16 | 17 | ```sh 18 | # Optional flags and method were omitted: 19 | # if unspecified method is set to POST if body is specified 20 | # -j/--json forces JSON mode, yet it's default behavior 21 | http "https://discord.com/api/webhooks/123/w3bh00k_t0k3n" content="test" embeds[0][title]="text" 22 | ``` 23 | 24 | Depends on type of value you have to use different separators: 25 | 26 | * `=` - text. 27 | * `:=` - raw JSON value. Use it for array, number, boolean and nested values. 28 | * `@` - embed file. 29 | * `=@` - embed json file. 30 | 31 | ```sh 32 | http \ 33 | "https://discord.com/api/webhooks/123/w3bh00k_t0k3n" \ 34 | content="test" \ 35 | embeds[0][title]="text" 36 | ``` 37 | 38 | Also, if you don't want to mess with these and would like to just pass raw body, like can be done in `curl`, use the next approach: 39 | 40 | ```sh 41 | echo -n '{"content": "test", "embeds": [{"title": "text"}]}' | http "https://discord.com/api/webhooks/123/w3bh00k_t0k3n" 42 | ``` 43 | 44 | ### PowerShell 45 | 46 | ```ps1 47 | $WEBHOOK_URL = "https://discord.com/api/webhooks/123/w3bh00k_t0k3n" 48 | http $WEBHOOK_URL content="test" embeds[0][title]="text" 49 | # Also you can just pass raw json body: 50 | '{"content": "test", "embeds": [{"title": "text"}]}' | http $WEBHOOK_URL 51 | ``` 52 | 53 | ### Command Prompt (cmd.exe) 54 | 55 | ```bat 56 | REM Notice escaped double quotes around values and none around link 57 | SET WEBHOOK_URL=https://discord.com/api/webhooks/123/w3bh00k_t0k3n 58 | http %WEBHOOK_URL% content="test" embeds[0][title]="text" 59 | 60 | REM Outer quotes are skipped due to cmd parsing 61 | echo {"content": "test", "embeds": [{"title": "text"}]} | http %WEBHOOK_URL% 62 | ``` 63 | 64 | ## Sending attachments 65 | 66 | ```sh 67 | # -f flag sets "Content-Type: multipart/form-data" header. 68 | # payload_json='{}' - when sending files json can provided with this field. 69 | # file1@cat.jpg - adds cat.jpg file as attachment. 70 | # file2@images/dog.jpg - adds dog.jpg file from images directory. 71 | http -f $WEBHOOK_URL \ 72 | payload_json='{"content": "test", "embeds": [{"title": "text"}]}' \ 73 | file1@cat.jpg \ 74 | file2@images/dog.jpg 75 | ``` 76 | -------------------------------------------------------------------------------- /docs/tools/insomnia.md: -------------------------------------------------------------------------------- 1 | # Insomnia 2 | 3 | [Insomnia](https://insomnia.rest/download) is a GUI tool similar to Postman for sending web requests. 4 | 5 | Download it from official website. Available for Windows, Linux, and macOS. 6 | 7 | Here's how to use it: 8 | 9 | 1. Click `+` on the left, choose `New Request`, in dialog window press `Create`. 10 | 2. Click on dropdown in front of URL field and choose `POST`. 11 | 3. Paste Webhook URL in URL field. 12 | 4. Click `Body` dropdown, choose `JSON`. 13 | 5. Paste the body below. 14 | 6. Press `Send`. 15 | 7. If status shows `204 No Content` means request succeed! 16 | 17 | ![Insomnia example](../img/other/insomnia.png) 18 | 19 | ## Sending attachments 20 | 21 | To send attachment(s): 22 | 23 | 1. Switch `Body` format from `JSON` to `Multipart Form`. 24 | 2. Click on arrow icon, choose `File`. 25 | 3. Click `Choose File` and select file. 26 | 4. Repeat if you want to add more attachments. 27 | 5. To add json to request add key with `payload_json` name and json body value (both `Text` and `Text (Multi-line)` are fine). 28 | 29 | ![Insomnia example](../img/other/insomnia_2.png) 30 | -------------------------------------------------------------------------------- /docs/tools/postman.md: -------------------------------------------------------------------------------- 1 | # Postman 2 | 3 | [Postman](https://www.postman.com/downloads/) is a GUI tool for sending web requests. 4 | 5 | Download it from official website. Available for Windows, Linux, and macOS. 6 | 7 | Here's how to use it: 8 | 9 | 1. Click `+` on the tabs panel. 10 | 2. Click on dropdown in front of URL field and choose `POST`. 11 | 3. Paste Webhook URL in URL field. 12 | 4. Click `Body` tab > `raw` > `JSON` from the dropdown. 13 | 5. Paste the body below. 14 | 6. Press `Send`. 15 | 7. If status shows `204 No Content` means request succeed! 16 | 17 | ![postman example](../img/other/postman.png) 18 | 19 | ## Sending attachments 20 | 21 | To send attachment(s): 22 | 23 | 1. Switch from `raw` to `form-data`. 24 | 2. Hover on key field, click on dropdown and choose `File`. 25 | 3. Click `Select Files` and select file (despite it allowing you to choose multiple files, choose one). 26 | 4. Repeat if you want to add more attachments. 27 | 5. To add json to request add key with `payload_json` name and json body value (dropdown must say `Text`). 28 | 29 | ![postman example](../img/other/postman_2.png) 30 | -------------------------------------------------------------------------------- /docs/tools/python.md: -------------------------------------------------------------------------------- 1 | # Python 2 | 3 | [Python](https://python.org) has many HTTP libraries that are able to generate webhook requests. While there's no way to list all of them, here are some examples you can try. 4 | 5 | ## httpx 6 | 7 | The [httpx](https://www.python-httpx.org/) client library can be used to submit both simple and more complex webhooks. 8 | 9 | ### Send a payload as json 10 | 11 | ```python 12 | import httpx 13 | 14 | response = httpx.post( 15 | "https://discord.com/api/webhooks/123/w3bh00k_t0k3n", 16 | json={ 17 | "username": "Captain Hook", 18 | "content": "Ahoy matey! I be a webhook message!", 19 | # you can add embeds here, too 20 | } 21 | ) 22 | # raise an exception if the operation failed. 23 | response.raise_for_status() 24 | ``` 25 | 26 | ### Sending Attachments 27 | 28 | ```python 29 | import json 30 | import httpx 31 | 32 | with open("image.png", "rb") as io_object: 33 | response = httpx.post( 34 | "https://discord.com/api/webhooks/123/w3bh00k_t0k3n", 35 | data={"payload_json": json.dumps({ 36 | "embeds": [{ 37 | "title": "Hello, world!", 38 | "description": "This is a message with an image", 39 | "image": {"url": "attachment://filename"} 40 | }] 41 | })}, 42 | files={"filetag": ("filename", io_object, "image/png")} 43 | ) 44 | # raise an exception if the operation failed. 45 | response.raise_for_status() 46 | ``` 47 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "discord-webhooks-guide", 3 | "version": "1.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "dependencies": { 7 | "csso-cli": "^4.0.2", 8 | "highlight.js": "github:highlightjs/highlight.js#11-stable", 9 | "html-minifier": "^4.0.0", 10 | "svgo": "~3.1.0", 11 | "terser": "^5.39.0" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | dependencies: 11 | csso-cli: 12 | specifier: ^4.0.2 13 | version: 4.0.2 14 | highlight.js: 15 | specifier: github:highlightjs/highlight.js#11-stable 16 | version: https://codeload.github.com/highlightjs/highlight.js/tar.gz/2a972d86589f65f4e79f67a02c3bf389a187afa0 17 | html-minifier: 18 | specifier: ^4.0.0 19 | version: 4.0.0 20 | svgo: 21 | specifier: ~3.1.0 22 | version: 3.1.0 23 | terser: 24 | specifier: ^5.39.0 25 | version: 5.39.0 26 | 27 | packages: 28 | 29 | '@jridgewell/gen-mapping@0.3.8': 30 | resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} 31 | engines: {node: '>=6.0.0'} 32 | 33 | '@jridgewell/resolve-uri@3.1.2': 34 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 35 | engines: {node: '>=6.0.0'} 36 | 37 | '@jridgewell/set-array@1.2.1': 38 | resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} 39 | engines: {node: '>=6.0.0'} 40 | 41 | '@jridgewell/source-map@0.3.6': 42 | resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} 43 | 44 | '@jridgewell/sourcemap-codec@1.5.0': 45 | resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} 46 | 47 | '@jridgewell/trace-mapping@0.3.25': 48 | resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} 49 | 50 | '@trysound/sax@0.2.0': 51 | resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} 52 | engines: {node: '>=10.13.0'} 53 | 54 | acorn@8.14.1: 55 | resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==} 56 | engines: {node: '>=0.4.0'} 57 | hasBin: true 58 | 59 | ansi-colors@4.1.3: 60 | resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} 61 | engines: {node: '>=6'} 62 | 63 | anymatch@3.1.3: 64 | resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} 65 | engines: {node: '>= 8'} 66 | 67 | binary-extensions@2.3.0: 68 | resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} 69 | engines: {node: '>=8'} 70 | 71 | boolbase@1.0.0: 72 | resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} 73 | 74 | braces@3.0.3: 75 | resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} 76 | engines: {node: '>=8'} 77 | 78 | buffer-from@1.1.2: 79 | resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} 80 | 81 | camel-case@3.0.0: 82 | resolution: {integrity: sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==} 83 | 84 | chokidar@3.6.0: 85 | resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} 86 | engines: {node: '>= 8.10.0'} 87 | 88 | clap@3.1.1: 89 | resolution: {integrity: sha512-vp42956Ax06WwaaheYEqEOgXZ3VKJxgccZ0gJL0HpyiupkIS9RVJFo5eDU1BPeQAOqz+cclndZg4DCqG1sJReQ==} 90 | engines: {node: ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} 91 | 92 | clean-css@4.2.4: 93 | resolution: {integrity: sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==} 94 | engines: {node: '>= 4.0'} 95 | 96 | commander@2.20.3: 97 | resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} 98 | 99 | commander@7.2.0: 100 | resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} 101 | engines: {node: '>= 10'} 102 | 103 | css-select@5.1.0: 104 | resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} 105 | 106 | css-tree@2.2.1: 107 | resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} 108 | engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} 109 | 110 | css-tree@2.3.1: 111 | resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} 112 | engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} 113 | 114 | css-what@6.1.0: 115 | resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} 116 | engines: {node: '>= 6'} 117 | 118 | csso-cli@4.0.2: 119 | resolution: {integrity: sha512-p/VipA45w8EmS8Lv6wGtE+UdsbFlqUBGhL9FCTGKxd5dC07mtg3BbZaMzMh0X+oIl2JUGR/mPx5YzuNnTM2a3w==} 120 | engines: {node: '>=12.20.0'} 121 | hasBin: true 122 | 123 | csso@5.0.5: 124 | resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} 125 | engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} 126 | 127 | dom-serializer@2.0.0: 128 | resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} 129 | 130 | domelementtype@2.3.0: 131 | resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} 132 | 133 | domhandler@5.0.3: 134 | resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} 135 | engines: {node: '>= 4'} 136 | 137 | domutils@3.2.2: 138 | resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} 139 | 140 | entities@4.5.0: 141 | resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} 142 | engines: {node: '>=0.12'} 143 | 144 | fill-range@7.1.1: 145 | resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} 146 | engines: {node: '>=8'} 147 | 148 | fsevents@2.3.3: 149 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 150 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 151 | os: [darwin] 152 | 153 | glob-parent@5.1.2: 154 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 155 | engines: {node: '>= 6'} 156 | 157 | he@1.2.0: 158 | resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} 159 | hasBin: true 160 | 161 | highlight.js@https://codeload.github.com/highlightjs/highlight.js/tar.gz/2a972d86589f65f4e79f67a02c3bf389a187afa0: 162 | resolution: {tarball: https://codeload.github.com/highlightjs/highlight.js/tar.gz/2a972d86589f65f4e79f67a02c3bf389a187afa0} 163 | version: 11.3.1 164 | engines: {node: '>=12.0.0'} 165 | 166 | html-minifier@4.0.0: 167 | resolution: {integrity: sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==} 168 | engines: {node: '>=6'} 169 | hasBin: true 170 | 171 | is-binary-path@2.1.0: 172 | resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} 173 | engines: {node: '>=8'} 174 | 175 | is-extglob@2.1.1: 176 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 177 | engines: {node: '>=0.10.0'} 178 | 179 | is-glob@4.0.3: 180 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 181 | engines: {node: '>=0.10.0'} 182 | 183 | is-number@7.0.0: 184 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 185 | engines: {node: '>=0.12.0'} 186 | 187 | lower-case@1.1.4: 188 | resolution: {integrity: sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==} 189 | 190 | mdn-data@2.0.28: 191 | resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} 192 | 193 | mdn-data@2.0.30: 194 | resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} 195 | 196 | no-case@2.3.2: 197 | resolution: {integrity: sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==} 198 | 199 | normalize-path@3.0.0: 200 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} 201 | engines: {node: '>=0.10.0'} 202 | 203 | nth-check@2.1.1: 204 | resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} 205 | 206 | param-case@2.1.1: 207 | resolution: {integrity: sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==} 208 | 209 | picocolors@1.1.1: 210 | resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 211 | 212 | picomatch@2.3.1: 213 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 214 | engines: {node: '>=8.6'} 215 | 216 | readdirp@3.6.0: 217 | resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} 218 | engines: {node: '>=8.10.0'} 219 | 220 | relateurl@0.2.7: 221 | resolution: {integrity: sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==} 222 | engines: {node: '>= 0.10'} 223 | 224 | source-map-js@1.2.1: 225 | resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 226 | engines: {node: '>=0.10.0'} 227 | 228 | source-map-support@0.5.21: 229 | resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} 230 | 231 | source-map@0.6.1: 232 | resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} 233 | engines: {node: '>=0.10.0'} 234 | 235 | svgo@3.1.0: 236 | resolution: {integrity: sha512-R5SnNA89w1dYgNv570591F66v34b3eQShpIBcQtZtM5trJwm1VvxbIoMpRYY3ybTAutcKTLEmTsdnaknOHbiQA==} 237 | engines: {node: '>=14.0.0'} 238 | hasBin: true 239 | 240 | terser@5.39.0: 241 | resolution: {integrity: sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==} 242 | engines: {node: '>=10'} 243 | hasBin: true 244 | 245 | to-regex-range@5.0.1: 246 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 247 | engines: {node: '>=8.0'} 248 | 249 | uglify-js@3.19.3: 250 | resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} 251 | engines: {node: '>=0.8.0'} 252 | hasBin: true 253 | 254 | upper-case@1.1.3: 255 | resolution: {integrity: sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==} 256 | 257 | snapshots: 258 | 259 | '@jridgewell/gen-mapping@0.3.8': 260 | dependencies: 261 | '@jridgewell/set-array': 1.2.1 262 | '@jridgewell/sourcemap-codec': 1.5.0 263 | '@jridgewell/trace-mapping': 0.3.25 264 | 265 | '@jridgewell/resolve-uri@3.1.2': {} 266 | 267 | '@jridgewell/set-array@1.2.1': {} 268 | 269 | '@jridgewell/source-map@0.3.6': 270 | dependencies: 271 | '@jridgewell/gen-mapping': 0.3.8 272 | '@jridgewell/trace-mapping': 0.3.25 273 | 274 | '@jridgewell/sourcemap-codec@1.5.0': {} 275 | 276 | '@jridgewell/trace-mapping@0.3.25': 277 | dependencies: 278 | '@jridgewell/resolve-uri': 3.1.2 279 | '@jridgewell/sourcemap-codec': 1.5.0 280 | 281 | '@trysound/sax@0.2.0': {} 282 | 283 | acorn@8.14.1: {} 284 | 285 | ansi-colors@4.1.3: {} 286 | 287 | anymatch@3.1.3: 288 | dependencies: 289 | normalize-path: 3.0.0 290 | picomatch: 2.3.1 291 | 292 | binary-extensions@2.3.0: {} 293 | 294 | boolbase@1.0.0: {} 295 | 296 | braces@3.0.3: 297 | dependencies: 298 | fill-range: 7.1.1 299 | 300 | buffer-from@1.1.2: {} 301 | 302 | camel-case@3.0.0: 303 | dependencies: 304 | no-case: 2.3.2 305 | upper-case: 1.1.3 306 | 307 | chokidar@3.6.0: 308 | dependencies: 309 | anymatch: 3.1.3 310 | braces: 3.0.3 311 | glob-parent: 5.1.2 312 | is-binary-path: 2.1.0 313 | is-glob: 4.0.3 314 | normalize-path: 3.0.0 315 | readdirp: 3.6.0 316 | optionalDependencies: 317 | fsevents: 2.3.3 318 | 319 | clap@3.1.1: 320 | dependencies: 321 | ansi-colors: 4.1.3 322 | 323 | clean-css@4.2.4: 324 | dependencies: 325 | source-map: 0.6.1 326 | 327 | commander@2.20.3: {} 328 | 329 | commander@7.2.0: {} 330 | 331 | css-select@5.1.0: 332 | dependencies: 333 | boolbase: 1.0.0 334 | css-what: 6.1.0 335 | domhandler: 5.0.3 336 | domutils: 3.2.2 337 | nth-check: 2.1.1 338 | 339 | css-tree@2.2.1: 340 | dependencies: 341 | mdn-data: 2.0.28 342 | source-map-js: 1.2.1 343 | 344 | css-tree@2.3.1: 345 | dependencies: 346 | mdn-data: 2.0.30 347 | source-map-js: 1.2.1 348 | 349 | css-what@6.1.0: {} 350 | 351 | csso-cli@4.0.2: 352 | dependencies: 353 | chokidar: 3.6.0 354 | clap: 3.1.1 355 | csso: 5.0.5 356 | source-map-js: 1.2.1 357 | 358 | csso@5.0.5: 359 | dependencies: 360 | css-tree: 2.2.1 361 | 362 | dom-serializer@2.0.0: 363 | dependencies: 364 | domelementtype: 2.3.0 365 | domhandler: 5.0.3 366 | entities: 4.5.0 367 | 368 | domelementtype@2.3.0: {} 369 | 370 | domhandler@5.0.3: 371 | dependencies: 372 | domelementtype: 2.3.0 373 | 374 | domutils@3.2.2: 375 | dependencies: 376 | dom-serializer: 2.0.0 377 | domelementtype: 2.3.0 378 | domhandler: 5.0.3 379 | 380 | entities@4.5.0: {} 381 | 382 | fill-range@7.1.1: 383 | dependencies: 384 | to-regex-range: 5.0.1 385 | 386 | fsevents@2.3.3: 387 | optional: true 388 | 389 | glob-parent@5.1.2: 390 | dependencies: 391 | is-glob: 4.0.3 392 | 393 | he@1.2.0: {} 394 | 395 | highlight.js@https://codeload.github.com/highlightjs/highlight.js/tar.gz/2a972d86589f65f4e79f67a02c3bf389a187afa0: {} 396 | 397 | html-minifier@4.0.0: 398 | dependencies: 399 | camel-case: 3.0.0 400 | clean-css: 4.2.4 401 | commander: 2.20.3 402 | he: 1.2.0 403 | param-case: 2.1.1 404 | relateurl: 0.2.7 405 | uglify-js: 3.19.3 406 | 407 | is-binary-path@2.1.0: 408 | dependencies: 409 | binary-extensions: 2.3.0 410 | 411 | is-extglob@2.1.1: {} 412 | 413 | is-glob@4.0.3: 414 | dependencies: 415 | is-extglob: 2.1.1 416 | 417 | is-number@7.0.0: {} 418 | 419 | lower-case@1.1.4: {} 420 | 421 | mdn-data@2.0.28: {} 422 | 423 | mdn-data@2.0.30: {} 424 | 425 | no-case@2.3.2: 426 | dependencies: 427 | lower-case: 1.1.4 428 | 429 | normalize-path@3.0.0: {} 430 | 431 | nth-check@2.1.1: 432 | dependencies: 433 | boolbase: 1.0.0 434 | 435 | param-case@2.1.1: 436 | dependencies: 437 | no-case: 2.3.2 438 | 439 | picocolors@1.1.1: {} 440 | 441 | picomatch@2.3.1: {} 442 | 443 | readdirp@3.6.0: 444 | dependencies: 445 | picomatch: 2.3.1 446 | 447 | relateurl@0.2.7: {} 448 | 449 | source-map-js@1.2.1: {} 450 | 451 | source-map-support@0.5.21: 452 | dependencies: 453 | buffer-from: 1.1.2 454 | source-map: 0.6.1 455 | 456 | source-map@0.6.1: {} 457 | 458 | svgo@3.1.0: 459 | dependencies: 460 | '@trysound/sax': 0.2.0 461 | commander: 7.2.0 462 | css-select: 5.1.0 463 | css-tree: 2.3.1 464 | css-what: 6.1.0 465 | csso: 5.0.5 466 | picocolors: 1.1.1 467 | 468 | terser@5.39.0: 469 | dependencies: 470 | '@jridgewell/source-map': 0.3.6 471 | acorn: 8.14.1 472 | commander: 2.20.3 473 | source-map-support: 0.5.21 474 | 475 | to-regex-range@5.0.1: 476 | dependencies: 477 | is-number: 7.0.0 478 | 479 | uglify-js@3.19.3: {} 480 | 481 | upper-case@1.1.3: {} 482 | -------------------------------------------------------------------------------- /scripts/highlight.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ( 4 | set -e 5 | 6 | # go to highlight.js package folder and install dependencies 7 | cd node_modules/highlight.js 8 | pnpm install 9 | 10 | # generate highlight.js file 11 | node tools/build.js -t browser json typescript bash powershell dos python 12 | 13 | # return back 14 | cd ../.. 15 | 16 | # copy result file to theme/highlight.js 17 | mkdir -p theme 18 | mv node_modules/highlight.js/build/highlight.min.js theme/highlight.js 19 | ) 20 | -------------------------------------------------------------------------------- /scripts/minify.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # minify html 4 | pnpm exec html-minifier \ 5 | --collapse-boolean-attributes \ 6 | --collapse-whitespace \ 7 | --decode-entities \ 8 | --minify-css true \ 9 | --minify-js true \ 10 | --process-conditional-comments \ 11 | --remove-attribute-quotes \ 12 | --remove-comments \ 13 | --remove-empty-attributes \ 14 | --remove-optional-tags \ 15 | --remove-script-type-attributes \ 16 | --remove-style-link-type-attributes \ 17 | --sort-attributes \ 18 | --sort-class-name \ 19 | --use-short-doctype \ 20 | --input-dir ./book \ 21 | --output-dir ./book \ 22 | --file-ext html 23 | 24 | # minify css 25 | find ./book -type f -name "*.css" | \ 26 | xargs -P0 -i -- pnpm exec csso --comments none -i {} -o {} 27 | 28 | # minify js 29 | find ./book -type f -name "*.js" | \ 30 | xargs -P0 -i -- pnpm exec terser {} -o {} 31 | 32 | # minify svg 33 | pnpm exec svgo -q -r -f ./book 34 | --------------------------------------------------------------------------------