1
1
mirror of https://gitlab.com/ceda_ei/Quadnite-Bot synced 2026-06-18 02:50:05 +02:00

Compare commits

..

26 Commits

Author SHA1 Message Date
0d7ed0f9e1 Add roleplay commands 2026-05-09 17:35:54 +02:00
899b6ecca8 Handle commands for ctx.params and add ctx.command 2026-05-09 17:35:01 +02:00
7bbc82d175 Add /help command 2026-05-09 10:27:59 +02:00
1ad42e6068 Add ipdb as a dev dependency 2026-05-09 09:06:58 +02:00
c41ab294e9 Add absurdify, dice, random commands, response commands 2026-05-09 09:06:47 +02:00
af03a53e21 Add commands to Command, logging and improve command check 2026-05-09 09:06:00 +02:00
58af21ca6d Update .gitignore 2026-05-09 09:01:33 +02:00
6405251ae1 Move static inside python package 2026-05-04 18:26:19 +02:00
bdd3a11cec Add core structure for DeltaChat port 2026-05-04 18:25:48 +02:00
7cf9689420 Copy message text for feedback instead of forwarding
Telegram's pseudo-DRM prevents bots from forwarding messages in chats
with "Restrict Saving Content"
2024-10-13 20:26:07 +05:30
e3a5f1a67b Change rate limit config
Don't send a message and use the chat as key when possible
2024-10-02 22:39:36 +05:30
cd374090f2 Merge branch 'feat/ratelimit' into 'main'
feat: add rate limiter middleware

See merge request ceda_ei/Quadnite-Bot!4
2024-09-30 05:22:36 +00:00
Sphericalkat
8274ab0980 feat: add rate limiter middleware
Signed-off-by: Sphericalkat <me@kat.bio>
2024-09-30 10:39:07 +05:30
80a0dbd2d3 Fix crash on failing to send gif 2024-09-30 10:05:45 +05:30
41ae943913 Remove donate link 2024-08-09 16:33:14 +05:30
bdf52331b1 Add username in feedback 2024-04-16 19:15:54 +05:30
5ededd535f Fix typos 2024-02-06 18:16:42 +05:30
21871c9cd6 Update telegraf to 4.15 2024-01-25 00:38:35 +05:30
c01ad5109d Update commands_list.txt 2024-01-25 00:37:34 +05:30
5f7f1ced01 Match dice for full line optionally as a command 2023-10-19 21:20:20 +05:30
d844ac8455 Make dice command case-insensitive 2023-10-14 23:00:15 +05:30
69448a1052 Add dice 2023-10-14 21:17:06 +05:30
f44d83c89a Remove questions of the form "... beginning with the letter ..." 2022-01-26 17:43:51 +05:30
ae21f68cc7 Add /donate 2021-11-25 00:05:57 +05:30
4b8aecf28a Allow aliases in roleplay.json. Add runs, sob, sobs, handhold aliases 2021-10-06 22:59:08 +05:30
f1740ce4c0 Update README 2021-09-28 14:54:05 +05:30
40 changed files with 1261 additions and 233 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
node_modules
data/*
!data/.gitkeep
__pycache__/

1
.python-version Normal file
View File

@@ -0,0 +1 @@
3.13

View File

@@ -1,2 +1,18 @@
# Quadnite-Bot
Source code for @quadnite_bot
Source code for [@quadnite\_bot](https://t.me/quadnite_bot)
## Running your own instance
Quadnite bot depends on [Ugoki](https://gitlab.com/ceda_ei/ugoki) for providing
roleplay gifs. Once you have an instance of Ugoki (and optionally
[Ugoki Frontend](https://gitlab.com/ceda_ei/ugoki-frontend)) running:
- Clone this repo
- `npm install`
- `export BOT_API_KEY="your-token-for-bot"`
- `export FEEDBACK_ID="chat-id-where-feedback-is-forwarded-to"`
- `export UGOKI_ROOT="https://root.of.ugoki.api/server/"`
- `export RATE_TIMEFRAME=5000 # rate limit time interval in milliseconds`
- `export RATE_LIMIT=5 # number of requests allowed in the timeframe`
- `npm start`

11
bot.js
View File

@@ -1,12 +1,19 @@
const Telegraf = require("telegraf");
const { BOT_API_KEY, FEEDBACK_ID, UGOKI_ROOT } = process.env;
const { Telegraf } = require("telegraf");
const { BOT_API_KEY, FEEDBACK_ID, UGOKI_ROOT, RATE_TIMEFRAME, RATE_LIMIT } = process.env;
const fs = require("fs").promises;
const commands = require("./commands");
const axios = require("axios");
const roleplay = require("./static/roleplay.json");
const { limit } = require("@grammyjs/ratelimiter");
const bot = new Telegraf(BOT_API_KEY);
bot.catch((err) => console.log(err));
bot.use(limit({
// default config: 1 message per 1 second
timeFrame: RATE_TIMEFRAME ?? 1000,
limit: RATE_LIMIT ?? 1,
keyGenerator: (ctx) => ctx.chat?.id.toString() ?? ctx.from?.id.toString(),
}))
const data = [
"questions",

View File

@@ -16,7 +16,7 @@ module.exports = () => (ctx) => {
} else {
if (ctx.message.reply_to_message)
if (ctx.message.reply_to_message && !ctx.message.reply_to_message.is_topic_message)
return absurdify(ctx.message.reply_to_message.text);
else
return "Need text to absurdify. Send /absurdify text or reply to a"

31
commands/dice.js Normal file
View File

@@ -0,0 +1,31 @@
function diceRoll(side) {
return Math.ceil(Math.random() * side);
}
module.exports = () => async (ctx) => {
const numDice = parseInt(ctx.match[1] || "1");
const diceSides = parseInt(ctx.match[2]);
const rolls = Array(numDice)
.fill(0)
.map(() => diceRoll(diceSides));
const total = rolls.reduce((acc, curr) => acc + curr, 0);
const message = rolls
.map((i) => `_You roll a_ *D${diceSides}* _and get a_ *${i}*`)
.join("\n");
let totalMessage = "";
if (numDice > 1 || ctx.match[4])
totalMessage = `*Total:* ${total}`;
if (ctx.match[4]) {
const modifier = parseInt(ctx.match[6]);
const sign = ctx.match[5];
if (sign === "+") totalMessage += ` + ${modifier} = ${total + modifier}`;
else totalMessage += ` - ${modifier} = ${total - modifier}`;
}
ctx.reply(message + "\n\n" + totalMessage, { parse_mode: "Markdown" });
};

View File

@@ -37,7 +37,7 @@ module.exports = (words = []) => (ctx) => {
} else {
if (ctx.message.reply_to_message)
if (ctx.message.reply_to_message && !ctx.message.reply_to_message.is_topic_message)
return expand(words, ctx.message.reply_to_message.text);
else
return "Need text to expand. Send /expand text or reply to a "

View File

@@ -1,14 +1,27 @@
module.exports = (feedback_id) => (ctx) => {
module.exports = (bot, feedback_id) => (ctx) => {
const message = ctx.message.text.replace(/^[^ ]+/, "");
if (message) {
ctx.forwardMessage(feedback_id);
return "Thanks for the feedback";
const from = ctx.message.from;
let contactable = "The developer might contact you regarding your feedback.";
let message;
if (from.username) {
message = `Feedback from: @${from.username}`;
} else {
contactable = "The developer might not be able to contact you due to lack of your username.";
message = `Feedback from User ${from.id}`;
}
bot.telegram.sendMessage(feedback_id, `${message} ${ctx.message.text}`).catch(console.log);
return `Thanks for the feedback! ${contactable}`;
} else {
return "To send feedback type in /feedback followed by the feedback";
return "To send feedback type in /feedback followed by the feedback. Note that developers may contact you regarding the feedback.";
}

View File

@@ -10,6 +10,7 @@ const info = require("./info");
const expand = require("./expand");
const roleplay = require("./roleplay");
const suggest = require("./suggest");
const dice = require("./dice");
module.exports = (bot, [ questions, kys, insults, commands_list, words, roleplay_data ], feedback_id, apiToken, ugokiRoot, axios) => {
@@ -20,7 +21,7 @@ module.exports = (bot, [ questions, kys, insults, commands_list, words, roleplay
.then(bot_user => {
const default_text = (command, text) => `Do you want to ${text} `
+ `yourself?\nIf no, reply to someone with /${command} to kill`
+ `yourself?\nIf no, reply to someone with /${command} to ${command}`
+ ` them or run /${command} username/name.\nYou can suggest `
+ `more /${command} replies using /feedback`;
@@ -54,7 +55,7 @@ module.exports = (bot, [ questions, kys, insults, commands_list, words, roleplay
"Markdown"}));
bot.command("weebify", (ctx) => ctx.reply(weebify()(ctx)));
bot.command("absurdify", (ctx) => ctx.reply(absurdify()(ctx)));
bot.command("feedback", (ctx) => ctx.reply(feedback(feedback_id)(ctx)));
bot.command("feedback", (ctx) => ctx.reply(feedback(bot, feedback_id)(ctx)));
bot.command("wiki", (ctx) => media_wiki(axios,
"https://en.wikipedia.org/w/api.php")(ctx).then(x => ctx.reply(x,
{parse_mode: "HTML"})));
@@ -66,17 +67,37 @@ module.exports = (bot, [ questions, kys, insults, commands_list, words, roleplay
bot.command("start", (ctx) => ctx.reply("Hi, I am Quadnite. If you are "
+ "chatting with me in private, you are most likely doing it wrong. "
+ "Add me to a group for fun. To give feedback, use /feedback"));
bot.hears(/^\/?(\d*)d(\d+)(@\w+)?(\s*([-+])\s*(\d+))?$/i, dice());
const getGetGif = (command) => () => axios.get(
`category/${command}/gif`,
{
baseURL: ugokiRoot
}
);
function getGetGif(command) {
const alias = roleplay_data[command].alias;
if (alias)
return getGetGif(alias);
return () => axios.get(
`category/${command}/gif`,
{
baseURL: ugokiRoot
}
);
}
function getForms(name) {
if (roleplay_data[name].forms)
return roleplay_data[name].forms;
return getForms(roleplay_data[name].alias);
}
// Add all roleplay commands
Object.keys(roleplay_data).map(command =>
bot.command(command, ctx => roleplay(roleplay_data[command].forms, getGetGif(command))(ctx)));
bot.command(command,
(ctx) => roleplay(getForms(command), getGetGif(command))(ctx)
)
);
bot.command("suggest", (ctx) => suggest(axios, apiToken, ugokiRoot)(ctx));

View File

@@ -5,7 +5,7 @@ module.exports = () => (ctx) => {
text += `Message ID: \`${msg.message_id}\`\n`;
text += `Chat ID: \`${msg.chat.id}\`\n`;
text += `User ID: \`${msg.from.id}\`\n`;
if (msg.reply_to_message) {
if (ctx.message.reply_to_message && !ctx.message.reply_to_message.is_topic_message) {
const reply = msg.reply_to_message;
text += "\n*Reply to*\n";

View File

@@ -1,6 +1,6 @@
module.exports = (random, kys, default_text, bot_text, excluded_names) => (ctx) => {
if (ctx.message.reply_to_message) {
if (ctx.message.reply_to_message && !ctx.message.reply_to_message.is_topic_message) {
const { from } = ctx.message.reply_to_message;
const name = from.username ? "@" + from.username : from.first_name;

View File

@@ -14,7 +14,7 @@ module.exports = (forms, getGif) => (ctx) => {
.match(/^((@\w+(\s+|$))*)(.*)/);
const users = message[1].trim().split(" ").filter(i => i.length);
const rtm = ctx.message.reply_to_message;
if (rtm)
if (rtm && !rtm.is_topic_message)
users.push(rtm.from.username ? "@" + rtm.from.username
: rtm.from.first_name);
const reason = message[4];
@@ -38,7 +38,7 @@ module.exports = (forms, getGif) => (ctx) => {
reply = forms.none
.replace("{}", user);
getGif()
return getGif()
.then(gif => ctx.replyWithAnimation(gif.data.url, {caption: reply}));
};

View File

@@ -44,7 +44,7 @@ module.exports = () => (ctx) => {
} else {
if (ctx.message.reply_to_message)
if (ctx.message.reply_to_message && !ctx.message.reply_to_message.is_topic_message)
return weebify(ctx.message.reply_to_message.text);
else
return "Need text to weebify. Send /weebify text or reply to a "

240
package-lock.json generated
View File

@@ -1,24 +1,41 @@
{
"name": "quadnite-bot",
"version": "1.0.0",
"version": "2.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "quadnite-bot",
"version": "1.0.0",
"version": "2.0.0",
"license": "GPL-3.0",
"dependencies": {
"@grammyjs/ratelimiter": "^1.2.0",
"axios": "^0.21.0",
"fluent-ffmpeg": "^2.1.2",
"form-data": "^4.0.0",
"telegraf": "^3.27.1"
"telegraf": "^4.15.3"
}
},
"node_modules/@types/node": {
"version": "10.12.26",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.26.tgz",
"integrity": "sha512-nMRqS+mL1TOnIJrL6LKJcNZPB8V3eTfRo9FQA2b5gDvrHurC8XbSA86KNe0dShlEL7ReWJv/OU9NL7Z0dnqWTg=="
"node_modules/@grammyjs/ratelimiter": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@grammyjs/ratelimiter/-/ratelimiter-1.2.0.tgz",
"integrity": "sha512-xBkH/ATJsuv5JgVYX9yQM9DNg75Qqjw+gh82lVsBn4j+d0DkxxC+kuy6WFoB96Cb6oifQfaBJL8CTikdYG4v0A=="
},
"node_modules/@telegraf/types": {
"version": "6.9.1",
"resolved": "https://registry.npmjs.org/@telegraf/types/-/types-6.9.1.tgz",
"integrity": "sha512-bzqwhicZq401T0e09tu8b1KvGfJObPmzKU/iKCT5V466AsAZZWQrBYQ5edbmD1VZuHLEwopoOVY5wPP4HaLtug=="
},
"node_modules/abort-controller": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
"dependencies": {
"event-target-shim": "^5.0.0"
},
"engines": {
"node": ">=6.5"
}
},
"node_modules/async": {
"version": "3.2.1",
@@ -38,6 +55,25 @@
"follow-redirects": "^1.14.0"
}
},
"node_modules/buffer-alloc": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
"integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==",
"dependencies": {
"buffer-alloc-unsafe": "^1.1.0",
"buffer-fill": "^1.0.0"
}
},
"node_modules/buffer-alloc-unsafe": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz",
"integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg=="
},
"node_modules/buffer-fill": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
"integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ=="
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@@ -50,9 +86,9 @@
}
},
"node_modules/debug": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dependencies": {
"ms": "2.1.2"
},
@@ -73,6 +109,14 @@
"node": ">=0.4.0"
}
},
"node_modules/event-target-shim": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
"engines": {
"node": ">=6"
}
},
"node_modules/fluent-ffmpeg": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/fluent-ffmpeg/-/fluent-ffmpeg-2.1.2.tgz",
@@ -141,20 +185,52 @@
"node": ">= 0.6"
}
},
"node_modules/mri": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
"integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
"engines": {
"node": ">=4"
}
},
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/node-fetch": {
"version": "2.6.5",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz",
"integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==",
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/p-timeout": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-4.1.0.tgz",
"integrity": "sha512-+/wmHtzJuWii1sXn3HCuH/FTwGhrp4tmJTxSKJbfS+vkipci6osxXM5mY0jUiRzWKMTgUT8l7HFbeSwZAynqHw==",
"engines": {
"node": ">=10"
}
},
"node_modules/safe-compare": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/safe-compare/-/safe-compare-1.1.4.tgz",
"integrity": "sha512-b9wZ986HHCo/HbKrRpBJb2kqXMK9CEWIE1egeEvZsYn69ay3kdfl9nG3RyOcR+jInTDf7a86WQ1d4VJX7goSSQ==",
"dependencies": {
"buffer-alloc": "^1.2.0"
}
},
"node_modules/sandwich-stream": {
@@ -166,38 +242,40 @@
}
},
"node_modules/telegraf": {
"version": "3.27.1",
"integrity": "sha512-RQUnuNAEEWcLhRap81qwGUUqAy1KcvqANnA0G3pzZqFkhMe6LrTk5lVi9tdOaF0Ud/yOx5fdx0rNPYfiB27Z+w==",
"version": "4.15.3",
"resolved": "https://registry.npmjs.org/telegraf/-/telegraf-4.15.3.tgz",
"integrity": "sha512-pm2ZQAisd0YlUvnq6xdymDfoQR++8wTalw0nfw7Tjy0va+V/0HaBLzM8kMNid8pbbt7GHTU29lEyA5CAAr8AqA==",
"dependencies": {
"@types/node": "^10.1.2",
"debug": "^4.0.1",
"node-fetch": "^2.2.0",
"sandwich-stream": "^2.0.1",
"telegram-typings": "^3.6.0"
"@telegraf/types": "^6.9.1",
"abort-controller": "^3.0.0",
"debug": "^4.3.4",
"mri": "^1.2.0",
"node-fetch": "^2.6.8",
"p-timeout": "^4.1.0",
"safe-compare": "^1.1.4",
"sandwich-stream": "^2.0.2"
},
"bin": {
"telegraf": "lib/cli.mjs"
},
"engines": {
"node": ">=6.2.0"
"node": "^12.20.0 || >=14.13.1"
}
},
"node_modules/telegram-typings": {
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/telegram-typings/-/telegram-typings-3.6.1.tgz",
"integrity": "sha512-njVv1EAhIZnmQVLocZEADYUyqA1WIXuVcDYlsp+mXua/XB0pxx+PKtMSPeZ/EE4wPWTw9h/hA9ASTT6yQelkiw=="
},
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
@@ -216,10 +294,23 @@
}
},
"dependencies": {
"@types/node": {
"version": "10.12.26",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.26.tgz",
"integrity": "sha512-nMRqS+mL1TOnIJrL6LKJcNZPB8V3eTfRo9FQA2b5gDvrHurC8XbSA86KNe0dShlEL7ReWJv/OU9NL7Z0dnqWTg=="
"@grammyjs/ratelimiter": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@grammyjs/ratelimiter/-/ratelimiter-1.2.0.tgz",
"integrity": "sha512-xBkH/ATJsuv5JgVYX9yQM9DNg75Qqjw+gh82lVsBn4j+d0DkxxC+kuy6WFoB96Cb6oifQfaBJL8CTikdYG4v0A=="
},
"@telegraf/types": {
"version": "6.9.1",
"resolved": "https://registry.npmjs.org/@telegraf/types/-/types-6.9.1.tgz",
"integrity": "sha512-bzqwhicZq401T0e09tu8b1KvGfJObPmzKU/iKCT5V466AsAZZWQrBYQ5edbmD1VZuHLEwopoOVY5wPP4HaLtug=="
},
"abort-controller": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
"requires": {
"event-target-shim": "^5.0.0"
}
},
"async": {
"version": "3.2.1",
@@ -239,6 +330,25 @@
"follow-redirects": "^1.14.0"
}
},
"buffer-alloc": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
"integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==",
"requires": {
"buffer-alloc-unsafe": "^1.1.0",
"buffer-fill": "^1.0.0"
}
},
"buffer-alloc-unsafe": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz",
"integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg=="
},
"buffer-fill": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
"integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ=="
},
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@@ -248,9 +358,9 @@
}
},
"debug": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"requires": {
"ms": "2.1.2"
}
@@ -260,6 +370,11 @@
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
},
"event-target-shim": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
},
"fluent-ffmpeg": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/fluent-ffmpeg/-/fluent-ffmpeg-2.1.2.tgz",
@@ -302,54 +417,71 @@
"mime-db": "1.49.0"
}
},
"mri": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
"integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node-fetch": {
"version": "2.6.5",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz",
"integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==",
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"requires": {
"whatwg-url": "^5.0.0"
}
},
"p-timeout": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-4.1.0.tgz",
"integrity": "sha512-+/wmHtzJuWii1sXn3HCuH/FTwGhrp4tmJTxSKJbfS+vkipci6osxXM5mY0jUiRzWKMTgUT8l7HFbeSwZAynqHw=="
},
"safe-compare": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/safe-compare/-/safe-compare-1.1.4.tgz",
"integrity": "sha512-b9wZ986HHCo/HbKrRpBJb2kqXMK9CEWIE1egeEvZsYn69ay3kdfl9nG3RyOcR+jInTDf7a86WQ1d4VJX7goSSQ==",
"requires": {
"buffer-alloc": "^1.2.0"
}
},
"sandwich-stream": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/sandwich-stream/-/sandwich-stream-2.0.2.tgz",
"integrity": "sha512-jLYV0DORrzY3xaz/S9ydJL6Iz7essZeAfnAavsJ+zsJGZ1MOnsS52yRjU3uF3pJa/lla7+wisp//fxOwOH8SKQ=="
},
"telegraf": {
"version": "3.27.1",
"integrity": "sha512-RQUnuNAEEWcLhRap81qwGUUqAy1KcvqANnA0G3pzZqFkhMe6LrTk5lVi9tdOaF0Ud/yOx5fdx0rNPYfiB27Z+w==",
"version": "4.15.3",
"resolved": "https://registry.npmjs.org/telegraf/-/telegraf-4.15.3.tgz",
"integrity": "sha512-pm2ZQAisd0YlUvnq6xdymDfoQR++8wTalw0nfw7Tjy0va+V/0HaBLzM8kMNid8pbbt7GHTU29lEyA5CAAr8AqA==",
"requires": {
"@types/node": "^10.1.2",
"debug": "^4.0.1",
"node-fetch": "^2.2.0",
"sandwich-stream": "^2.0.1",
"telegram-typings": "^3.6.0"
"@telegraf/types": "^6.9.1",
"abort-controller": "^3.0.0",
"debug": "^4.3.4",
"mri": "^1.2.0",
"node-fetch": "^2.6.8",
"p-timeout": "^4.1.0",
"safe-compare": "^1.1.4",
"sandwich-stream": "^2.0.2"
}
},
"telegram-typings": {
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/telegram-typings/-/telegram-typings-3.6.1.tgz",
"integrity": "sha512-njVv1EAhIZnmQVLocZEADYUyqA1WIXuVcDYlsp+mXua/XB0pxx+PKtMSPeZ/EE4wPWTw9h/hA9ASTT6yQelkiw=="
},
"tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"requires": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"

View File

@@ -22,9 +22,10 @@
},
"homepage": "https://gitlab.com/ceda_ei/Quadnite-Bot#readme",
"dependencies": {
"@grammyjs/ratelimiter": "^1.2.0",
"axios": "^0.21.0",
"fluent-ffmpeg": "^2.1.2",
"form-data": "^4.0.0",
"telegraf": "^3.27.1"
"telegraf": "^4.15.3"
}
}

25
pyproject.toml Normal file
View File

@@ -0,0 +1,25 @@
[project]
name = "quadnite-bot"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
authors = [
{ name = "Irene Sheen", email = "ceda_ei@webionite.com" }
]
requires-python = ">=3.13"
dependencies = [
"deltabot-cli>=8.1.0",
"requests>=2.33.1",
]
[project.scripts]
quadnite-bot = "quadnite_bot:main"
[build-system]
requires = ["uv_build>=0.11.7,<0.12.0"]
build-backend = "uv_build"
[dependency-groups]
dev = [
"ipdb>=0.13.13",
]

View File

@@ -0,0 +1,3 @@
from quadnite_bot.__main__ import main
__all__ = ["main"]

View File

@@ -0,0 +1,15 @@
import logging
from deltabot_cli import BotCli
from deltachat2 import events
from quadnite_bot.command_registry import dispatcher
def main():
cli = BotCli("quadnite-bot")
logging.basicConfig(level=logging.DEBUG)
cli.on(events.NewMessage)(dispatcher)
cli.start()

View File

@@ -0,0 +1,83 @@
from abc import ABC, abstractmethod
import logging
import re
from deltachat2 import Bot, MsgData, NewMsgEvent
logger = logging.getLogger(__name__)
class Context:
match: re.Match[str] | None
params: str
args: list[str]
def __init__(self, bot: Bot, accid: int, event: NewMsgEvent, command: "Command") -> None:
self.bot = bot
self.accid = accid
self.event = event
self.command = ""
if command.command or command.commands:
commands: list[str] = [command.command] if command.command else command.commands
commands_join = "|".join(re.escape(command) for command in commands)
commands_re = re.compile(fr"^/({commands_join})\b\s*", re.I)
self.params = commands_re.sub("", event.msg.text)
if match := commands_re.match(event.msg.text):
self.command = match.group(1)
else:
self.params = event.msg.text
self.args = re.split(r"\s+", self.params)
self.match = None
if command.regex:
self.match = command.regex.search(event.msg.text)
def reply(self, text: str, **kwargs):
self.bot.rpc.send_msg(
self.accid,
self.event.msg.chat_id,
MsgData(text, **kwargs),
)
class Command(ABC):
command: str|None = None
commands: list[str]|None = None
regex: re.Pattern|None = None
run_next: bool = False
def handles_message(self, event: NewMsgEvent) -> bool:
commands = [self.command] if self.command else self.commands
if commands:
for command in commands:
user_input = event.msg.text.lower()
expected_input = f"/{command.lower()}"
if user_input == expected_input or user_input.startswith(expected_input + " "):
return True
return False
if self.regex:
return self.regex.search(event.msg.text) is not None
raise NotImplementedError(f"The command has neither 'command' nor 'regex' set. Required one of the two.")
@abstractmethod
def process_event(self, ctx: Context, event: NewMsgEvent) -> None:
pass
def __call__(self, bot: Bot, accid: int, event: NewMsgEvent) -> None:
self.process_event(Context(bot, accid, event, self), event)
class CommandDispatcher:
def __init__(self):
self._commands: list[Command] = []
def add_command(self, command: Command):
self._commands.append(command)
def __call__(self, bot: Bot, accid: int, event: NewMsgEvent) -> None:
logger.info("Received new message")
for command in self._commands:
logger.debug("Checking against %s", command)
if command.handles_message(event):
logger.info("Match found. Running the command %s", command)
command(bot, accid, event)
if not command.run_next:
break

View File

@@ -0,0 +1,21 @@
from quadnite_bot.command import CommandDispatcher
from quadnite_bot.commands.absurdify import AbsurdifyCommand
from quadnite_bot.commands.dice import DiceMatch
from quadnite_bot.commands.echo import EchoCommand
from quadnite_bot.commands.help import HelpCommand
from quadnite_bot.commands.random import CoinCommand, QuestionCommand, WordCommand, WordsCommand
from quadnite_bot.commands.response import ResponseCommands
from quadnite_bot.commands.roleplay import RoleplayCommands
dispatcher = CommandDispatcher()
dispatcher.add_command(EchoCommand())
dispatcher.add_command(AbsurdifyCommand())
dispatcher.add_command(DiceMatch())
dispatcher.add_command(QuestionCommand())
dispatcher.add_command(WordCommand())
dispatcher.add_command(WordsCommand())
dispatcher.add_command(CoinCommand())
dispatcher.add_command(ResponseCommands())
dispatcher.add_command(HelpCommand())
dispatcher.add_command(RoleplayCommands())

View File

View File

@@ -0,0 +1,16 @@
import random
from deltachat2 import NewMsgEvent
from quadnite_bot.command import Command, Context
def _absurdify(text):
return "".join(
random.choice([char.upper(), char.lower()]) for char in text
)
class AbsurdifyCommand(Command):
command = "absurdify"
def process_event(self, ctx: Context, event: NewMsgEvent) -> None:
ctx.reply(_absurdify(ctx.params))

View File

@@ -0,0 +1,69 @@
import random
import re
import operator
from deltachat2 import NewMsgEvent
from quadnite_bot.command import Command, Context
class DiceMatch(Command):
regex = re.compile(
r"""^
/? # optional slash at beginning
(\d*)d(\d+) # num of dice + num of side
(\s*(kh|kl)\s*(\d+))? # keep highest / lowest
(\s*([-+><]|>=|<=)\s*(\d+))? # modifier for sum / count successes
$""",
re.I | re.VERBOSE,
)
def process_event(self, ctx: Context, event: NewMsgEvent) -> None:
if not ctx.match:
return
num_dice = int(ctx.match.group(1) or 1)
dice_sides = int(ctx.match.group(2))
if num_dice > 50:
ctx.reply("Maximum of 50 dice allowed")
if dice_sides > 1000:
ctx.reply("Number of sides must be 1000 or lower")
rolls = [random.randint(1, dice_sides) for _ in range(num_dice)]
message = "\n".join(
f"You rolled a D{dice_sides} and got a {roll}" for roll in rolls
)
message += "\n\n"
keep = ctx.match.group(4)
if keep:
keep_count = int(ctx.match.group(5))
rolls = sorted(rolls, reverse=keep=="kh")[:keep_count]
modifier = ctx.match.group(7)
modifier_value = ctx.match.group(8)
if modifier_value:
modifier_value = int(modifier_value)
else:
modifier_value = 0
if modifier in [None, "+", "-"]:
total = sum(rolls)
if modifier == "+":
total += modifier_value
elif modifier == "-":
total -= modifier_value
message += f"Total = {total}"
elif modifier in [">", "<", "<=", ">="]:
successes = 0
op_map = {
">": operator.gt,
"<": operator.lt,
">=": operator.ge,
"<=": operator.le,
}
for roll in rolls:
if op_map[modifier](roll, modifier_value):
successes += 1
message += f"You got {successes} successes."
ctx.reply(message)

View File

@@ -0,0 +1,8 @@
from deltachat2 import NewMsgEvent
from quadnite_bot.command import Command, Context
class EchoCommand(Command):
command = "echo"
def process_event(self, ctx: Context, event: NewMsgEvent) -> None:
ctx.reply(event.msg.text)

View File

@@ -0,0 +1,17 @@
from pathlib import Path
from deltachat2 import NewMsgEvent
from quadnite_bot.command import Command, Context
class HelpCommand(Command):
command = "help"
def __init__(self):
self.responses = []
for file in sorted((Path(__file__).resolve().parent.parent / "static/help").iterdir()):
with open(file) as f:
self.responses.append(f.read())
def process_event(self, ctx: Context, event: NewMsgEvent) -> None:
for response in self.responses:
ctx.reply(response)

View File

@@ -0,0 +1,53 @@
from pathlib import Path
import random
from deltachat2 import NewMsgEvent
from quadnite_bot.command import Command, Context
class BaseRandomCommand(Command):
filename: str
def __init__(self):
file = Path(__file__).resolve().parent.parent / "static" / self.filename
with open(file) as f:
self.options = [line.strip() for line in f.readlines()]
def process_event(self, ctx: Context, event: NewMsgEvent) -> None:
ctx.reply(random.choice(self.options))
class QuestionCommand(BaseRandomCommand):
filename = "questions.txt"
command = "question"
class WordCommand(BaseRandomCommand):
filename = "words.txt"
command = "word"
class WordsCommand(BaseRandomCommand):
filename = "words.txt"
command = "words"
def process_event(self, ctx: Context, event: NewMsgEvent) -> None:
count = 10
if ctx.args:
try:
count = int(ctx.args[0])
except ValueError:
ctx.reply(f"{ctx.args[0]!r} is not a number.")
return
if count > 50:
count = 50
ctx.reply("Number too high. Limiting to 50.")
ctx.reply("\n".join(random.choices(self.options, k=count)))
class CoinCommand(BaseRandomCommand):
command = 'coin'
def __init__(self):
self.options = ['Heads', 'Tails']

View File

@@ -0,0 +1,19 @@
import random
from deltachat2 import NewMsgEvent
from quadnite_bot.command import Command, Context
class ResponseCommands(Command):
commands = ["is", "are", "can", "will", "shall", "was", "do", "does", "did", "should"]
def process_event(self, ctx: Context, event: NewMsgEvent) -> None:
ctx.reply(
random.choice(
random.choice(
[
["Yes", "Yep", "Yeah", "Yus", "Ja", "Ya", "Aye", "Ay", "Oui"],
["No", "Nopes", "Nu", "Nah", "Nein", "Naw", "Nay", "Yesn't"],
]
)
)
)

View File

@@ -0,0 +1,63 @@
import json
from pathlib import Path
import tempfile
import requests
from deltachat2 import MessageViewtype, NewMsgEvent
from quadnite_bot.command import Command, Context
class RoleplayCommands(Command):
def __init__(self):
file = Path(__file__).resolve().parent.parent / "static/roleplay.json"
with open(file) as f:
self.roleplay_commands = json.load(f)
self.commands = list(self.roleplay_commands.keys())
def _join_users(self, users: list[str]) -> str:
message = ", ".join(users[:1])
if len(users) > 1:
message += f" and {users[-1]}"
return message
def _get_command_form(self, command: str) -> tuple[str, dict[str, str]]:
roleplay = self.roleplay_commands[command]
if "forms" in roleplay:
return (command, roleplay["forms"])
return self._get_command_form(roleplay["alias"])
def _get_gif(self, category: str):
url = requests.get(f"https://ugoki.webionite.com/api/category/{category}/gif").json()["url"]
return requests.get(url).content
def process_event(self, ctx: Context, event: NewMsgEvent) -> None:
sender = event.msg.sender.display_name
users = []
message = ''
for idx, arg in enumerate(ctx.args):
if arg.startswith("@"):
users.append(arg[1:])
else:
message = " ".join(ctx.args[idx:])
break
category, roleplay = self._get_command_form(ctx.command)
users_message = self._join_users(users)
if users and message:
template = roleplay['both']
args = (sender, users_message, message)
elif users:
template = roleplay['others']
args = (sender, users_message)
elif message:
template = roleplay['reason']
args = (sender, message)
else:
template = roleplay['none']
args = (sender,)
gif = self._get_gif(category)
with tempfile.NamedTemporaryFile("w+b", suffix=".gif") as f:
f.write(gif)
ctx.reply(template.format(*args), viewtype=MessageViewtype.GIF.value, file=f.name)

View File

@@ -0,0 +1,5 @@
Random
/coin - Tosses a coin
/wiki [search term] - Search Wikipedia
/arch_wiki [search term] - Search the Arch wiki

View File

@@ -0,0 +1,8 @@
Wordplay
/question - Get a random question
/word - Get a random word
/words [n] - Get n random words
/weebify [text] - Weebifies the given text
/absurdify [text] - mAke tExT aBSUrd
/expand [word] - Expands a given abbreviation

View File

@@ -0,0 +1,8 @@
Ask a question
/<command> [question]
/is /are /can
/will /did /shall
/was /do /does
/should

View File

@@ -0,0 +1,42 @@
Roleplay
/<command> [@user1] [@user2] ... [@userN] [message]
(All arguments to the commands are optional)
/angry /bite
/blush /bored
/bonk /boop
/chase /cheer
/cringe /cry
/cuddle /dab
/dance /die
/eat /facepalm
/feed /glomp
/happy /hate
/holdhands /hide
/highfive /hug
/kill /kiss
/laugh /lick
/love /lurk
/nervous /no
/nom /nuzzle
/panic /pat
/peck /poke
/pout /run
/shoot /shrug
/sip /slap
/sleep /snuggle
/stab /tease
/think /thumbsup
/tickle /triggered
/twerk /wag
/wave /wink
/yes
Examples:
/hug @foobar
/slap making me angry
/holdhands @baz biz

View File

@@ -0,0 +1,16 @@
Dice
[num]d[sides] [keep modifier] [modifier]
num is the number of the dices to roll. (Optional)
sides is the number of sides of the dice. (Required)
keep_modifier is in the form of kh or kl followed by a number. This only keeps either the highest or lowest dice. (Optional)
modifier is in the form of +, -, >, <, >= or <= followed by a number. In case of + or -, the number is added or subtracted to the total. In case of >, <, >= or <=, the dice roll is checked against the condition and counted as a success if it matches it.(Optional)
Examples:
1d6
2d10 + 5
3d20 kh2 - 2
2d20 kl 2
10d6 >= 6
6d20 < 10

View File

@@ -605,32 +605,32 @@ On a scale of 1-10 how bitchy would you say you are?
On a scale of 1-10 how polite would you say you are?
On a scale of 1-10 how attractive would you say you are?
If you could be any famous person who would you be and why?
Whats your favourite animal beginning with the letter A?
Whats your favourite item of clothing beginning with the letter B?
Whats your favourite expleitive beginning with the letter C?
Whats your favourite boys name beginning with the letter D?
Whats your favourite girls name beginning with the letter E?
Whats your favourite book beginning with the letter F?
Whats your favourite bodypart beginning with the letter G?
Whats your favourite musical instrument beginning with the letter H?
Whats your favourite song beginning with the letter I?
Whats your favourite actress beginning with the letter J?
Whats your favourite actor beginning with the letter K?
Whats your favourite film beginning with the letter L?
Whats your favourite tv show beginning with the letter M?
Whats your favourite game beginning with the letter N?
Whats your favourite non alcoholic drink beginning with the letter O?
Whats your favourite food beginning with the letter P?
Whats your favourite band beginning with the letter Q?
Whats your favourite author beginning with the letter R?
Whats your favourite sport beginning with the letter S?
Whats your favourite job beginning with the letter T?
Whats your favourite mythical creature beginning with the letter U?
Whats your favourite alcoholic drink beginning with the letter V?
Whats your favourite cartoon character beginning with the letter W?
Whats your favourite word beginning with the letter X?
Whats your favourite city beginning with the letter Y?
Whats your favourite country beginning with the letter Z?
Whats your favourite animal?
Whats your favourite item of clothing?
Whats your favourite expleitive?
Whats your favourite boys name?
Whats your favourite girls name?
Whats your favourite book?
Whats your favourite bodypart?
Whats your favourite musical instrument?
Whats your favourite song?
Whats your favourite actress?
Whats your favourite actor?
Whats your favourite film?
Whats your favourite tv show?
Whats your favourite game?
Whats your favourite non alcoholic drink?
Whats your favourite food?
Whats your favourite band?
Whats your favourite author?
Whats your favourite sport?
Whats your favourite job?
Whats your favourite mythical creature?
Whats your favourite alcoholic drink?
Whats your favourite cartoon character?
Whats your favourite word?
Whats your favourite city?
Whats your favourite country?
Do you get seasick?
If you discovered a new species of dinosaur what would you call it?
Do you own a paddling pool?
@@ -1232,28 +1232,7 @@ If you were to remake a movie, what actors would you cast?
If you were to replace a character in your favourite movie, who would you replace with who?
Under rated actor who deserves to be famous in your opinion?
Whos your favourite celebrity with the same birthday or name as you?
Whats your favorite movie beginning with the letter A?
Whats your fav movie beginning with the letter B?
Whats your fav movie beginning with the letter C?
Whats your fav movie beginning with the letter D?
Whats your fav movie beginning with the letter E?
Whats your fav movie beginning with the letter F?
Whats your fav movie beginning with the letter G?
Whats your fav movie beginning with the letter H?
Whats your fav movie beginning with the letter I?
Whats your fav movie beginning with the letter J?
Whats your fav movie beginning with the letter K?
Whats your fav movie beginning with the letter L?
Whats your fav movie beginning with the letter M?
Whats your fav movie beginning with the letter N?
Whats your fav movie beginning with the letter O?
Whats your fav movie beginning with the letter P?
Whats your fav movie beginning with the letter S?
Whats your fav movie beginning with the letter Q?
Whats your fav movie beginning with the letter V?
Whats your fav movie beginning with the letter X?
Whats your fav movie beginning with the letter Y?
Whats your fav movie beginning with the letter Z?
Whats your favorite movie?
What movie would you wish to come to life?
Movies you think one should watch before dying?
Favourite actor who has not won a oscar yet?
@@ -1575,28 +1554,7 @@ What is your favourite cheat in GTA?
What car do you prefer to drive in GTA?
Hardest mission youve done in GTA?
Easiest mission youve done in GTA?
Whats your favourite game beginning with the letter A?
Whats your favourite game beginning with the letter B?
Whats your favourite game beginning with the letter C?
Whats your favourite game beginning with the letter D?
Whats your favourite game beginning with the letter E?
Whats your favourite game beginning with the letter F?
Whats your favourite game beginning with the letter G?
Whats your favourite game beginning with the letter H?
Whats your favourite game beginning with the letter I?
Whats your favourite game beginning with the letter J?
Whats your favourite game beginning with the letter K?
Whats your favourite game beginning with the letter L?
Whats your favourite game beginning with the letter M?
Whats your favourite game beginning with the letter N?
Whats your favourite game beginning with the letter O?
Whats your favourite game beginning with the letter P?
Whats your favourite game beginning with the letter S?
Whats your favourite game beginning with the letter Q?
Whats your favourite game beginning with the letter V?
Whats your favourite game beginning with the letter X?
Whats your favourite game beginning with the letter Y?
Whats your favourite game beginning with the letter Z?
Whats your favourite game?
Do you usually win or lose when playing against friends?
What are your parents inputs on you gaming?
What type of games do you like to play with your partner?
@@ -1631,8 +1589,7 @@ What impact do you think phones have had on the world?
Life without smartphone be like?
Have you ever did a prank call on anyone? If so, who and how did you prank them?
What was their reaction?
Have you ever been prank called?
What was your reaction?
Have you ever been prank called? What was your reaction?
Favourite smartphone logo?
Your favourite iphone?
Your favourite samsung phone?
@@ -1650,28 +1607,7 @@ Worst app youve installed?
Do you prefer free or paid apps?
Have you bought any paid apps? If so which?
Most expensive paid app you bought and were you satisfied with it?
Whats your favourite mobile app beginning with the letter A?
Whats your favourite mobile app beginning with the letter B?
Whats your favourite mobile app beginning with the letter C?
Whats your favourite mobile app beginning with the letter D?
Whats your favourite mobile appbeginning with the letter E?
Whats your favourite mobile app beginning with the letter F?
Whats your favourite mobile app beginning with the letter G?
Whats your favourite mobile app beginning with the letter H?
Whats your favourite mobile app beginning with the letter I?
Whats your favourite mobile app beginning with the letter J?
Whats your favourite mobile app beginning with the letter K?
Whats your favourite mobile app beginning with the letter L?
Whats your favourite mobile app beginning with the letter M?
Whats your favourite mobile app beginning with the letter N?
Whats your favourite mobile app beginning with the letter O?
Whats your favourite mobile app beginning with the letter P?
Whats your favourite mobile app beginning with the letter S?
Whats your favourite mobile app beginning with the letter Q?
Whats your favourite mobile app beginning with the letter V?
Whats your favourite mobile app beginning with the letter X?
Whats your favourite mobile app beginning with the letter Y?
Whats your favourite mobile app beginning with the letter Z?
Whats your favourite mobile app?
How do you usually take your photos? (With camera, phone? etc)
What software do you use to backup your photos?
Total number of photos youve in your gallery?

View File

@@ -143,6 +143,9 @@
"both": "{} is glomping {} for {}"
}
},
"handhold": {
"alias": "holdhands"
},
"happy": {
"forms": {
"none": "{} is happy",
@@ -319,6 +322,9 @@
"both": "{} is running from {} for {}"
}
},
"runs": {
"alias": "run"
},
"shoot": {
"forms": {
"none": "{} is shooting",
@@ -359,6 +365,18 @@
"both": "{} is sleeping {} for {}"
}
},
"sob": {
"alias": "sobs"
},
"sobs": {
"alias": "cry",
"forms": {
"none": "{} is sobbing",
"others": "{} is sobbing due to {}",
"reason": "{} is sobbing because {}",
"both": "{} is sobbing due to {} because {}"
}
},
"snuggle": {
"forms": {
"none": "{} is snuggling",

View File

@@ -1,61 +0,0 @@
<b>Random</b>
coin - Tosses a coin
wiki - Search Wikipedia
arch_wiki - Search the Arch wiki
kys - Kill yourself
insult - As expected, insults
<b>Wordplay</b>
question - Get a random question
word - Get a random word
words - Get n random words
weebify - Weebifies the given text
absurdify - mAke tExT aBSUrd
expand - Expands a given abbreviation
<b>Ask a question</b>
<code>
is are can
will did shall
was do does
should
</code>
<b>Roleplay</b>
<code>
angry bite
blush bored
bonk boop
chase cheer
cringe cry
cuddle dab
dance die
eat facepalm
feed glomp
happy hate
holdhands hide
highfive hug
kill kiss
laugh lick
love lurk
nervous no
nom nuzzle
panic pat
peck poke
pout run
shoot shrug
sip slap
sleep snuggle
stab tease
think thumbsup
tickle triggered
twerk wag
wave wink
yes
</code>
<b>Miscallenous</b>
help - Need help? Go here
feedback - Send feedback, suggestion for kys, insult text
rate - Rate me on TGDR

441
uv.lock generated Normal file
View File

@@ -0,0 +1,441 @@
version = 1
revision = 3
requires-python = ">=3.13"
[[package]]
name = "appdirs"
version = "1.4.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d7/d8/05696357e0311f5b5c316d7b95f46c669dd9c15aaeecbb48c7d0aeb88c40/appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41", size = 13470, upload-time = "2020-05-11T07:59:51.037Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/3b/00/2344469e2084fb287c2e0b57b72910309874c3245463acd6cf5e3db69324/appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128", size = 9566, upload-time = "2020-05-11T07:59:49.499Z" },
]
[[package]]
name = "asttokens"
version = "3.0.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308, upload-time = "2025-11-15T16:43:48.578Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047, upload-time = "2025-11-15T16:43:16.109Z" },
]
[[package]]
name = "certifi"
version = "2026.4.22"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/25/ee/6caf7a40c36a1220410afe15a1cc64993a1f864871f698c0f93acb72842a/certifi-2026.4.22.tar.gz", hash = "sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580", size = 137077, upload-time = "2026-04-22T11:26:11.191Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/22/30/7cd8fdcdfbc5b869528b079bfb76dcdf6056b1a2097a662e5e8c04f42965/certifi-2026.4.22-py3-none-any.whl", hash = "sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a", size = 135707, upload-time = "2026-04-22T11:26:09.372Z" },
]
[[package]]
name = "charset-normalizer"
version = "3.4.7"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271, upload-time = "2026-04-02T09:28:39.342Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063", size = 309627, upload-time = "2026-04-02T09:26:45.198Z" },
{ url = "https://files.pythonhosted.org/packages/2e/4e/b7f84e617b4854ade48a1b7915c8ccfadeba444d2a18c291f696e37f0d3b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c", size = 207008, upload-time = "2026-04-02T09:26:46.824Z" },
{ url = "https://files.pythonhosted.org/packages/c4/bb/ec73c0257c9e11b268f018f068f5d00aa0ef8c8b09f7753ebd5f2880e248/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66", size = 228303, upload-time = "2026-04-02T09:26:48.397Z" },
{ url = "https://files.pythonhosted.org/packages/85/fb/32d1f5033484494619f701e719429c69b766bfc4dbc61aa9e9c8c166528b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18", size = 224282, upload-time = "2026-04-02T09:26:49.684Z" },
{ url = "https://files.pythonhosted.org/packages/fa/07/330e3a0dda4c404d6da83b327270906e9654a24f6c546dc886a0eb0ffb23/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd", size = 215595, upload-time = "2026-04-02T09:26:50.915Z" },
{ url = "https://files.pythonhosted.org/packages/e3/7c/fc890655786e423f02556e0216d4b8c6bcb6bdfa890160dc66bf52dee468/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215", size = 201986, upload-time = "2026-04-02T09:26:52.197Z" },
{ url = "https://files.pythonhosted.org/packages/d8/97/bfb18b3db2aed3b90cf54dc292ad79fdd5ad65c4eae454099475cbeadd0d/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859", size = 211711, upload-time = "2026-04-02T09:26:53.49Z" },
{ url = "https://files.pythonhosted.org/packages/6f/a5/a581c13798546a7fd557c82614a5c65a13df2157e9ad6373166d2a3e645d/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8", size = 210036, upload-time = "2026-04-02T09:26:54.975Z" },
{ url = "https://files.pythonhosted.org/packages/8c/bf/b3ab5bcb478e4193d517644b0fb2bf5497fbceeaa7a1bc0f4d5b50953861/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5", size = 202998, upload-time = "2026-04-02T09:26:56.303Z" },
{ url = "https://files.pythonhosted.org/packages/e7/4e/23efd79b65d314fa320ec6017b4b5834d5c12a58ba4610aa353af2e2f577/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832", size = 230056, upload-time = "2026-04-02T09:26:57.554Z" },
{ url = "https://files.pythonhosted.org/packages/b9/9f/1e1941bc3f0e01df116e68dc37a55c4d249df5e6fa77f008841aef68264f/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6", size = 211537, upload-time = "2026-04-02T09:26:58.843Z" },
{ url = "https://files.pythonhosted.org/packages/80/0f/088cbb3020d44428964a6c97fe1edfb1b9550396bf6d278330281e8b709c/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48", size = 226176, upload-time = "2026-04-02T09:27:00.437Z" },
{ url = "https://files.pythonhosted.org/packages/6a/9f/130394f9bbe06f4f63e22641d32fc9b202b7e251c9aef4db044324dac493/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a", size = 217723, upload-time = "2026-04-02T09:27:02.021Z" },
{ url = "https://files.pythonhosted.org/packages/73/55/c469897448a06e49f8fa03f6caae97074fde823f432a98f979cc42b90e69/charset_normalizer-3.4.7-cp313-cp313-win32.whl", hash = "sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e", size = 148085, upload-time = "2026-04-02T09:27:03.192Z" },
{ url = "https://files.pythonhosted.org/packages/5d/78/1b74c5bbb3f99b77a1715c91b3e0b5bdb6fe302d95ace4f5b1bec37b0167/charset_normalizer-3.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110", size = 158819, upload-time = "2026-04-02T09:27:04.454Z" },
{ url = "https://files.pythonhosted.org/packages/68/86/46bd42279d323deb8687c4a5a811fd548cb7d1de10cf6535d099877a9a9f/charset_normalizer-3.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b", size = 147915, upload-time = "2026-04-02T09:27:05.971Z" },
{ url = "https://files.pythonhosted.org/packages/97/c8/c67cb8c70e19ef1960b97b22ed2a1567711de46c4ddf19799923adc836c2/charset_normalizer-3.4.7-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0", size = 309234, upload-time = "2026-04-02T09:27:07.194Z" },
{ url = "https://files.pythonhosted.org/packages/99/85/c091fdee33f20de70d6c8b522743b6f831a2f1cd3ff86de4c6a827c48a76/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a", size = 208042, upload-time = "2026-04-02T09:27:08.749Z" },
{ url = "https://files.pythonhosted.org/packages/87/1c/ab2ce611b984d2fd5d86a5a8a19c1ae26acac6bad967da4967562c75114d/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b", size = 228706, upload-time = "2026-04-02T09:27:09.951Z" },
{ url = "https://files.pythonhosted.org/packages/a8/29/2b1d2cb00bf085f59d29eb773ce58ec2d325430f8c216804a0a5cd83cbca/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41", size = 224727, upload-time = "2026-04-02T09:27:11.175Z" },
{ url = "https://files.pythonhosted.org/packages/47/5c/032c2d5a07fe4d4855fea851209cca2b6f03ebeb6d4e3afdb3358386a684/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e", size = 215882, upload-time = "2026-04-02T09:27:12.446Z" },
{ url = "https://files.pythonhosted.org/packages/2c/c2/356065d5a8b78ed04499cae5f339f091946a6a74f91e03476c33f0ab7100/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae", size = 200860, upload-time = "2026-04-02T09:27:13.721Z" },
{ url = "https://files.pythonhosted.org/packages/0c/cd/a32a84217ced5039f53b29f460962abb2d4420def55afabe45b1c3c7483d/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18", size = 211564, upload-time = "2026-04-02T09:27:15.272Z" },
{ url = "https://files.pythonhosted.org/packages/44/86/58e6f13ce26cc3b8f4a36b94a0f22ae2f00a72534520f4ae6857c4b81f89/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b", size = 211276, upload-time = "2026-04-02T09:27:16.834Z" },
{ url = "https://files.pythonhosted.org/packages/8f/fe/d17c32dc72e17e155e06883efa84514ca375f8a528ba2546bee73fc4df81/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356", size = 201238, upload-time = "2026-04-02T09:27:18.229Z" },
{ url = "https://files.pythonhosted.org/packages/6a/29/f33daa50b06525a237451cdb6c69da366c381a3dadcd833fa5676bc468b3/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab", size = 230189, upload-time = "2026-04-02T09:27:19.445Z" },
{ url = "https://files.pythonhosted.org/packages/b6/6e/52c84015394a6a0bdcd435210a7e944c5f94ea1055f5cc5d56c5fe368e7b/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46", size = 211352, upload-time = "2026-04-02T09:27:20.79Z" },
{ url = "https://files.pythonhosted.org/packages/8c/d7/4353be581b373033fb9198bf1da3cf8f09c1082561e8e922aa7b39bf9fe8/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44", size = 227024, upload-time = "2026-04-02T09:27:22.063Z" },
{ url = "https://files.pythonhosted.org/packages/30/45/99d18aa925bd1740098ccd3060e238e21115fffbfdcb8f3ece837d0ace6c/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72", size = 217869, upload-time = "2026-04-02T09:27:23.486Z" },
{ url = "https://files.pythonhosted.org/packages/5c/05/5ee478aa53f4bb7996482153d4bfe1b89e0f087f0ab6b294fcf92d595873/charset_normalizer-3.4.7-cp314-cp314-win32.whl", hash = "sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10", size = 148541, upload-time = "2026-04-02T09:27:25.146Z" },
{ url = "https://files.pythonhosted.org/packages/48/77/72dcb0921b2ce86420b2d79d454c7022bf5be40202a2a07906b9f2a35c97/charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl", hash = "sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f", size = 159634, upload-time = "2026-04-02T09:27:26.642Z" },
{ url = "https://files.pythonhosted.org/packages/c6/a3/c2369911cd72f02386e4e340770f6e158c7980267da16af8f668217abaa0/charset_normalizer-3.4.7-cp314-cp314-win_arm64.whl", hash = "sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246", size = 148384, upload-time = "2026-04-02T09:27:28.271Z" },
{ url = "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24", size = 330133, upload-time = "2026-04-02T09:27:29.474Z" },
{ url = "https://files.pythonhosted.org/packages/8d/da/96975ddb11f8e977f706f45cddd8540fd8242f71ecdb5d18a80723dcf62c/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79", size = 216257, upload-time = "2026-04-02T09:27:30.793Z" },
{ url = "https://files.pythonhosted.org/packages/e5/e8/1d63bf8ef2d388e95c64b2098f45f84758f6d102a087552da1485912637b/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960", size = 234851, upload-time = "2026-04-02T09:27:32.44Z" },
{ url = "https://files.pythonhosted.org/packages/9b/40/e5ff04233e70da2681fa43969ad6f66ca5611d7e669be0246c4c7aaf6dc8/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4", size = 233393, upload-time = "2026-04-02T09:27:34.03Z" },
{ url = "https://files.pythonhosted.org/packages/be/c1/06c6c49d5a5450f76899992f1ee40b41d076aee9279b49cf9974d2f313d5/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e", size = 223251, upload-time = "2026-04-02T09:27:35.369Z" },
{ url = "https://files.pythonhosted.org/packages/2b/9f/f2ff16fb050946169e3e1f82134d107e5d4ae72647ec8a1b1446c148480f/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1", size = 206609, upload-time = "2026-04-02T09:27:36.661Z" },
{ url = "https://files.pythonhosted.org/packages/69/d5/a527c0cd8d64d2eab7459784fb4169a0ac76e5a6fc5237337982fd61347e/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44", size = 220014, upload-time = "2026-04-02T09:27:38.019Z" },
{ url = "https://files.pythonhosted.org/packages/7e/80/8a7b8104a3e203074dc9aa2c613d4b726c0e136bad1cc734594b02867972/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e", size = 218979, upload-time = "2026-04-02T09:27:39.37Z" },
{ url = "https://files.pythonhosted.org/packages/02/9a/b759b503d507f375b2b5c153e4d2ee0a75aa215b7f2489cf314f4541f2c0/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3", size = 209238, upload-time = "2026-04-02T09:27:40.722Z" },
{ url = "https://files.pythonhosted.org/packages/c2/4e/0f3f5d47b86bdb79256e7290b26ac847a2832d9a4033f7eb2cd4bcf4bb5b/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0", size = 236110, upload-time = "2026-04-02T09:27:42.33Z" },
{ url = "https://files.pythonhosted.org/packages/96/23/bce28734eb3ed2c91dcf93abeb8a5cf393a7b2749725030bb630e554fdd8/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e", size = 219824, upload-time = "2026-04-02T09:27:43.924Z" },
{ url = "https://files.pythonhosted.org/packages/2c/6f/6e897c6984cc4d41af319b077f2f600fc8214eb2fe2d6bcb79141b882400/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb", size = 233103, upload-time = "2026-04-02T09:27:45.348Z" },
{ url = "https://files.pythonhosted.org/packages/76/22/ef7bd0fe480a0ae9b656189ec00744b60933f68b4f42a7bb06589f6f576a/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe", size = 225194, upload-time = "2026-04-02T09:27:46.706Z" },
{ url = "https://files.pythonhosted.org/packages/c5/a7/0e0ab3e0b5bc1219bd80a6a0d4d72ca74d9250cb2382b7c699c147e06017/charset_normalizer-3.4.7-cp314-cp314t-win32.whl", hash = "sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0", size = 159827, upload-time = "2026-04-02T09:27:48.053Z" },
{ url = "https://files.pythonhosted.org/packages/7a/1d/29d32e0fb40864b1f878c7f5a0b343ae676c6e2b271a2d55cc3a152391da/charset_normalizer-3.4.7-cp314-cp314t-win_amd64.whl", hash = "sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c", size = 174168, upload-time = "2026-04-02T09:27:49.795Z" },
{ url = "https://files.pythonhosted.org/packages/de/32/d92444ad05c7a6e41fb2036749777c163baf7a0301a040cb672d6b2b1ae9/charset_normalizer-3.4.7-cp314-cp314t-win_arm64.whl", hash = "sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d", size = 153018, upload-time = "2026-04-02T09:27:51.116Z" },
{ url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" },
]
[[package]]
name = "colorama"
version = "0.4.6"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
]
[[package]]
name = "decorator"
version = "5.2.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" },
]
[[package]]
name = "deltabot-cli"
version = "8.1.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "appdirs" },
{ name = "deltachat2", extra = ["full"] },
{ name = "rich" },
]
sdist = { url = "https://files.pythonhosted.org/packages/8c/3c/b380bc6c2bf3d76d7d39faec57e022d25447d0503c04109f5bc1ca0c779a/deltabot_cli-8.1.0.tar.gz", hash = "sha256:53bf983d9a76381deb23506d232de619993b82642d76ead201a1beef27ebe98e", size = 14886, upload-time = "2026-04-14T02:09:42.214Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/7b/64/cfecb6303fd90be9897ba6bb3184955996368ceff02a49853a31fff54b92/deltabot_cli-8.1.0-py3-none-any.whl", hash = "sha256:691bf62266628f6ef25788cba2054ab6fb2774e1918c8a7fb66be6e3e135fa3a", size = 12694, upload-time = "2026-04-14T02:09:41.303Z" },
]
[[package]]
name = "deltachat-rpc-server"
version = "2.49.0"
source = { registry = "https://pypi.org/simple" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b6/5c/5cc080e47555116f34c9c14c8c8bad14568499b148bcbb1c736447b9afa5/deltachat_rpc_server-2.49.0-py3-none-android_21_arm64_v8a.whl", hash = "sha256:a5a6aed57436766794764aa90897eddd700bffca979c924725a3dff3b40ccca3", size = 11455996, upload-time = "2026-04-13T09:11:05.039Z" },
{ url = "https://files.pythonhosted.org/packages/b2/6c/1641b807f7a880a495c58f76f6f333e0db46a1a891cea155d1077e66a831/deltachat_rpc_server-2.49.0-py3-none-android_21_armeabi_v7a.whl", hash = "sha256:100379ca2c29aaa433dd536038ee5603f3ab36517777b0d5923a2d4bd1e4b701", size = 9712072, upload-time = "2026-04-13T09:11:07.88Z" },
{ url = "https://files.pythonhosted.org/packages/2a/1f/c5c61a1ffd3c2369848db9cd1e83989257b3b5836b07d61c0de9b51c515d/deltachat_rpc_server-2.49.0-py3-none-linux_armv6l.whl", hash = "sha256:4a0719575130ea8d96eeceb4b0c2eca4de276c9b0aa42d6a048438754107003f", size = 10558722, upload-time = "2026-04-13T09:11:10.355Z" },
{ url = "https://files.pythonhosted.org/packages/2c/ab/65d7f305cca0762a17bcd0686650d33e5b8c2dd66e9a304633066677344e/deltachat_rpc_server-2.49.0-py3-none-linux_armv7l.manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:449c9b714a520b60f843735bdd3fb4be891dd08c15db3e6e1bebb643a7be9178", size = 10457845, upload-time = "2026-04-13T09:11:12.749Z" },
{ url = "https://files.pythonhosted.org/packages/6d/14/f47884b55bf267115e89826db02ff65a4b409658fc1190c9b793dcd65c7f/deltachat_rpc_server-2.49.0-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:7c6897c9beb0b75ecbbddd9417f05906a5646e61fe7f6f4bec0e1392055c6871", size = 9929478, upload-time = "2026-04-13T09:11:15.567Z" },
{ url = "https://files.pythonhosted.org/packages/a3/e1/8a0c2657d53b9c463d94b749481cd616a4ba9f8a9b67daa5b506019fd9b3/deltachat_rpc_server-2.49.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b62592f0217ff2de23fd363c0fb47b17a0de94fb4e7f21e2aa5a7196cd87d6eb", size = 9743447, upload-time = "2026-04-13T09:11:18.209Z" },
{ url = "https://files.pythonhosted.org/packages/aa/f6/59f4e09dbd6f6f9ada62436ad0a7d16072412bce65f071fa20723c9b024b/deltachat_rpc_server-2.49.0-py3-none-manylinux_2_12_i686.manylinux2010_i686.musllinux_1_1_i686.whl", hash = "sha256:687315e0e9a753c42ae1ad241013b72e863fe267297e17d26f141b277733452a", size = 11172948, upload-time = "2026-04-13T09:11:21.043Z" },
{ url = "https://files.pythonhosted.org/packages/9a/f1/507556562cf52606b726b2deafb052d90161a3ebf195f15448b807a9311f/deltachat_rpc_server-2.49.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:84e1b89cfcfd0be07c9d43fa830f9ebdd84eb6d5c71e558c19ee81d18d7c23c1", size = 11409855, upload-time = "2026-04-13T09:11:23.72Z" },
{ url = "https://files.pythonhosted.org/packages/bd/e1/b6b9defefd8d5e5896993ec6be5dafeb3e5c44da6db1b60d671553d8a618/deltachat_rpc_server-2.49.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.musllinux_1_1_x86_64.whl", hash = "sha256:2aa8f41aebe7a502bd30e72f8009a199f4f91948deffcfab90b71c5dbbee9691", size = 11745522, upload-time = "2026-04-13T09:11:26.426Z" },
{ url = "https://files.pythonhosted.org/packages/df/e9/ca3978f05a4edb450da387275fa0401bd26f80d22e339b0b7e0107ab76ea/deltachat_rpc_server-2.49.0-py3-none-win32.whl", hash = "sha256:a80cb2171685060d7c48f90013ecf5e0239fa5b1b6c3598c37d593903438a4d9", size = 10527871, upload-time = "2026-04-13T09:11:29.359Z" },
{ url = "https://files.pythonhosted.org/packages/ff/d3/3eb5b1ad0dd193288ced6ac44b9d3741768b17ffdca8cc13bd53cc994802/deltachat_rpc_server-2.49.0-py3-none-win_amd64.whl", hash = "sha256:324e480f201a9477b045571aa9baf08ee07b5eb53ef7ae3b64efb689efa124fd", size = 10546684, upload-time = "2026-04-13T09:11:32.141Z" },
]
[[package]]
name = "deltachat2"
version = "0.10.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f0/c1/f025ab95da941fdaf49a47978974c3666d681625b5f584b2782c14ca1f31/deltachat2-0.10.0.tar.gz", hash = "sha256:b27f2f46cfb378b276a530f7f8eb475aa113339d2136825539332823cbb5a389", size = 19563, upload-time = "2026-04-13T23:44:31.639Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ec/ad/0eb9c72275c8178a2668da906f2635c90a97a7c5cecbfb2624cdc7cc1048/deltachat2-0.10.0-py3-none-any.whl", hash = "sha256:b20ff04b295ddebd981bb9be9185868ce5448c83b0ddfb064bef77706a3dbd45", size = 19062, upload-time = "2026-04-13T23:44:30.492Z" },
]
[package.optional-dependencies]
full = [
{ name = "deltachat-rpc-server" },
]
[[package]]
name = "executing"
version = "2.2.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488, upload-time = "2025-09-01T09:48:10.866Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" },
]
[[package]]
name = "idna"
version = "3.13"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ce/cc/762dfb036166873f0059f3b7de4565e1b5bc3d6f28a414c13da27e442f99/idna-3.13.tar.gz", hash = "sha256:585ea8fe5d69b9181ec1afba340451fba6ba764af97026f92a91d4eef164a242", size = 194210, upload-time = "2026-04-22T16:42:42.314Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/5d/13/ad7d7ca3808a898b4612b6fe93cde56b53f3034dcde235acb1f0e1df24c6/idna-3.13-py3-none-any.whl", hash = "sha256:892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3", size = 68629, upload-time = "2026-04-22T16:42:40.909Z" },
]
[[package]]
name = "ipdb"
version = "0.13.13"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "decorator" },
{ name = "ipython" },
]
sdist = { url = "https://files.pythonhosted.org/packages/3d/1b/7e07e7b752017f7693a0f4d41c13e5ca29ce8cbcfdcc1fd6c4ad8c0a27a0/ipdb-0.13.13.tar.gz", hash = "sha256:e3ac6018ef05126d442af680aad863006ec19d02290561ac88b8b1c0b0cfc726", size = 17042, upload-time = "2023-03-09T15:40:57.487Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/0c/4c/b075da0092003d9a55cf2ecc1cae9384a1ca4f650d51b00fc59875fe76f6/ipdb-0.13.13-py3-none-any.whl", hash = "sha256:45529994741c4ab6d2388bfa5d7b725c2cf7fe9deffabdb8a6113aa5ed449ed4", size = 12130, upload-time = "2023-03-09T15:40:55.021Z" },
]
[[package]]
name = "ipython"
version = "9.13.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
{ name = "decorator" },
{ name = "ipython-pygments-lexers" },
{ name = "jedi" },
{ name = "matplotlib-inline" },
{ name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
{ name = "prompt-toolkit" },
{ name = "psutil" },
{ name = "pygments" },
{ name = "stack-data" },
{ name = "traitlets" },
]
sdist = { url = "https://files.pythonhosted.org/packages/cd/c4/87cda5842cf5c31837c06ddb588e11c3c35d8ece89b7a0108c06b8c9b00a/ipython-9.13.0.tar.gz", hash = "sha256:7e834b6afc99f020e3f05966ced34792f40267d64cb1ea9043886dab0dde5967", size = 4430549, upload-time = "2026-04-24T12:24:55.221Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b9/86/3060e8029b7cc505cce9a0137431dda81d0a3fde93a8f0f50ee0bf37a795/ipython-9.13.0-py3-none-any.whl", hash = "sha256:57f9d4639e20818d328d287c7b549af3d05f12486ea8f2e7f73e52a36ec4d201", size = 627274, upload-time = "2026-04-24T12:24:53.038Z" },
]
[[package]]
name = "ipython-pygments-lexers"
version = "1.1.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pygments" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" },
]
[[package]]
name = "jedi"
version = "0.20.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "parso" },
]
sdist = { url = "https://files.pythonhosted.org/packages/46/b7/a3635f6a2d7cf5b5dd98064fc1d5fbbafcb25477bcea204a3a92145d158b/jedi-0.20.0.tar.gz", hash = "sha256:c3f4ccbd276696f4b19c54618d4fb18f9fc24b0aef02acf704b23f487daa1011", size = 3119416, upload-time = "2026-05-01T23:38:47.814Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/9a/93/242e2eab5fe682ffcb8b0084bde703a41d51e17ee0f3a31ff0d9d813620a/jedi-0.20.0-py2.py3-none-any.whl", hash = "sha256:7bdd9c2634f56713299976f4cbd59cb3fa92165cc5e05ea811fb253480728b67", size = 4884812, upload-time = "2026-05-01T23:38:43.919Z" },
]
[[package]]
name = "markdown-it-py"
version = "4.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "mdurl" },
]
sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" },
]
[[package]]
name = "matplotlib-inline"
version = "0.2.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "traitlets" },
]
sdist = { url = "https://files.pythonhosted.org/packages/bd/c0/9f7c9a46090390368a4d7bcb76bb87a4a36c421e4c0792cdb53486ffac7a/matplotlib_inline-0.2.2.tar.gz", hash = "sha256:72f3fe8fce36b70d4a5b612f899090cd0401deddc4ea90e1572b9f4bfb058c79", size = 8150, upload-time = "2026-05-08T17:33:33.49Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/41/09/5b161152e2d90f7b87f781c2e1267494aef9c32498df793f73ad0a0a494a/matplotlib_inline-0.2.2-py3-none-any.whl", hash = "sha256:3c821cf1c209f59fb2d2d64abbf5b23b67bcb2210d663f9918dd851c6da1fcf6", size = 9534, upload-time = "2026-05-08T17:33:32.055Z" },
]
[[package]]
name = "mdurl"
version = "0.1.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
]
[[package]]
name = "parso"
version = "0.8.7"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/30/4b/90c937815137d43ce71ba043cd3566221e9df6b9c805f24b5d138c9d40a7/parso-0.8.7.tar.gz", hash = "sha256:eaaac4c9fdd5e9e8852dc778d2d7405897ec510f2a298071453e5e3a07914bb1", size = 401824, upload-time = "2026-05-01T23:13:02.138Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/99/5d/8268b644392ee874ee82a635cd0df1773de230bde356c38de28e298392cc/parso-0.8.7-py2.py3-none-any.whl", hash = "sha256:a8926eb2a1b915486941fdbd31e86a4baf88fe8c210f25f2f35ecec5b574ca1c", size = 107025, upload-time = "2026-05-01T23:12:58.867Z" },
]
[[package]]
name = "pexpect"
version = "4.9.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "ptyprocess" },
]
sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" },
]
[[package]]
name = "prompt-toolkit"
version = "3.0.52"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "wcwidth" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" },
]
[[package]]
name = "psutil"
version = "7.2.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/aa/c6/d1ddf4abb55e93cebc4f2ed8b5d6dbad109ecb8d63748dd2b20ab5e57ebe/psutil-7.2.2.tar.gz", hash = "sha256:0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372", size = 493740, upload-time = "2026-01-28T18:14:54.428Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/51/08/510cbdb69c25a96f4ae523f733cdc963ae654904e8db864c07585ef99875/psutil-7.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2edccc433cbfa046b980b0df0171cd25bcaeb3a68fe9022db0979e7aa74a826b", size = 130595, upload-time = "2026-01-28T18:14:57.293Z" },
{ url = "https://files.pythonhosted.org/packages/d6/f5/97baea3fe7a5a9af7436301f85490905379b1c6f2dd51fe3ecf24b4c5fbf/psutil-7.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e78c8603dcd9a04c7364f1a3e670cea95d51ee865e4efb3556a3a63adef958ea", size = 131082, upload-time = "2026-01-28T18:14:59.732Z" },
{ url = "https://files.pythonhosted.org/packages/37/d6/246513fbf9fa174af531f28412297dd05241d97a75911ac8febefa1a53c6/psutil-7.2.2-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1a571f2330c966c62aeda00dd24620425d4b0cc86881c89861fbc04549e5dc63", size = 181476, upload-time = "2026-01-28T18:15:01.884Z" },
{ url = "https://files.pythonhosted.org/packages/b8/b5/9182c9af3836cca61696dabe4fd1304e17bc56cb62f17439e1154f225dd3/psutil-7.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:917e891983ca3c1887b4ef36447b1e0873e70c933afc831c6b6da078ba474312", size = 184062, upload-time = "2026-01-28T18:15:04.436Z" },
{ url = "https://files.pythonhosted.org/packages/16/ba/0756dca669f5a9300d0cbcbfae9a4c30e446dfc7440ffe43ded5724bfd93/psutil-7.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:ab486563df44c17f5173621c7b198955bd6b613fb87c71c161f827d3fb149a9b", size = 139893, upload-time = "2026-01-28T18:15:06.378Z" },
{ url = "https://files.pythonhosted.org/packages/1c/61/8fa0e26f33623b49949346de05ec1ddaad02ed8ba64af45f40a147dbfa97/psutil-7.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:ae0aefdd8796a7737eccea863f80f81e468a1e4cf14d926bd9b6f5f2d5f90ca9", size = 135589, upload-time = "2026-01-28T18:15:08.03Z" },
{ url = "https://files.pythonhosted.org/packages/81/69/ef179ab5ca24f32acc1dac0c247fd6a13b501fd5534dbae0e05a1c48b66d/psutil-7.2.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:eed63d3b4d62449571547b60578c5b2c4bcccc5387148db46e0c2313dad0ee00", size = 130664, upload-time = "2026-01-28T18:15:09.469Z" },
{ url = "https://files.pythonhosted.org/packages/7b/64/665248b557a236d3fa9efc378d60d95ef56dd0a490c2cd37dafc7660d4a9/psutil-7.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7b6d09433a10592ce39b13d7be5a54fbac1d1228ed29abc880fb23df7cb694c9", size = 131087, upload-time = "2026-01-28T18:15:11.724Z" },
{ url = "https://files.pythonhosted.org/packages/d5/2e/e6782744700d6759ebce3043dcfa661fb61e2fb752b91cdeae9af12c2178/psutil-7.2.2-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fa4ecf83bcdf6e6c8f4449aff98eefb5d0604bf88cb883d7da3d8d2d909546a", size = 182383, upload-time = "2026-01-28T18:15:13.445Z" },
{ url = "https://files.pythonhosted.org/packages/57/49/0a41cefd10cb7505cdc04dab3eacf24c0c2cb158a998b8c7b1d27ee2c1f5/psutil-7.2.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e452c464a02e7dc7822a05d25db4cde564444a67e58539a00f929c51eddda0cf", size = 185210, upload-time = "2026-01-28T18:15:16.002Z" },
{ url = "https://files.pythonhosted.org/packages/dd/2c/ff9bfb544f283ba5f83ba725a3c5fec6d6b10b8f27ac1dc641c473dc390d/psutil-7.2.2-cp314-cp314t-win_amd64.whl", hash = "sha256:c7663d4e37f13e884d13994247449e9f8f574bc4655d509c3b95e9ec9e2b9dc1", size = 141228, upload-time = "2026-01-28T18:15:18.385Z" },
{ url = "https://files.pythonhosted.org/packages/f2/fc/f8d9c31db14fcec13748d373e668bc3bed94d9077dbc17fb0eebc073233c/psutil-7.2.2-cp314-cp314t-win_arm64.whl", hash = "sha256:11fe5a4f613759764e79c65cf11ebdf26e33d6dd34336f8a337aa2996d71c841", size = 136284, upload-time = "2026-01-28T18:15:19.912Z" },
{ url = "https://files.pythonhosted.org/packages/e7/36/5ee6e05c9bd427237b11b3937ad82bb8ad2752d72c6969314590dd0c2f6e/psutil-7.2.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ed0cace939114f62738d808fdcecd4c869222507e266e574799e9c0faa17d486", size = 129090, upload-time = "2026-01-28T18:15:22.168Z" },
{ url = "https://files.pythonhosted.org/packages/80/c4/f5af4c1ca8c1eeb2e92ccca14ce8effdeec651d5ab6053c589b074eda6e1/psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979", size = 129859, upload-time = "2026-01-28T18:15:23.795Z" },
{ url = "https://files.pythonhosted.org/packages/b5/70/5d8df3b09e25bce090399cf48e452d25c935ab72dad19406c77f4e828045/psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:076a2d2f923fd4821644f5ba89f059523da90dc9014e85f8e45a5774ca5bc6f9", size = 155560, upload-time = "2026-01-28T18:15:25.976Z" },
{ url = "https://files.pythonhosted.org/packages/63/65/37648c0c158dc222aba51c089eb3bdfa238e621674dc42d48706e639204f/psutil-7.2.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0726cecd84f9474419d67252add4ac0cd9811b04d61123054b9fb6f57df6e9e", size = 156997, upload-time = "2026-01-28T18:15:27.794Z" },
{ url = "https://files.pythonhosted.org/packages/8e/13/125093eadae863ce03c6ffdbae9929430d116a246ef69866dad94da3bfbc/psutil-7.2.2-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fd04ef36b4a6d599bbdb225dd1d3f51e00105f6d48a28f006da7f9822f2606d8", size = 148972, upload-time = "2026-01-28T18:15:29.342Z" },
{ url = "https://files.pythonhosted.org/packages/04/78/0acd37ca84ce3ddffaa92ef0f571e073faa6d8ff1f0559ab1272188ea2be/psutil-7.2.2-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b58fabe35e80b264a4e3bb23e6b96f9e45a3df7fb7eed419ac0e5947c61e47cc", size = 148266, upload-time = "2026-01-28T18:15:31.597Z" },
{ url = "https://files.pythonhosted.org/packages/b4/90/e2159492b5426be0c1fef7acba807a03511f97c5f86b3caeda6ad92351a7/psutil-7.2.2-cp37-abi3-win_amd64.whl", hash = "sha256:eb7e81434c8d223ec4a219b5fc1c47d0417b12be7ea866e24fb5ad6e84b3d988", size = 137737, upload-time = "2026-01-28T18:15:33.849Z" },
{ url = "https://files.pythonhosted.org/packages/8c/c7/7bb2e321574b10df20cbde462a94e2b71d05f9bbda251ef27d104668306a/psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee", size = 134617, upload-time = "2026-01-28T18:15:36.514Z" },
]
[[package]]
name = "ptyprocess"
version = "0.7.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" },
]
[[package]]
name = "pure-eval"
version = "0.2.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" },
]
[[package]]
name = "pygments"
version = "2.20.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" },
]
[[package]]
name = "quadnite-bot"
version = "0.1.0"
source = { editable = "." }
dependencies = [
{ name = "deltabot-cli" },
{ name = "requests" },
]
[package.dev-dependencies]
dev = [
{ name = "ipdb" },
]
[package.metadata]
requires-dist = [
{ name = "deltabot-cli", specifier = ">=8.1.0" },
{ name = "requests", specifier = ">=2.33.1" },
]
[package.metadata.requires-dev]
dev = [{ name = "ipdb", specifier = ">=0.13.13" }]
[[package]]
name = "requests"
version = "2.33.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "certifi" },
{ name = "charset-normalizer" },
{ name = "idna" },
{ name = "urllib3" },
]
sdist = { url = "https://files.pythonhosted.org/packages/5f/a4/98b9c7c6428a668bf7e42ebb7c79d576a1c3c1e3ae2d47e674b468388871/requests-2.33.1.tar.gz", hash = "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517", size = 134120, upload-time = "2026-03-30T16:09:15.531Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl", hash = "sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a", size = 64947, upload-time = "2026-03-30T16:09:13.83Z" },
]
[[package]]
name = "rich"
version = "15.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "markdown-it-py" },
{ name = "pygments" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" },
]
[[package]]
name = "stack-data"
version = "0.6.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "asttokens" },
{ name = "executing" },
{ name = "pure-eval" },
]
sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" },
]
[[package]]
name = "traitlets"
version = "5.15.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/1b/22/40f55b26baeab80c2d7b3f1db0682f8954e4617fee7d90ce634022ef05c6/traitlets-5.15.0.tar.gz", hash = "sha256:4fead733f81cf1c4c938e06f8ca4633896833c9d89eff878159457f4d4392971", size = 163197, upload-time = "2026-05-06T08:05:58.016Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/da/98/a9937a969d018a23badfea0b381f66783649d48e0ea6c41923265c3cbeb3/traitlets-5.15.0-py3-none-any.whl", hash = "sha256:fb36a18867a6803deab09f3c5e0fa81bb7b26a5c9e82501c9933f759166eff40", size = 85877, upload-time = "2026-05-06T08:05:55.853Z" },
]
[[package]]
name = "urllib3"
version = "2.7.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" },
]
[[package]]
name = "wcwidth"
version = "0.7.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/2c/ee/afaf0f85a9a18fe47a67f1e4422ed6cf1fe642f0ae0a2f81166231303c52/wcwidth-0.7.0.tar.gz", hash = "sha256:90e3a7ea092341c44b99562e75d09e4d5160fe7a3974c6fb842a101a95e7eed0", size = 182132, upload-time = "2026-05-02T16:04:12.653Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/41/52/e465037f5375f43533d1a80b6923955201596a99142ed524d77b571a1418/wcwidth-0.7.0-py3-none-any.whl", hash = "sha256:5d69154c429a82910e241c738cd0e2976fac8a2dd47a1a805f4afed1c0f136f2", size = 110825, upload-time = "2026-05-02T16:04:11.033Z" },
]