Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
1 MB
Referenced Files
None
Subscribers
None
This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/.busted b/.busted
new file mode 100644
index 0000000..da3b724
--- /dev/null
+++ b/.busted
@@ -0,0 +1,6 @@
+return {
+ _all = {
+ lua = 'lua',
+ ROOT = { 'spec/' }
+ }
+}
diff --git a/.dockerignore b/.dockerignore
index aa62185..f643c64 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,10 +1,12 @@
.git
.env
.vscode
.idea
backups/
downloads/
pgdata/
redisdata/
*.md
+*.rockspec
LICENSE
+spec/
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..b99e0e4
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,41 @@
+name: CI
+
+on:
+ push:
+ branches: [develop, main]
+ pull_request:
+ branches: [develop, main]
+
+jobs:
+ lint-and-test:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Install Lua 5.3
+ uses: leafo/gh-actions-lua@v11
+ with:
+ luaVersion: '5.3'
+
+ - name: Install LuaRocks
+ uses: leafo/gh-actions-luarocks@v4
+
+ - name: Install dependencies
+ run: |
+ luarocks install busted
+ luarocks install luacheck
+ luarocks install telegram-bot-lua
+ luarocks install pgmoon
+ luarocks install redis-lua
+ luarocks install dkjson
+ luarocks install luasocket
+ luarocks install luasec
+ luarocks install luautf8
+
+ - name: Lint
+ run: luacheck src/ spec/ main.lua
+
+ - name: Test
+ run: busted spec/
diff --git a/.luacheckrc b/.luacheckrc
new file mode 100644
index 0000000..8195575
--- /dev/null
+++ b/.luacheckrc
@@ -0,0 +1,14 @@
+std = 'lua53'
+max_line_length = 200
+
+-- Globally ignore: unused self (212), unused loop vars (213),
+-- value assigned to variable is unused (311) - common for error handling
+ignore = { '212', '213', '311' }
+
+-- Test files: busted std, plus allow unused locals (211) for test variables,
+-- setting read-only globals (131) for mocking, empty if branches (542)
+files['spec/'] = {
+ std = 'lua53+busted',
+ max_line_length = 200,
+ ignore = { '211', '212', '213', '311', '122', '131', '142', '143', '542' }
+}
diff --git a/ai.sh b/ai.sh
deleted file mode 100644
index 4ecb6d6..0000000
--- a/ai.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/sh
-if [ ! -f ./configuration.lua ]
-then
- echo "Please insert the required variables into configuration.example.lua. Then, you need to rename configuration.example.lua to configuration.lua!"
-else
- cd helpers/
- while true; do
- lua ai.lua
- echo "AI helper has stopped!"
- sleep 3s
- done
-fi
diff --git a/backup.sh b/backup.sh
deleted file mode 100644
index c81de65..0000000
--- a/backup.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-redis-cli save
-redispassword=$(lua5.3 -e "print(require('configuration').redis.password)")
-redisdb=$(lua5.3 -e "print(require('configuration').redis.db)")
-redishost=$(lua5.3 -e "print(require('configuration').redis.host)")
-redisport=$(lua5.3 -e "print(require('configuration').redis.port)")
-if [ ! -d "backups/" ]; then
- mkdir backups
-fi
-cd backups/
-redisquery="-u $redishost:$redisport -d $redisdb"
-if [ ! $redispassword == "nil" ]; then
- redisquery="-u :$redispassword@$redishost:$redisport -d $redisdb"
-fi
-redis-dump $redisquery > "$(date).json"
-printf "mattata's database has been saved!"
-cd ..
\ No newline at end of file
diff --git a/configuration.example.lua b/configuration.example.lua
deleted file mode 100644
index c13a1c8..0000000
--- a/configuration.example.lua
+++ /dev/null
@@ -1,399 +0,0 @@
---[[
- _ _ _
- _ __ ___ __ _| |_| |_ __ _| |_ __ _
- | '_ ` _ \ / _` | __| __/ _` | __/ _` |
- | | | | | | (_| | |_| || (_| | || (_| |
- |_| |_| |_|\__,_|\__|\__\__,_|\__\__,_|
-
- Configuration file for mattata v1.5
-
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-
- Each value in an array should be comma separated, with the exception of the last value!
- Make sure you always update your configuration file after pulling changes from GitHub!
-
-]]
-
-local configuration = { -- Rename this file to configuration.lua for the bot to work!
- ['bot_token'] = '', -- In order for the bot to actually work, you MUST insert the Telegram
- -- bot API token you received from @BotFather.
- ['connected_message'] = 'Connected to the Telegram bot API!', -- The message to print when the bot is connected to the Telegram bot API
- ['version'] = '1.5', -- the version of mattata, don't change this!
- -- The following two tokens will require you to have setup payments with @BotFather, and
- -- a Stripe account with @stripe!
- ['stripe_live_token'] = '', -- Payment token you receive from @BotFather.
- ['stripe_test_token'] = '', -- Test payment token you receive from @BotFather.
- ['admins'] = { -- Here you need to specify the numerical ID of the users who shall have
- -- FULL control over the bot, this includes access to server files via the lua and shell plugins.
- 221714512
- },
- ['allowlist_plugin_exceptions'] = { -- An array of plugins that will still be used for allowlisted users.
- 'antispam'
- },
- ['beta_plugins'] = { -- An array of plugins that only the configured bot admins are able to use.
- 'array_of_beta_plugins'
- },
- ['permanent_plugins'] = { -- An array of plugins that can't be disabled with /plugins.
- 'plugins',
- 'help',
- 'administration',
- 'about'
- },
- ['updates'] = {
- ['timeout'] = 3, -- timeout in seconds for api.get_updates()
- ['limit'] = 100 -- message limit for api.get_updates() - must be between 1-100
- },
- ['language'] = 'en', -- The two character locale to set your default language to.
- ['log_chat'] = nil, -- This needs to be the numerical identifier of the chat you wish to log
- -- errors into. If it's not a private chat it should begin with a '-' symbol.
- ['log_admin_actions'] = true, -- Should administrative actions be logged? [true/false]
- ['log_channel'] = nil, -- This needs to be the numerical identifier of the channel you wish
- -- to log administrative actions in by default. It should begin with a '-' symbol.
- ['bug_reports_chat'] = nil, -- This needs to be the numerical identifier of the chat you wish to send
- -- bug reports into. If it's not a private chat it should begin with a '-' symbol.
- ['counter_channel'] = nil, -- This needs to be the numerical identifier of the channel you wish
- -- to forward messages into, for use with the /counter command. It should begin with a '-' symbol.
- -- The following directory values should NOT have a "/" at the end!
- ['bot_directory'] = '/path/to/bot',
- ['download_location'] = '/path/to/downloads', -- The location to save all downloaded media to.
- ['fonts_directory'] = '/path/to/fonts', -- The location where fonts are stored for CAPTCHAs
- ['debug'] = true, -- Turn this on to print EVEN MORE information to the terminal.
- ['redis'] = { -- Configurable options for connecting the bot to redis. Do NOT modify
- -- these settings if you don't know what you're doing!
- ['host'] = '127.0.0.1',
- ['port'] = 6379,
- ['password'] = nil,
- ['db'] = 2
- },
- ['keys'] = { -- API keys needed for the full functionality of several plugins.
- ['cats'] = '', -- http://thecatapi.com/api-key-registration.html
- ['translate'] = '', -- https://tech.yandex.com/keys/get/?service=trnsl
- ['lyrics'] = '', -- https://developer.musixmatch.com/admin/applications
- ['lastfm'] = '', -- http://www.last.fm/api/account/create
- ['weather'] = '', -- https://darksky.net/dev/register
- ['youtube'] = '', -- https://console.developers.google.com/apis
- ['maps'] = '', -- https://console.cloud.google.com/google/maps-apis
- ['location'] = '', -- https://opencagedata.com/api
- ['bing'] = '', -- https://datamarket.azure.com/account/keys
- ['flickr'] = '', -- https://www.flickr.com/services/apps/create/noncommercial/
- ['news'] = '', -- https://newsapi.org/
- ['twitch'] = '', -- https://twitchapps.com/tmi/
- ['pastebin'] = '', -- https://pastebin.com/api
- ['dictionary'] = { -- https://developer.oxforddictionaries.com/
- ['id'] = '',
- ['key'] = ''
- },
- ['adfly'] = { -- https://ay.gy/publisher/tools#tools-api
- ['api_key'] = '',
- ['user_id'] = '',
- ['secret_key'] = ''
- },
- ['pasteee'] = '', -- https://paste.ee/
- ['google'] = { -- https://console.developers.google.com/apis
- ['api_key'] = '',
- ['cse_key'] = ''
- },
- ['steam'] = '', -- https://steamcommunity.com/dev/apikey
- ['spotify'] = { -- https://developer.spotify.com/my-applications/#!/applications/create
- ['client_id'] = '',
- ['client_secret'] = '',
- ['redirect_uri'] = 'https://t.me/mattatabot?start='
- },
- ['twitter'] = { -- https://apps.twitter.com/app/new
- ['consumer_key'] = '',
- ['consumer_secret'] = ''
- },
- ['imgur'] = { -- https://api.imgur.com/oauth2/addclient
- ['client_id'] = '',
- ['client_secret'] = ''
- },
- ['spamwatch'] = '', -- https://t.me/SpamWatchSupport
- ['wolframalpha'] = '', -- https://developer.wolframalpha.com/portal/myapps/
- ['movies'] = {
- ['omdb'] = '', -- http://www.omdbapi.com/apikey.aspx
- ['poster'] = '' -- https://www.myapifilms.com/token.do
- },
- ['transcribe'] = '' -- https://wit.ai/v2
- },
- ['errors'] = { -- Messages to provide a more user-friendly approach to errors.
- ['connection'] = 'Connection error.',
- ['results'] = 'I couldn\'t find any results for that.',
- ['supergroup'] = 'This command can only be used in supergroups.',
- ['admin'] = 'You need to be a moderator or an administrator in this chat in order to use this command.',
- ['unknown'] = 'I don\'t recognise that user. If you would like to teach me who they are, forward a message from them to any chat that I\'m in.',
- ['generic'] = 'An unexpected error occured. Please report this error using /bugreport.'
- },
- ['limits'] = {
- ['bing'] = {
- ['private'] = 15,
- ['public'] = 7
- },
- ['stackoverflow'] = {
- ['private'] = 12,
- ['public'] = 8
- },
- ['reddit'] = {
- ['private'] = 8,
- ['public'] = 4
- },
- ['chatroulette'] = 512,
- ['copypasta'] = 300,
- ['drawtext'] = 1000,
- ['help'] = {
- ['per_page'] = 4
- },
- ['nick'] = 128,
- ['plugins'] = {
- ['per_page'] = 18,
- ['columns'] = 2
- }
- },
- ['administration'] = { -- Values used in administrative plugins
- ['warnings'] = {
- ['maximum'] = 10,
- ['minimum'] = 2,
- ['default'] = 3
- },
- ['captcha'] = {
- ['length'] = {
- ['min'] = 4,
- ['max'] = 10,
- ['default'] = 7
- },
- ['size'] = {
- ['min'] = 20,
- ['max'] = 50,
- ['default'] = 40
- },
- ['timeout'] = {
- ['min'] = 1,
- ['max'] = 60,
- ['default'] = 5
- }
- },
- ['allowed_links'] = {
- 'username',
- 'telegram',
- 'mattata',
- 'admin',
- 'admins'
- },
- ['aliases'] = {
- ['length'] = {
- ['min'] = 1,
- ['max'] = 64
- },
- ['total'] = 150
- },
- ['store_chat_members'] = true,
- ['global_antispam'] = { -- normal antispam is processed in plugins/antispam.mattata
- ['ttl'] = 5, -- amount of seconds to process the messages in
- ['message_warning_amount'] = 10, -- amount of messages a user can send in the TTL until they're warned
- ['message_allowlist_amount'] = 25, -- amount of messages a user can send in the TTL until they're allowlisted
- ['allowlist_length'] = 86400, -- amount (in seconds) to allowlist the user for (set it to -1 if you want it forever)
- ['max_code_length'] = 64 -- maximum length of code or pre entities that are allowed with "remove pasted code" setting on
- },
- ['default'] = {
- ['antispam'] = {
- ['text'] = 8,
- ['forwarded'] = 16,
- ['sticker'] = 4,
- ['photo'] = 4,
- ['video'] = 4,
- ['location'] = 4,
- ['voice'] = 4,
- ['game'] = 2,
- ['venue'] = 4,
- ['video_note'] = 4,
- ['invoice'] = 2,
- ['contact'] = 2,
- ['dice'] = 1,
- ['poll'] = 1
- }
- },
- ['feds'] = {
- ['group_limit'] = 3,
- ['shortened_feds'] = {
- ['name'] = 'uuid'
- }
- }
- },
- ['join_messages'] = { -- Values used in plugins/administration.lua.
- 'Welcome, NAME!',
- 'Hello, NAME!',
- 'Enjoy your stay, NAME!',
- 'I\'m glad you joined, NAME!',
- 'Howdy, NAME!',
- 'Hi, NAME!'
- },
- ['groups'] = {
- ['name'] = 't.me/username'
- },
- ['sort_groups'] = true, -- Decides whether groups will be sorted by name in /groups.
- ['stickers'] = { -- Values used in mattata.lua, for administrative plugin functionality.
- -- These are the file_id values for stickers which are binded to the relevant command.
- ['ban'] = {
- 'AgAD0AIAAlAYNw0',
- 'AgADzwIAAlAYNw0'
- },
- ['warn'] = {
- 'AgAD0QIAAlAYNw0',
- 'AgAD0gIAAlAYNw0'
- },
- ['kick'] = {
- 'AgAD0wIAAlAYNw0'
- }
- },
- ['slaps'] = {
- '{THEM} was shot by {ME}.',
- '{THEM} was pricked to death.',
- '{THEM} walked into a cactus while trying to escape {ME}.',
- '{THEM} drowned.',
- '{THEM} drowned whilst trying to escape {ME}.',
- '{THEM} blew up.',
- '{THEM} was blown up by {ME}.',
- '{THEM} hit the ground too hard.',
- '{THEM} fell from a high place.',
- '{THEM} fell off a ladder.',
- '{THEM} fell into a patch of cacti.',
- '{THEM} was doomed to fall by {ME}.',
- '{THEM} was blown from a high place by {ME}.',
- '{THEM} was squashed by a falling anvil.',
- '{THEM} went up in flames.',
- '{THEM} burned to death.',
- '{THEM} was burnt to a crisp whilst fighting {ME}.',
- '{THEM} walked into a fire whilst fighting {ME}.',
- '{THEM} tried to swim in lava.',
- '{THEM} tried to swim in lava whilst trying to escape {ME}.',
- '{THEM} was struck by lightning.',
- '{THEM} was slain by {ME}.',
- '{THEM} got finished off by {ME}.',
- '{THEM} was killed by magic.',
- '{THEM} was killed by {ME} using magic.',
- '{THEM} starved to death.',
- '{THEM} suffocated in a wall.',
- '{THEM} fell out of the world.',
- '{THEM} was knocked into the void by {ME}.',
- '{THEM} withered away.',
- '{THEM} was pummeled by {ME}.',
- '{THEM} was fragged by {ME}.',
- '{THEM} was desynchronized.',
- '{THEM} was wasted.',
- '{THEM} was busted.',
- '{THEM}\'s bones are scraped clean by the desolate wind.',
- '{THEM} has died of dysentery.',
- '{THEM} fainted.',
- '{THEM} is out of usable Pokemon! {THEM} whited out!',
- '{THEM} is out of usable Pokemon! {THEM} blacked out!',
- '{THEM} whited out!',
- '{THEM} blacked out!',
- '{THEM} says goodbye to this cruel world.',
- '{THEM} got rekt.',
- '{THEM} was sawn in half by {ME}.',
- '{THEM} died. I blame {ME}.',
- '{THEM} was axe-murdered by {ME}.',
- '{THEM}\'s melon was split by {ME}.',
- '{THEM} was sliced and diced by {ME}.',
- '{THEM} was split from crotch to sternum by {ME}.',
- '{THEM}\'s death put another notch in {ME}\'s axe.',
- '{THEM} died impossibly!',
- '{THEM} died from {ME}\'s mysterious tropical disease.',
- '{THEM} escaped infection by dying.',
- '{THEM} played hot-potato with a grenade.',
- '{THEM} was knifed by {ME}.',
- '{THEM} fell on his sword.',
- '{THEM} ate a grenade.',
- '{THEM}\'s parents got shot by {ME}.',
- '{THEM} practiced being {ME}\'s clay pigeon.',
- '{THEM} is what\'s for dinner!',
- '{THEM} was terminated by {ME}.',
- '{THEM} was shot before being thrown out of a plane.',
- '{THEM} was not invincible.',
- '{THEM} has encountered an error.',
- '{THEM} died and reincarnated as a goat.',
- '{ME} threw {THEM} off a building.',
- '{THEM} is sleeping with the fishes.',
- '{THEM} got a premature burial.',
- '{ME} replaced all of {THEM}\'s music with Nickelback.',
- '{ME} spammed {THEM}\'s email.',
- '{ME} cut {THEM}\'s genitals off with a rusty pair of scissors!',
- '{ME} made {THEM} a knuckle sandwich.',
- '{ME} slapped {THEM} with pure nothing.',
- '{ME} hit {THEM} with a small, interstellar spaceship.',
- '{THEM} was quickscoped by {ME}.',
- '{ME} put {THEM} in check-mate.',
- '{ME} RSA-encrypted {THEM} and deleted the private key.',
- '{ME} put {THEM} in the friendzone.',
- '{ME} molested {THEM} in a shed.',
- '{ME} slaps {THEM} with a DMCA takedown request!',
- '{THEM} became a corpse blanket for {ME}.',
- 'Death is when the monsters get you. Death comes for {THEM}.',
- 'Cowards die many times before their death. {THEM} never tasted death but once.',
- '{THEM} died of hospital gangrene.',
- '{THEM} got a house call from Doctor {ME}.',
- '{ME} beheaded {THEM}.',
- '{THEM} got stoned...by an angry mob.',
- '{ME} sued the pants off {THEM}.',
- '{THEM} was impeached.',
- '{THEM} was beaten to a pulp by {ME}.',
- '{THEM} was forced to have cheeky bum sex with {ME}!',
- '{THEM} was one-hit KO\'d by {ME}.',
- '{ME} sent {THEM} to /dev/null.',
- '{ME} sent {THEM} down the memory hole.',
- '{THEM} was a mistake.',
- '{THEM} is a failed abortion.',
- '{THEM}\'s birth certificate is just an apology letter from their local condom dispensary.',
- '\'{THEM} was a mistake.\' - {ME}',
- '{ME} checkmated {THEM} in two moves.',
- '{THEM} was brutally raped by {ME}.'
- }
-}
-
-local get_plugins = function(extension, directory)
- extension = extension and tostring(extension) or 'lua'
- if extension:match('^%.') then
- extension = extension:match('^%.(.-)$')
- end
- directory = directory and tostring(directory) or 'plugins'
- if directory:match('/$') then
- directory = directory:match('^(.-)/$')
- end
- local plugins = {}
- local list = io.popen('ls ' .. directory .. '/')
- local all = list:read('*all')
- list:close()
- for plugin in all:gmatch('[%w_-]+%.' .. extension .. ' ?') do
- plugin = plugin:match('^([%w_-]+)%.' .. extension .. ' ?$')
- table.insert(plugins, plugin)
- end
- return plugins
-end
-
-local get_fonts = function()
- local fonts = {}
- local list = io.popen('ls fonts/')
- local all = list:read('*all')
- list:close()
- for font in all:gmatch('%a+') do
- table.insert(fonts, font)
- end
- return fonts
-end
-
-configuration.plugins = get_plugins()
-configuration.administrative_plugins = get_plugins(nil, 'plugins/administration')
-configuration.administration.captcha.files = get_fonts()
-for _, v in pairs(configuration.administrative_plugins) do
- table.insert(configuration.plugins, v)
-end
-
-return configuration
-
---[[
-
- End of configuration, you're good to go.
- Use `./launch.sh` to start the bot.
- If you can't execute the script, try running `chmod +x launch.sh`
-
-]]
\ No newline at end of file
diff --git a/credits.txt b/credits.txt
deleted file mode 100644
index 4beeefc..0000000
--- a/credits.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-I'd like to thank the following people for their support, feedback and ideas:
-@aaomidi
-@bo0tzz
-@caidens
-@danogentili
-@DespeoN
-@eaglezz11
-@emcakes2
-@enotly
-@FabianPastor
-@Floodie_Wowers
-@Floofy_Fox
-@hstntn
-@JuanPotato
-@JustaDebianDistro
-@kiritjom
-@marcsello
-@MazenK
-@nickrobson
-@nootnootnootnootnoot
-@POTUS
-@semangkasegar
-@T3CHNO
-@TheWiseOwl
-@topkecleon
-@Vontus
-@xenial
-@xxdamage
-@zackpollard
-@Zenexer
-There are more that I've probably forgotten, and some don't have usernames. Contact me on Telegram if you believe you should be on here!
\ No newline at end of file
diff --git a/fonts.sh b/fonts.sh
deleted file mode 100644
index 06806ba..0000000
--- a/fonts.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-for x in fonts/*.ttf; do
- mkdir "${x%.*}" && mv "$x" "${x%.*}"
-done
diff --git a/fonts/alef/alef.ttf b/fonts/alef/alef.ttf
deleted file mode 100644
index 3390fb9..0000000
Binary files a/fonts/alef/alef.ttf and /dev/null differ
diff --git a/fonts/algerian/algerian.ttf b/fonts/algerian/algerian.ttf
deleted file mode 100644
index dcc72ae..0000000
Binary files a/fonts/algerian/algerian.ttf and /dev/null differ
diff --git a/fonts/antiqua/antiqua.ttf b/fonts/antiqua/antiqua.ttf
deleted file mode 100644
index d52046c..0000000
Binary files a/fonts/antiqua/antiqua.ttf and /dev/null differ
diff --git a/fonts/arial/arial.ttf b/fonts/arial/arial.ttf
deleted file mode 100644
index 886789b..0000000
Binary files a/fonts/arial/arial.ttf and /dev/null differ
diff --git a/fonts/bauhaus/bauhaus.ttf b/fonts/bauhaus/bauhaus.ttf
deleted file mode 100644
index 42c3238..0000000
Binary files a/fonts/bauhaus/bauhaus.ttf and /dev/null differ
diff --git a/fonts/britanic/britanic.ttf b/fonts/britanic/britanic.ttf
deleted file mode 100644
index e98502b..0000000
Binary files a/fonts/britanic/britanic.ttf and /dev/null differ
diff --git a/fonts/calibri/calibri.ttf b/fonts/calibri/calibri.ttf
deleted file mode 100644
index aac4726..0000000
Binary files a/fonts/calibri/calibri.ttf and /dev/null differ
diff --git a/fonts/cambria/cambria.ttf b/fonts/cambria/cambria.ttf
deleted file mode 100644
index c70283c..0000000
Binary files a/fonts/cambria/cambria.ttf and /dev/null differ
diff --git a/fonts/cantarell/cantarell.ttf b/fonts/cantarell/cantarell.ttf
deleted file mode 100644
index ff7a11d..0000000
Binary files a/fonts/cantarell/cantarell.ttf and /dev/null differ
diff --git a/fonts/centaur/centaur.ttf b/fonts/centaur/centaur.ttf
deleted file mode 100644
index 1c2abac..0000000
Binary files a/fonts/centaur/centaur.ttf and /dev/null differ
diff --git a/fonts/century/century.ttf b/fonts/century/century.ttf
deleted file mode 100644
index cb46e46..0000000
Binary files a/fonts/century/century.ttf and /dev/null differ
diff --git a/fonts/chiller/chiller.ttf b/fonts/chiller/chiller.ttf
deleted file mode 100644
index 3ebfa84..0000000
Binary files a/fonts/chiller/chiller.ttf and /dev/null differ
diff --git a/fonts/comic/comic.ttf b/fonts/comic/comic.ttf
deleted file mode 100644
index 831e3d8..0000000
Binary files a/fonts/comic/comic.ttf and /dev/null differ
diff --git a/fonts/consolas/consolas.ttf b/fonts/consolas/consolas.ttf
deleted file mode 100644
index e881ca4..0000000
Binary files a/fonts/consolas/consolas.ttf and /dev/null differ
diff --git a/fonts/corbel/corbel.ttf b/fonts/corbel/corbel.ttf
deleted file mode 100644
index 34fd5aa..0000000
Binary files a/fonts/corbel/corbel.ttf and /dev/null differ
diff --git a/fonts/courier/courier.ttf b/fonts/courier/courier.ttf
deleted file mode 100644
index 46a0712..0000000
Binary files a/fonts/courier/courier.ttf and /dev/null differ
diff --git a/fonts/curlz/curlz.ttf b/fonts/curlz/curlz.ttf
deleted file mode 100644
index fbcd460..0000000
Binary files a/fonts/curlz/curlz.ttf and /dev/null differ
diff --git a/fonts/dosis/dosis.ttf b/fonts/dosis/dosis.ttf
deleted file mode 100644
index 2f28866..0000000
Binary files a/fonts/dosis/dosis.ttf and /dev/null differ
diff --git a/fonts/ebrima/ebrima.ttf b/fonts/ebrima/ebrima.ttf
deleted file mode 100644
index 50b4894..0000000
Binary files a/fonts/ebrima/ebrima.ttf and /dev/null differ
diff --git a/fonts/forte/forte.ttf b/fonts/forte/forte.ttf
deleted file mode 100644
index f4dfaa7..0000000
Binary files a/fonts/forte/forte.ttf and /dev/null differ
diff --git a/fonts/garamond/garamond.ttf b/fonts/garamond/garamond.ttf
deleted file mode 100644
index 0606e80..0000000
Binary files a/fonts/garamond/garamond.ttf and /dev/null differ
diff --git a/fonts/georgia/georgia.ttf b/fonts/georgia/georgia.ttf
deleted file mode 100644
index 43672d8..0000000
Binary files a/fonts/georgia/georgia.ttf and /dev/null differ
diff --git a/fonts/hack/hack.ttf b/fonts/hack/hack.ttf
deleted file mode 100644
index 92a90cb..0000000
Binary files a/fonts/hack/hack.ttf and /dev/null differ
diff --git a/fonts/lucida/lucida.ttf b/fonts/lucida/lucida.ttf
deleted file mode 100644
index 607f839..0000000
Binary files a/fonts/lucida/lucida.ttf and /dev/null differ
diff --git a/fonts/papyrus/papyrus.ttf b/fonts/papyrus/papyrus.ttf
deleted file mode 100644
index b530afb..0000000
Binary files a/fonts/papyrus/papyrus.ttf and /dev/null differ
diff --git a/fonts/perpetua/perpetua.ttf b/fonts/perpetua/perpetua.ttf
deleted file mode 100644
index 846b3dc..0000000
Binary files a/fonts/perpetua/perpetua.ttf and /dev/null differ
diff --git a/fonts/roboto/roboto.ttf b/fonts/roboto/roboto.ttf
deleted file mode 100644
index 0e58508..0000000
Binary files a/fonts/roboto/roboto.ttf and /dev/null differ
diff --git a/fonts/script/script.ttf b/fonts/script/script.ttf
deleted file mode 100644
index 776f51c..0000000
Binary files a/fonts/script/script.ttf and /dev/null differ
diff --git a/fonts/segoe/segoe.ttf b/fonts/segoe/segoe.ttf
deleted file mode 100644
index 0f52cbd..0000000
Binary files a/fonts/segoe/segoe.ttf and /dev/null differ
diff --git a/fonts/source/source.ttf b/fonts/source/source.ttf
deleted file mode 100644
index 6cbdd36..0000000
Binary files a/fonts/source/source.ttf and /dev/null differ
diff --git a/fonts/stencil/stencil.ttf b/fonts/stencil/stencil.ttf
deleted file mode 100644
index 3cc031b..0000000
Binary files a/fonts/stencil/stencil.ttf and /dev/null differ
diff --git a/fonts/tahoma/tahoma.ttf b/fonts/tahoma/tahoma.ttf
deleted file mode 100644
index b7b7086..0000000
Binary files a/fonts/tahoma/tahoma.ttf and /dev/null differ
diff --git a/fonts/tequila/tequila.ttf b/fonts/tequila/tequila.ttf
deleted file mode 100644
index fb89baf..0000000
Binary files a/fonts/tequila/tequila.ttf and /dev/null differ
diff --git a/fonts/times/times.ttf b/fonts/times/times.ttf
deleted file mode 100644
index a998fee..0000000
Binary files a/fonts/times/times.ttf and /dev/null differ
diff --git a/fonts/vera/vera.ttf b/fonts/vera/vera.ttf
deleted file mode 100644
index 58cd6b5..0000000
Binary files a/fonts/vera/vera.ttf and /dev/null differ
diff --git a/fonts/verdana/verdana.ttf b/fonts/verdana/verdana.ttf
deleted file mode 100644
index 9a34997..0000000
Binary files a/fonts/verdana/verdana.ttf and /dev/null differ
diff --git a/helpers/ai.lua b/helpers/ai.lua
deleted file mode 100644
index 0016b12..0000000
--- a/helpers/ai.lua
+++ /dev/null
@@ -1,249 +0,0 @@
-local ai = {}
-package.path = '/usr/local/share/lua/5.3/?.lua;/usr/local/share/lua/5.3/?/init.lua;/usr/local/lib/lua/5.3/?.lua;/usr/local/lib/lua/5.3/?/init.lua;../?.lua;./?/init.lua'
-local redis = require('libs.redis')
-local configuration = require('configuration')
-local api = require('telegram-bot-lua.core').configure(configuration.bot_token)
-local https = require('ssl.https')
-local url = require('socket.url')
-local json = require('dkjson')
-local ltn12 = require('ltn12')
-local md5 = require('md5')
-
-function ai.unescape(str)
- if not str then
- return false
- end
- str = str:gsub('%%(%x%x)', function(x)
- return tostring(tonumber(x, 16)):char()
- end)
- return str
-end
-
-function ai.cookie()
- local cookie = {}
- local _, res, headers = https.request({
- ['url'] = 'http://www.cleverbot.com/',
- ['method'] = 'GET'
- })
- if res ~= 200 then
- return false
- end
- local set = headers['set-cookie']
- local k, v = set:match('([^%s;=]+)=?([^%s;]*)')
- cookie[k] = v
- return cookie
-end
-
-function ai.talk(message, reply, language)
- if not message then
- return false
- end
- return ai.cleverbot(message, reply, language)
-end
-
-function ai.cleverbot(message, reply, language)
- local cookie = ai.cookie()
- if not cookie then
- return false
- end
- for k, v in pairs(cookie) do
- cookie[#cookie + 1] = k .. '=' .. v
- end
- local query = 'stimulus=' .. url.escape(message)
- if reply then
- query = query .. '&vText2=' .. url.escape(reply)
- end
- query = query .. '&cb_settings_language=' .. language .. '&cb_settings_scripting=no&islearning=1&icognoid=wsf&icognocheck='
- local icognocheck = md5.sumhexa(query:sub(8, 33))
- query = query .. icognocheck
- local agents = {
- 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36',
- 'Mozilla/5.0 CK={} (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko',
- 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36',
- 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763'
- }
- local agent = agents[math.random(#agents)]
- local old_timeout = https.TIMEOUT
- https.TIMEOUT = 5
- local _, res, headers = https.request({
- ['url'] = 'https://www.cleverbot.com/webservicemin?uc=UseOfficialCleverbotAPI&dl=en&flag=&user=&mode=1&alt=0&reac=&emo=&sou=website&xed=&dl=' .. language .. '&',
- ['method'] = 'POST',
- ['headers'] = {
- ['Host'] = 'www.cleverbot.com',
- ['User-Agent'] = agent,
- ['Accept'] = '*/*',
- ['Accept-Language'] = 'en-US,en;q=0.5',
- ['Accept-Encoding'] = 'gzip, deflate',
- ['Referrer'] = 'https://www.cleverbot.com/',
- ['Content-Length'] = query:len(),
- ['Content-Type'] = 'text/plain;charset=UTF-8',
- ['Cookie'] = table.concat(cookie, ';'),
- ['DNT'] = '1'
- },
- ['source'] = ltn12.source.string(query)
- })
- https.TIMEOUT = old_timeout
- if res ~= 200 or not headers.cboutput then
- return false
- end
- local output = ai.unescape(headers.cboutput)
- if not output then
- return false
- end
- return output
-end
-
-function ai.process(message, reply, language)
- if not message then
- return ai.unsure()
- end
- local original_message = message
- message = message:lower()
- local success = api.get_me()
- if message:match('^hi%s*') or message:match('^hello%s*') or message:match('^howdy%s*') or message:match('^hi.?$') or message:match('^hello.?$') or message:match('^howdy.?$') then
- return ai.greeting()
- elseif message:match('^bye%s*') or message:match('^good[%-%s]?bye%s*') or message:match('^bye$') or message:match('^good[%-%s]?bye$') then
- return ai.farewell()
- elseif message:match('%s*y?o?ur%s*name%s*') or message:match('^what%s*is%s*y?o?ur%s*name') then
- return string.format('My name is %s, what\'s yours?', success.result.first_name)
- elseif message:match('^do y?o?u[%s.]*') then
- return ai.choice(message)
- elseif message:match('^how%s*a?re?%s*y?o?u.?') or message:match('.?how%s*a?re?%s*y?o?u%s*') or message:match('.?how%s*a?re?%s*y?o?u.?$') or message:match('^a?re?%s*y?o?u%s*oka?y?.?$') or message:match('%s*a?re?%s*y?o?u%s*oka?y?.?$') then
- return ai.feeling()
- else
- return ai.talk(original_message, reply or false, language)
- end
-end
-
-function ai.greeting()
- local greetings = {
- 'Hello!',
- 'Hi.',
- 'How are you?',
- 'What\'s up?',
- 'Are you okay?',
- 'How\'s it going?',
- 'What\'s your name?',
- 'What are you up to?',
- 'Hello.',
- 'Hey!',
- 'Hey.',
- 'Howdy!',
- 'Howdy.',
- 'Hello there!',
- 'Hello there.'
- }
- return greetings[math.random(#greetings)]
-end
-
-function ai.farewell()
- local farewells = {
- 'Goodbye!',
- 'Bye.',
- 'I\'ll speak to you later, yeah?',
- 'See ya!',
- 'Oh, bye then.',
- 'Bye bye.',
- 'BUH-BYE!',
- 'Aw. See ya.'
- }
- return farewells[math.random(#farewells)]
-end
-
-function ai.unsure()
- local unsure = {
- 'What?',
- 'I really don\'t understand.',
- 'What are you trying to say?',
- 'Huh?',
- 'Um..?',
- 'Excuse me?',
- 'What does that mean?'
- }
- return unsure[math.random(#unsure)]
-end
-
-function ai.feeling()
- local feelings = {
- 'I am good thank you!',
- 'I am well.',
- 'Good, how about you?',
- 'Very well thank you; you?',
- 'Never better!',
- 'I feel great!'
- }
- return feelings[math.random(#feelings)]
-end
-
-function ai.choice(message)
- local generic_choices = {
- 'I do!',
- 'I do not.',
- 'Nah, of course not!',
- 'Why would I?',
- 'Um...',
- 'I sure do!',
- 'Yes, do you?',
- 'Nope!',
- 'Yeah!'
- }
- local personal_choices = {
- 'I love you!',
- 'I\'m sorry, but I don\'t really like you!',
- 'I really like you.',
- 'I\'m crazy about you!'
- }
- if message:match('%s*me.?$') then
- return personal_choices[math.random(#personal_choices)]
- end
- return generic_choices[math.random(#generic_choices)]
-end
-
-function ai.offline()
- local responses = {
- 'I don\'t feel like talking right now!',
- 'I don\'t want to talk at the moment.',
- 'Can we talk later?',
- 'I\'m not in the mood right now...',
- 'Leave me alone!',
- 'Please can I have some time to myself?',
- 'I really don\'t want to talk to anyone right now!',
- 'Please leave me in peace.',
- 'I don\'t wanna talk right now, I hope you understand.'
- }
- return responses[math.random(#responses)]
-end
-
-while true do
- local messages = redis:keys('ai:*:*')
- if next(messages) then
- for _, message in pairs(messages) do
- local chat_id, message_id = message:match('^ai:(.-):(.-)$')
- local text = redis:hget(message, 'text')
- local reply = redis:hget(message, 'reply') or false
- local language = redis:hget(message, 'language') or 'en'
- api.send_chat_action(chat_id, 'typing')
- local output = ai.process(text, reply, language)
- if output then
- local msg = {
- ['chat'] = {
- ['id'] = chat_id
- },
- ['message_id'] = message_id
- }
- redis:del(message)
- local jstr, res = https.request('https://translate.yandex.net/api/v1.5/tr.json/translate?key=' .. configuration.keys.translate .. '&lang=' .. language .. '&text=' .. url.escape(output))
- if res ~= 200 then
- return api.send_reply(msg, output)
- end
- local jdat = json.decode(jstr)
- if not jdat.text then
- return api.send_reply(msg, output)
- else
- api.send_reply(msg, jdat.text[1])
- end
- end
- end
- end
- os.execute('sleep 0.1s')
-end
\ No newline at end of file
diff --git a/helpers/transcribe.lua b/helpers/transcribe.lua
deleted file mode 100644
index c353542..0000000
--- a/helpers/transcribe.lua
+++ /dev/null
@@ -1,84 +0,0 @@
-package.path = '/usr/local/share/lua/5.3/?.lua;/usr/local/share/lua/5.3/?/init.lua;/usr/local/lib/lua/5.3/?.lua;/usr/local/lib/lua/5.3/?/init.lua;../?.lua;./?/init.lua'
-local redis = require('libs.redis')
-local configuration = require('configuration')
-local api = require('telegram-bot-lua.core').configure(configuration.bot_token)
-local tools = require('telegram-bot-lua.tools')
-local https = require('ssl.https')
-local json = require('dkjson')
-local ltn12 = require('ltn12')
-
-while true do
- local messages = redis:keys('transcribe:*:*')
- if next(messages) then
- for _, msg in pairs(messages) do
- local message = json.decode(redis:get(msg))
- local voice = message.voice
- local file = api.get_file(voice.file_id)
- if file then
- local file_name = file.result.file_path
- local file_path = string.format('https://api.telegram.org/file/bot%s/%s', configuration.bot_token, file_name)
- tools.download_file(file_path, voice.file_id .. '.oga', configuration.bot_directory .. '/')
- os.execute('ffmpeg -i ' .. configuration.bot_directory .. '/' .. voice.file_id .. '.oga -ac 1 -y ' .. configuration.bot_directory .. '/' .. voice.file_id .. '.mp3')
- os.remove(configuration.bot_directory .. '/' .. voice.file_id .. '.oga')
- file = io.open(configuration.bot_directory .. '/' .. voice.file_id .. '.mp3', 'r')
- local current = file:seek()
- local size = file:seek('end')
- file:seek('set', current)
- size = tonumber(size)
- os.remove(configuration.bot_directory .. '/' .. voice.file_id .. '.mp3')
- local response = {}
- local _, res = https.request({
- ['url'] = 'https://api.wit.ai/speech',
- ['method'] = 'POST',
- ['headers'] = {
- ['Authorization'] = 'Bearer ' .. configuration.keys.transcribe,
- ['Content-Type'] = 'audio/mpeg3',
- ['Content-Length'] = size
- },
- ['redirect'] = false,
- ['source'] = ltn12.source.file(file),
- ['sink'] = ltn12.sink.table(response)
- })
- if res == 200 then
- local jstr = table.concat(response)
- local jdat = json.decode(jstr)
- if jdat then
- local nothing = {
- '*bong noises*',
- '*tumbleweed passes*',
- '*silent noises*',
- '*unknown sounds*'
- }
- local text = jdat.text or jdat._text or false
- local output = '<pre>Transcription ' .. tools.symbols.next .. ' ' .. nothing[math.random(#nothing)] .. '</pre>'
- if text and text ~= '' then
- output = '<pre>Transcription ' .. tools.symbols.next .. ' ' .. tools.escape_html(text) .. '</pre>'
- end
- local ids = {
- 'CQACAgQAAx0CVClmWQACHZFe-9jPBIqWiyNMnkLTBsogIZGFeQACIQcAAvNJ2VOZvtK5bU4CSBoE',
- 'CQACAgQAAx0CVClmWQACHZZe-9og8tRI6K4ZjQaxpMxAva5gjQACIgcAAvNJ2VNwy64JjeDiwRoE'
- }
- if math.random(2) == 2 and (not text or text == '') then
- if math.random(3) == 1 then
- api.send_voice(message.chat.id, 'AwACAgEAAx0CSdNVGgABBus7XvvbfQNDreQ-ZFMedF8xYDagcjsAAt4AAx7N4UfVVxLVLBpPZxoE')
- else
- api.send_audio(message.chat.id, ids[math.random(#ids)], nil, nil, nil, nil, nil, false, message.message_id)
- end
- else
- api.send_reply(message, output, 'html')
- end
- redis:del(msg)
- else
- error('No jdat object!')
- end
- else
- print('Connection error!', '[' .. res .. ']')
- end
- else
- error('No file!')
- end
- redis:del(msg)
- end
- end
- os.execute('sleep 1.5s')
-end
\ No newline at end of file
diff --git a/install.sh b/install.sh
deleted file mode 100644
index c3764fc..0000000
--- a/install.sh
+++ /dev/null
@@ -1,61 +0,0 @@
-printf "This script is intended to work with Ubuntu 16.04 - 18.04, other versions may also\n"
-printf "work. Root access is required to complete the installation. Press enter to continue,\n"
-printf "or press CTRL + C to abort.\n"
-read
-set -e
-sudo apt-get update
-aptlist="git wget openssl coreutils make gcc libreadline-dev redis-server unzip libexpat1-dev libcurl3 libcurl3-gnutls ruby ruby-dev libgd-dev imagemagick tesseract-ocr libpcre3-dev"
-for package in $aptlist; do
- printf "[Info] Installing $package...\n"
- sudo apt-get --yes --force-yes install $package
-done
-if [ ! -f "`which lua`" ]; then
- printf "[Info] Downloading Lua 5.3.5...\n"
- wget -N http://www.lua.org/ftp/lua-5.3.5.tar.gz
- printf "[Info] Extracting Lua 5.3.5...\n"
- tar zxf lua-5.3.5.tar.gz
- cd lua-5.3.5/
- printf "[Info] Installing Lua 5.3.5...\n"
- sudo make linux test
- sudo make install
- sudo cp /usr/local/bin/lua /usr/bin/lua
- sudo cp /usr/local/bin/luac /usr/bin/luac
- cd ../
-fi
-if [ ! -f "`which luarocks`" ]; then
- printf "[Info] Downloading LuaRocks...\n"
- git clone --recursive https://github.com/keplerproject/luarocks
- cd luarocks/
- printf "[Info] Building LuaRocks...\n"
- sudo ./configure --lua-version=5.3 --versioned-rocks-dir
- sudo make build
- printf "[Info] Installing LuaRocks...\n"
- sudo make install
- cd ../
-fi
-printf "[Info] Installing openssl...\n"
-sudo luarocks install --server=http://luarocks.org/dev openssl
-rocklist="luasocket luasec multipart-post lpeg dkjson serpent redis-lua luafilesystem uuid html-entities feedparser telegram-bot-lua lzlib lrexlib-pcre md5 lbase64"
-for rock in $rocklist; do
- printf "[Info] Installing $rock...\n"
- sudo luarocks install $rock
-done
-printf "[Info] Installing lua-captcha...\n"
-git clone git://github.com/lua-programming/lua-captcha.git
-cp patch/malloc.patch lua-captcha/
-cd lua-captcha/
-git apply malloc.patch
-sudo luarocks make rockspec/lua-captcha-1.0-0.rockspec
-cd ../
-printf "[Info] Installing redis-dump...\n"
-sudo gem install redis-dump
-printf "[Info] Installing ImageMagick...\n"
-wget https://imagemagick.org/download/binaries/magick
-printf "[Info] Cleaning up installation files...\n"
-sudo rm -rf lua-5.3.5/
-sudo rm lua-5.3.5.tar.gz
-sudo rm -rf luarocks/
-sudo rm -rf patch/
-sudo rm -rf lua-captcha/
-sudo -k
-printf "[Info] Installation complete.\n"
diff --git a/languages/ar_ar.lua b/languages/ar_ar.lua
deleted file mode 100644
index 64b8ef4..0000000
--- a/languages/ar_ar.lua
+++ /dev/null
@@ -1,806 +0,0 @@
-
--- This is a language file for mattata
--- Language: ar_ar
--- Author: disk3
-
--- DO NOT CHANGE ANYTHING THAT BEGINS OR ENDS WITH A %
--- THESE ARE PLACEHOLDERS!
-
--- DO NOT CHANGE ANY MARKDOWN/HTML FORMATTING!
--- IF YOU ARE UNSURE, ASK ON TELEGRAM (t.me/mattataDev),
-
-return {
- ['errors'] = {
- ['connection'] = 'خطا في الاتصال.',
- ['results'] = 'لا نتائج.',
- ['supergroup'] = 'هذا الامر فقط للمجموعات الكبيرة.',
- ['admin'] = 'يجب أن تكون مشرفاً أو منشئاً لإستخدام هذا الأمر',
- ['unknown'] = 'لا أعرف هذا الشخص. إذا أردت أن تعرفني علية، حول أيً من رسائلة إلى أي محادثة أنا فية',
- ['generic'] = 'حصلت مشكلة!',
- ['use'] = 'استخدام هذا غير مسموح!',
- ['private'] = 'يمكنك استعمال هذا الأمر في الخاص فقط'
- },
- ['addcommand'] = {
- ['1'] = 'يرجى تحديد الأمر بالشكل <code> /command - المحتوى</code>',
- ['2'] = 'لم تعطني امر!',
- ['3'] = 'وصف الامر لا يمكن ان يكون اطول من 256 أحرف!',
- ['4'] = 'حدث خطأ لم يتم إضافة الأمر!',
- ['5'] = 'تم إضافة الأمر بنجاح!'
- },
- ['addrule'] = {
- ['1'] = 'يرجى تحديد النص لقانون المجموعة!',
- ['2'] = 'ليس لديك أية قوانين حالية لكي تضيف له. يرجى إرسال /setrules لضبط القوانين!',
- ['3'] = 'لا يمكن إضافة القانون؛ النص طويل جدا أكثر من حد التليجرام 4096 احرف!',
- ['4'] = 'لا يمكن أضافة هذا القانون لأنه يحتوي على تحديدات خط غير مدعومة!',
- ['5'] = 'تم تحديث القانون بنجاح!'
- },
- ['addslap'] = {
- ['1'] = 'يمكن استعماله فقط في المجموعات!',
- ['2'] = 'لا يمكن استعمال هذه الأقواس في أمر الصفعة بعيدا عن الثوابت!',
- ['3'] = 'الحد الأقصى الأحرف 256!',
- ['4'] = 'تم إضافة هذه الصفعة بنجاح!',
- ['5'] = 'يجب أن تضع هذه القوانين في الصفعة، {ME} يعني اسم الشخص الصافع، {THEM} اسم الشخص المصفوع'
- },
- ['administration'] = {
- ['1'] = 'تفعيل الأدمنية',
- ['2'] = 'تعطيل الأدمنية',
- ['3'] = 'إعدادات تكرار الرسائل',
- ['4'] = 'إعدادات التحذير',
- ['5'] = 'الحظر بتصويت الأعضاء',
- ['6'] = 'ترحيب الأعضاء الجدد؟',
- ['7'] = 'ارسال القوانين عند الانضمام؟',
- ['8'] = 'ارسال القوانين في المجموعة؟',
- ['9'] = 'رجوع',
- ['10'] = 'التالي',
- ['11'] = 'فلترة الكلمة',
- ['12'] = 'مانع البوت',
- ['13'] = 'مانع الروابط',
- ['14'] = 'تسجيل الافعال؟',
- ['15'] = 'كتم العربية',
- ['16'] = 'عقوبة تكرار الرسائل',
- ['17'] = 'حظر',
- ['18'] = 'طرد',
- ['19'] = 'مسح الأوامر؟',
- ['20'] = 'رد الإنجليزي فقط؟',
- ['21'] = 'ارسال الاعدادات بالمجموعة؟',
- ['22'] = 'مسح الرد على الأوامر؟',
- ['23'] = 'طلب تحقق للمنضمين؟',
- ['24'] = 'تحقق inline للمنضمين؟',
- ['25'] = 'طرد المشبوهين تلقائياً؟',
- ['26'] = 'عدد التحذيرات لكي يتم %s:',
- ['27'] = 'عدد التصويتات المطلوبة:',
- ['28'] = 'عدد التصويتات الرفض للإلغاء:',
- ['29'] = 'تم مسح %s, من قاعدة البيانات',
- ['30'] = 'لا يوجد قيمة مطابقة لهذا "%s" في قاعدة البيانات!',
- ['31'] = 'لست مشرفاً في تلك المحادثة!',
- ['32'] = 'اقل عدد التصويتات للحظر بالتصويت هي %s.',
- ['33'] = 'أقصى عدد التصويتات للحظر بالتصويت هي %s.',
- ['34'] = 'اقل عدد رفض التصويت للحظر بالتصويت هي %s.',
- ['35'] = 'أقصى عدد رفض التصويت للحظر بالتصويت هي %s.',
- ['36'] = 'اقصى عدد التحذيرات هي %s.',
- ['37'] = 'أقل عدد التحذيرات هي %s.',
- ['38'] = 'يمكنك إضافة كلمات بالأمر الاتي /filter <الكلمة>',
- ['39'] = 'لن يتم اشعارك بأن الاضافة (الادمنية) معطلة, استعمل /administration لتفعيله.',
- ['40'] = 'ليست محادثة صالحة!',
- ['41'] = 'على ما يبدو أنك لست مشرفاً هناك!',
- ['42'] = 'خاصيتي (الادمنية) يمكن استعمالها في مجموعات/قنوات..اذا كنت تبحث عن المساعدة باستعمالها، اكتب /help ثم قسم "الادمنية",لو كنت تريد إدارة مجموعة لم الإشراف فيها أرسل /administration <اسم المحادثة>.',
- ['43'] = 'استعمل الأزرار السفلية لتضبيط اعدادات الإدارية في <b>%s</b>:',
- ['44'] = 'ارسل لي [رسالة خاصة](https://t.me/%s), لكي أرسل لك المعلومة.',
- ['45'] = 'ارسلت لك معلومتك في الخاص',
- ['46'] = 'ازالة تثبيتات القناة؟',
- ['47'] = 'ازالة باقي تثبيتات؟',
- ['48'] = 'مسح الكود الملصوق؟',
- ['49'] = 'منع بوتات inline؟',
- ['50'] = 'طرد مرسل الصور عند انضمام؟',
- ['51'] = 'اطفاء الاضافات للكل؟'
- },
- ['afk'] = {
- ['1'] = 'عذرا, هذا الخاصية متاحة فقط للأشخاص، بإسم مستخدم @username!',
- ['2'] = 'رجع %s, بعد غياب %s!',
- ['3'] = 'ملاحظة',
- ['4'] = '%s مشغول الآن,%s'
- },
- ['antispam'] = {
- ['1'] = 'تعطيل',
- ['2'] = 'تفعيل',
- ['3'] = 'تعطيل الحد',
- ['4'] = 'تفعيل الحد في %s',
- ['5'] = 'جميع إعدادات الادمنية',
- ['6'] = ' طردت %s [%s] %s [%s] من %s [%s] لتجاوز حد التكرار [%s] للوسائط.',
- ['7'] = 'طردت %s لتجاوز حد التكرار [%s] للوسائط.',
- ['8'] = 'الحد الأقصى هي 100.',
- ['9'] = 'الحد الأدنى هي 1.',
- ['10'] = 'ضبط حد التكرار ل %s ادناه:',
- ['11'] = 'مرحبا %s, إذا ترسل كود أطول من %s حرف, استعمل /paste في <a href="https://t.me/%s"> محادثة خاصة معي</a>!',
- ['12'] = '%s <code>[%s]</code> لديه %s %s <code>[%s]</code> من %s <code>[%s]</code> لإرسال روابط الدعوة.\n#chat%s #المستخدم%s',
- ['13'] = '%s %s لإرسال روابط دعوة.',
- ['14'] = 'مرحبا, لاحظت أنك مفعل مانع روابط، ولا تسمح المستخدمين بنشر روابط حتى الذي استعملته ,إذا أردت أن تسمح رابطك استعمل /whitelistlink <رابط>.',
- ['15'] = 'طردت %s <code>[%s]</code> من %s <code>[%s]</code> لارسال صورة عند أول دخول.\n#محادثة%s #مستخدم%s',
- ['16'] = 'Kicked %s <code>[%s]</code> from %s <code>[%s]</code> for sending a URL within their first few messages.\n#chat%s #user%s',
- ['17'] = 'Action',
- ['18'] = 'Kick',
- ['19'] = 'Ban',
- ['20'] = 'Mute'
- },
- ['appstore'] = {
- ['1'] = 'عرض في ايتونز',
- ['2'] = 'التقييم',
- ['3'] = 'التقييمات'
- },
- ['authspotify'] = {
- ['1'] = 'انت بالفعل مخول بهذا الحساب.',
- ['2'] = 'يتم التخويل، يرجى الانتضار...',
- ['3'] = 'حصل خطأ في الإتصال، هل الرابط صالح؟ مثال الرابط',
- ['4'] = 'تم التخويل بنجاح!'
- },
- ['avatar'] = {
- ['1'] = 'لم أحصل على الصور الخاصة بالمستخدم, يرجى التأكد من إدخال اسم مستخدم صالح أو ID.',
- ['2'] = 'لا يملك المستخدم هذا أية صور.',
- ['3'] = 'لا يملك المستخدم هذا الكم من الصور!',
- ['4'] = 'هذا المستخدم رفض خاصية تجميع البيانات عنه, وعليه لست مخولا لإظهار صورهِ.',
- ['5'] = 'مستخدم: %s\nصورة: %s/%s\nارسل /avatar %s [رقم] الى @%s لإظهار الصورة ذات الرقم المعطى',
- ['6'] = 'مستخدم: %s\nصورة: %s/%s\nاستعمل /avatar %s [رقم] لإظهار صورة ذات الرقم المطلوب',
- },
- ['ban'] = {
- ['1'] = 'من يجب على حظره؟ , يمكنك تحديد المستخدم مع @username او ID الرقمي..',
- ['2'] = ' لا أستطيع حظر المشرفين و المنشئين.',
- ['3'] = 'لا أستطيع حظر هذا الشخص لأنهم خارج المجموعة اصلاً.',
- ['4'] = 'لا يمكنني حظر هذا الشخص لأنه محظور بالفعل.',
- ['5'] = 'اجعلني مشرفا لكي احظر هذا المستخدم، حاول مجددا لاحقا.',
- ['6'] = '%s <code>[%s]</code> حظر %s <code>[%s]</code> من %s <code>[%s]</code>%s.\n%s %s',
- ['7'] = 'قام %s بحظر %s%s.'
- },
- ['bash'] = {
- ['1'] = 'حدد أمراً لتنفيذه!',
- ['2'] = 'نجح!'
- },
- ['blacklist'] = {
- ['1'] = 'أي مستخدم تريده في القائمة السوداء؟ حدد بوساطة @username او ID الرقمي.',
- ['2'] = 'لا أستطيع وضع المشرفين و المنشئين في القائمة السوداء',
- ['3'] = 'لا أستطيع وضعه في القائمة السوداء لأنه خارج المجموعة اصلاً.',
- ['4'] = 'لا أستطيع وضعه في القائمة السوداء لأنه محظور من المجموعة اصلاً.',
- ['5'] = 'وضع %s <code>[%s]</code> ... %s <code>[%s]</code> في القائمة السوداء، لمنع استعمال %s <code>[%s]</code> في %s <code>[%s]</code>%s.\n%s %s',
- ['6'] = 'وضع %s %s في القائمة السوداء من استعمال %s%s.'
- },
- ['blacklistchat'] = {
- ['1'] = 'تم وضع %s بالقائمة السوداء، سوف أغادر عند انضمامي هنا.!',
- ['2'] = '%s مستخدم, هذا الأمر للمجموعات و ليس المستخدمين!',
- ['3'] = ' هذا المحادثة %s لا يبدو صالحاً'
- },
- ['bugreport'] = {
- ['1'] = 'تم إرسال تقرير الأخطاء للمطور!. عنوان ID للبلاغ هي #%s.',
- ['2'] = 'حصلت مشكلة أثناء هذه العملية، يا لحظك!'
- },
- ['calc'] = {
- ['1'] = 'اضغط لإرسال النتائج.',
- ['2'] = 'هذه الكلمة "%s" غير متوقعة!',
- ['3'] = 'لا يمكن وضع وحدة قبل الأرقام!!'
- },
- ['captionbotai'] = {
- ['1'] = 'لا أستطيع وصف الصورة!'
- },
- ['cats'] = {
- ['1'] = 'مياو :3!'
- },
- ['channel'] = {
- ['1'] = 'غير مسموح لك القيام بهذا!',
- ['2'] = 'انت لست مشرفا في المحادثة!',
- ['3'] = 'فشلت في ارسال رسالتك، هل انت متاكد انه اذوناتي لكتابه الرسائل مفعله؟',
- ['4'] = 'تم ارسال رسالتك!',
- ['5'] = 'لا استطيع الحصول على لائحه مشرفين المحادثه!',
- ['6'] = 'يبدو انك لست مشرفا المحادثه!',
- ['7'] = 'حدد رساله المطلوبه للارسال، استعمل الصيغه /channel <القناة> <الرسالة>.',
- ['8'] = 'هل انت متاكد انك تريد ارسال هذه الرساله؟ سوف تبدو هكذا:',
- ['9'] = 'نعم انا متاكد!',
- ['10'] = 'الرساله تحتوي على تحديدات هن غير مدعومه ! يرجى تصحيح الصيغه والمحاوله مجددا.'
- },
- ['chatroulette'] = {
- ['1'] = 'مرحبا! لا ترسل رسائل اطول من %s حرف. لكي لا تزعج المستخدم الثاني!',
- ['2'] = '*قال المجهول:*\n```\n%s\n```\nلإنهاء الجلسة, ارسل /endchat.',
- ['3'] = 'للاسف فقدت الاتصال بالمستخدم الاخر! لبدء محادثه جديده ارسل رجاءا /chatroulette!',
- ['4'] = 'الشخص الذي تتحدث معه انهى الجلسه. لبدء محادثه جديده ارسل /chatroulette.',
- ['5'] = 'تم بدء جلسة بنجاح. لبدء واحده جديده أرسل /chatroulette.',
- ['6'] = 'لقد ازلتك من لائحة مستخدمين المتوفرين بنجاح.',
- ['7'] = 'لا تملك جلسه حاليا. لبدء واحده جديده ارسل /chatroulette.',
- ['8'] = 'جاري البحث عن الجلسه انتضر...',
- ['9'] = 'لسوء الحظ لا يوجد اي مستخدمين حاليا لكني اضفتك الى لائحه المستخدمين المتوفرين! لايقاف هذا كليا ارسل /endchat.',
- ['10'] = 'لقد جمعتك بنجاح مع شخص اخر في الجلسه! تذكر رجاءا ان تكون لطيفا! ايقاف الجلسه ارسل /endchat.',
- ['11'] = 'لسوء الحظ الشخص الذي حاولت انشاء الجلسه معه محظور. ارسل رجاءا /chatroulette للمحاوله!',
- ['12'] = 'لقد تم جمعكبنجاح مع شخص اخر في محادثه! تذكر ان تكون لطيفا معهم! لانهاء الجلسه ارسل /endchat.'
- },
- ['commandstats'] = {
- ['1'] = 'لم يتم ارسال اي اوامر في هذه المحادثه!',
- ['2'] = '<b> احصائيات الاوامر في:</b> %s\n\n%s\n<b> مجمل الاوامر المستعمله:</b> %s',
- ['3'] = 'تم مسح التفاصيل الاوامر المستعمله!',
- ['4'] = 'فشل مسح التفاصيل الاوامر المستعمله في هذه المحادثه على الاغلب لانها ممسوحه اصلا؟'
- },
- ['control'] = {
- ['1'] = 'تهي, أنت تتمنى!',
- ['2'] = 'جاري تحميل %s...'
- },
- ['copypasta'] = {
- ['1'] = 'النص الذي قمت بالرد عليه لا يجب ان يتجاوز %s احرف!'
- },
- ['coronavirus'] = {
- ['1'] = [[* احصائيات COVID-19 عن:* %s
-
-*الحالات الموثقه الجديده:* %s
-*الحالات الموثقه الكليه:* %s
-*احصائيات الموت الجديده:* %s
-*اجمالي الموت:* %s
-*حالات التعافي الجديده:* %s
-*حالات التعافى الكليه:* %s]]
- },
- ['counter'] = {
- ['1'] = 'لم استطع اضافه العداد الى تلك الرساله!'
- },
- ['custom'] = {
- ['1'] = 'تم النجاح! سوف يرسل رساله في كل مره يرسل احدهم %s!',
- ['2'] = 'الرد "%s" غير موجود!',
- ['3'] = 'تم مسح الرد "%s"!',
- ['4'] = 'ليس لديك اي ردود خاصه محفوظه!',
- ['5'] = 'الاوامر الخاصه في %s:\n',
- ['6'] = 'لصنع امر خاص جديد استعمل الصيغه الاتيه:\n/custom new #<كلمة> <الرد>... لعرض كل الردود الحاليه استعمل الأمر /custom list. لمسح رد استعمل /custom del #<كلمة>.'
- },
- ['delete'] = {
- ['1'] = 'لم أستطع مسح الرسالة. ربما لان الرساله قديمه جدا او غير موجوده؟'
- },
- ['demote'] = {
- ['1'] = 'اي مستخدم تريد مني تخفيضه؟ يمكنك تحديد بوساطة @username أو ID.',
- ['2'] = 'لماذا تريد مني تخفيظه من هو ليس مشرفا أو منشئا.',
- ['3'] = 'لا يمكنني تخفيضه لانه خارج المحادثه.',
- ['4'] = 'لا يمكنني تخفيض هذا المستخدم لانه مطرود من المحادثه.'
- },
- ['dice'] = {
- ['1'] = 'النطاق الادنى هي: %s.',
- ['2'] = 'النطاق الاعلى والعد هما %s.',
- ['3'] = 'النطاق الاقصى هي %s, والعداد الادنى هي %s.',
- ['4'] = 'نطاق %s هي %s:\n'
- },
- ['doge'] = {
- ['1'] = 'ادخل النص الذي تريده في صورة الكلب. كل جمله يجب ان تكون مفصوله بسطر جديد او سلاش'
- },
- ['donate'] = {
- ['1'] = '<b>مرحبا, %s!</b>\n\nلو تشعر بالكرم, يمكنك التبرع لمشروع mattata, بدعمنا بشكل إرادي بأي كمية. سوف تستعمل كلها لتكاليف الخوادم و تعويضاً للوقت و الموارد المستعملة في المشروع. هذا **اختياري**, على كل حال مساهمتك مشكورة و ستظهر اسمك في صفحتنا على كيت هاب\n\nإذا أردت الاستمرار, رابط الدعم المادي<a href="https://paypal.me/wrxck"> هنا</a>. شكرا جزيلا لدعمك!'
- },
- ['duckduckgo'] = {
- ['1'] = 'لا أعرف ما هذا :/!'
- },
- ['eightball'] = {
- ['1'] = 'نعم.',
- ['2'] = 'لا.',
- ['3'] = 'على مايبدو هي كذلك.',
- ['4'] = 'همممم،...حسنا، لو كنت مكانك لسألت مرة اخرى'
- },
- ['exec'] = {
- ['1'] = 'حدد لغة البرمجة:',
- ['2'] = 'خطا في الاتصال. هل كنت تنوي صنع اضرار؟',
- ['3'] = 'اختيارك هي "%s" – هل استمر؟',
- ['4'] = 'رجوع',
- ['5'] = 'استمر',
- ['6'] = 'ادخل البرمجة لتنفيذه. لا حاجة لتحديد لغتها, سوف نهتم بها لاحقا!',
- ['7'] = 'حدد لغة البرمجة:'
- },
- ['facebook'] = {
- ['1'] = 'حدثت مشكلة!',
- ['2'] = 'ادخل اسم مستخدم الفيسبوك للحصول على صوره،.',
- ['3'] = 'افتح @%s في الفيسبوك'
- },
- ['fact'] = {
- ['1'] = 'اصنع غيرها'
- },
- ['fban'] = {
- ['1'] = 'اي مستخدم علي حظره بالحظر الجماعي؟ حدد باسم @username او ID الرقمي.',
- ['2'] = ' لا يمكنني حظر هذا الشخص جماعيا لأنه مشرف أو منشئ هنا',
- },
- ['flickr'] = {
- ['1'] = 'بحثك كانت عن:',
- ['2'] = 'ادخل كلمة البحث(المراد البحث عنه مثل: "لمبوركيني" سوف يظهر لك ما لا يمكنك الحصول عليه :p).',
- ['3'] = 'المزيد'
- },
- ['fortune'] = {
- ['1'] = 'اضغط لإرسال حظك!'
- },
- ['frombinary'] = {
- ['1'] = 'ادخل الرقم الثنائي لتحويله الى كلمات.',
- ['2'] = 'المعطيات تالفة!'
- },
- ['game'] = {
- ['1'] = 'إجمالي الفوز: %s\nإجمالي الخسارة: %s\nالرصيد: %s عملة متاتا',
- ['2'] = 'انضمام للعبة',
- ['3'] = 'هذه اللعبة انتهت!',
- ['4'] = ' دورك الآن!',
- ['5'] = 'لست مشاركاً في اللعبة!',
- ['6'] = 'لا يمكنك الذهاب هنا!',
- ['7'] = 'انت مشترك باللعبة فعلا!',
- ['8'] = 'لقد بدأت اللعبة بالفعل!',
- ['9'] = 'يقوم %s [%s] باللعب ضد %s [%s]\nإنه دور%s حالياً!',
- ['10'] = 'فاز %s على %s!',
- ['11'] = 'تعادل %s مع %s!',
- ['12'] = 'بانتضار متحدٍ...',
- ['13'] = 'لعبه X O',
- ['14'] = 'اضغط لإرسال اللعبة لمحادثتك!',
- ['15'] = 'احصائيات %s:\n',
- ['16'] = 'إلعب X O!'
- },
- ['gblacklist'] = {
- ['1'] = 'ردَ على المستخدم لوضعه في قائمة السوادء الشاملة, أو حددهم باسم المستخدم أو ID.',
- ['2'] = ' فشلت في تحصيل المعلومات عن "%s", رجاءا تأكد أنه اسم مستخدم أو ID صالح و حاول.',
- ['3'] = 'همم، هذا %s, وليس مستخدماً!'
- },
- ['gif'] = {
- ['1'] = 'اعطي كلمات البحث رجاءا، (الذي تريد البحث عنه في GIPHY مثلا memes سيظهر لك متحركات الميمز :-:)'
- },
- ['godwords'] = {
- ['1'] = 'ادخل قيمة عددية يتراوح بين 1 الى 64!',
- ['2'] = 'رقم صغيرٌ جدا, حدد واحداً بين 1 الى 64!',
- ['3'] = 'رقم كبيرٌ جدا, حدد واحداً بين 1 الى 64!',
- },
- ['gwhitelist'] = {
- ['1'] = 'ردَ على المستخدم لازالته من قائمة السوادء الشاملة, أو حددهم باسم المستخدم أو ID.',
- ['2'] = ' فشلت في تحصيل المعلومات عن "%s", رجاءا تأكد أنه اسم مستخدم أو ID صالح و حاول.',
- ['3'] = 'همم، هذا %s, وليس مستخدماً!'
- },
- ['hackernews'] = {
- ['1'] = 'ابرز العناوين Hacker News:'
- },
- ['help'] = {
- ['1'] = 'لا نتائج!',
- ['2'] = 'لا يوجد ميزة تم الحصول عليها باسم "%s", حاول أنت تكون دقيقا أكثر!',
- ['3'] = '\n\nالجملة: <مطلوب> [اختياري]\n\nابحث عن المميزات أو ابحث بخاصية inline - فقط الصق هذا المعرف بمكان الكتابة @%s ثم <كلمة البحث>.',
- ['4'] = 'السابق',
- ['5'] = 'التالي',
- ['6'] = 'رجوع',
- ['7'] = 'البحث',
- ['8'] = 'الصفحة رقم %s من %s!',
- ['9'] = [[
-أستطيع إدارة مجموعتك فقط اجعلني مشرفا وارسل /administration لضبط الاعدادات لمجموعتك.
-الأوامر الشائعة:
-
-• /pin <نص> - تثبيت الرسالة
-• /ban - حظر المستخدمين بالرد أو /ban @username
-• /kick - طرد
-• /unban - إلغاء الحظر
-• /setrules <نص> - ضبط قوانين المجموعه، يحصل عليها من الأمر /rules
- ]],
- ['10'] = [[
-• /setwelcome - وضع ترحيب،،(يمكن استعمال أشياء مذهلة ايضا. مثل $name اكتبه بالرسالة الترحيب فيكتب اسم الشخص المرحب به او, $chat_id الكتابه ID المحادثة في الرسالة الترحيبية, $user_id لكتابة ID الشخص المرحب به, $title لادخال اسم المحادثة $username لادخال المعرف الشخص المركزي به برسالة الترحيب( إذا المستخدم لا يملك اسم المستخدم سيتم استخدام اسمه بدلا من ذلك)
-
-• /warn - تحذير المخالفة ثم الطرد بعد تجاوز الحد الاقصى
-
-• /mod - ترقية الناس،، لا ترقي احد الا اذا كنت تثق به
-• /demod - تخفيض الرتبة
-• /staff - عرض المجموعة الاشرافية
- ]],
- ['11'] = [[
-• /report - تاك الادمنية
-• /setlink <الرابط> - حفظ الروابط,, يحصل عليه من قبل الاعضاء بباستعمال الامر /link
-• /links <نص> - عدم حظر جميع الروابط التي ترسل هذا الامر اليه ردا على رسالة الحاوية للروابط المطلوبة
- ]],
- ['12'] = 'ادناه روابط قد تكون مفيدة:',
- ['13'] = 'تواصل',
- ['14'] = 'قناتنا',
- ['15'] = 'دعم',
- ['16'] = 'الاسئلة',
- ['17'] = 'السورس',
- ['18'] = 'تبرع',
- ['19'] = 'تقييم',
- ['20'] = 'سجلات الطرد',
- ['21'] = 'إعدادات المشرف',
- ['22'] = 'الإضافات',
- ['23'] = [[
-<b>مرحبا %s! اسمي %s, سررت بمعرفتك </b> %s
-
-أستطيع فهم أوامر عديدة، يمكنك معرفة الأوامر بالضغط على زر "الاوامر" أدناه
-
-%s <b>نصيحة:</b> استعمل زر "الاعدادات" لتغيير أسلوب عملي %s!
-
-%s <b>لو استفدت مني, أو تريد المساعدة فقط؟</b> سوف تسرني بدعم مالي صغير , استعمل الأمر /donate لمزيد من المعلومات!
- ]],
- ['24'] = 'داخل'
- },
- ['id'] = {
- ['1'] = 'لا أعرف هذا الشخص. إذا أردت أن تعرفني علية، حول أيً من رسائلة إلى أي محادثة أنا فية أو أخبرهم بمراسلتي',
- ['2'] = 'المحادثة المطلوبة:',
- ['3'] = 'هذه المحادثة:',
- ['4'] = 'اضغط لإرسال النتائج!'
- },
- ['imdb'] = {
- ['1'] = 'السابق',
- ['2'] = 'التالي',
- ['3'] = 'انت في الصفحة %s من %s!'
- },
- ['import'] = {
- ['1'] = 'لا أعرف هذه المحادثة!',
- ['2'] = 'هذه ليس مجموعه خارقة, وعليه لن أستطيع استيراد أيه الاعدادات منه!',
- ['3'] = 'تم الاستيراد اعدادات الاشراف و الاضافات المفعلة من %s إلى %s!'
- },
- ['info'] = {
- ['1'] = [[
-```
-Redis:
-%s ملف التفاصيل: %s
-%s الوضع: %s
-%s بوابة TCP: %s
-%s الإصدار: %s
-%s وقت التشغيل: %s days
-%s تفاصيل العملية: %s
-%s مفاتيح منتهيه الصلاحية: %s
-
-%s عدد المستخدمين: %s
-%s عدد المجموعات: %s
-
-النظام:
-%s OS: %s
-```
- ]]
- },
- ['instagram'] = {
- ['1'] = '@%s في الانستكرام'
- },
- ['ipsw'] = {
- ['1'] = '<b>%s</b> iOS %s\n\n<code>MD5 شفرة: %s\nSHA1 شفرة: %s\nحجم الملف: %s كيكا</code>\n\n<i>%s %s</i>',
- ['2'] = 'هذا النظام خارج عملية التسجيل!',
- ['3'] = 'هذا النظام يتم تسجيله!',
- ['4'] = 'حدد موديلك:',
- ['5'] = 'حدد إصدار النظام:',
- ['6'] = 'حدد نوع الجهاز:',
- ['7'] = 'iPod الملموس',
- ['8'] = 'ايفون',
- ['9'] = 'ايباد',
- ['10'] = 'Apple تلفاز'
- },
- ['ispwned'] = {
- ['1'] = 'تم العثور على الحساب في التسريبات ادناه:'
- },
- ['isup'] = {
- ['1'] = 'هذا الموقع يبدو نشطا',
- ['2'] = 'لا يبدو هذا موقعاً صالحا!',
- ['3'] = 'الموقع غير نشط عندي كذلك'
- },
- ['itunes'] = {
- ['1'] = 'الاسم:',
- ['2'] = 'الفنان:',
- ['3'] = 'الالبوم:',
- ['4'] = 'الأغنية:',
- ['5'] = 'القرص:',
- ['6'] = 'لم يتم العثور على الطلب الأصلي , لقد مسحت رسالتك الأصلية على الأغلب.',
- ['7'] = 'القطعة الفنية موجودة ادناه:',
- ['8'] = 'ادخل كلمة البحث (ما تريد البحث عنه مثل "شيلات" ستظهر نتائج عن الشيلات (—~—).',
- ['9'] = 'احصل على الالبوم',
- },
- ['kick'] = {
- ['1'] = 'من علي طرده؟ حدد بالمعروف خاصتهم @username or ID.',
- ['2'] = 'لا يمكنني طرد المشرفين و المنشئين.',
- ['3'] = 'لا يمكن طرد هذا الشخص لأنه خارج المجموعة اصلا.',
- ['4'] = 'لا يمكن طرد هذا الشخص لأنه مطرود اصلا.',
- ['5'] = 'اجعلني مشرفاً لكي أستطيع طردهم. وفر هذا رجاءاً, وحاول مجددا',
- },
- ['lastfm'] = {
- ['1'] = 'تم تغيير اسم last.fm الخاصة في %s إلى "%s".',
- ['2'] = 'تم المسح!',
- ['3'] = 'ليست هناك أي اسم مستخدم last.fm!',
- ['4'] = 'حدد اسم مستخدم last.fm او اصنع واحدة بالأمر /fmset.',
- ['5'] = 'لم يتم العثور على سجلات لهذا المستخدم.',
- ['6'] = 'يقوم %s بالاستماع إلى:\n',
- ['7'] = 'استمع %s آخر مرة الى:\n',
- ['8'] = 'مجهول',
- ['9'] = 'اضغط لإرسال النتائج.'
- },
- ['lmgtfy'] = {
- ['1'] = 'دعني ابحثها في الكوكل لك!'
- },
- ['location'] = {
- ['1'] = 'لم تعيين ايه مواقع سابقة،، ماذا تود أن يكون الموقع الحالي؟'
- },
- ['logchat'] = {
- ['1'] = 'ادخل المعرف ID المحادثة التي تودني أن أرسل سجلات الأفعال مثل الطرد و غيرها.',
- ['2'] = 'جارٍ التحقق من صلاحية المحادثة...',
- ['3'] = 'للاسف، أن أنه المحادثةُ غير موجودة,أو أنك نسيت اضافتي هناك، تأكد من هذا و حاول مجددا.',
- ['4'] = 'فقط المحادثات و القنوات، لايمكن اختبار مستخدم!',
- ['5'] = 'لا يبدو انك مشرف في تلك محادثه !',
- ['6'] = 'على ما يبدو، إنه المحادثة قيد الاستخدام من قبلي فعلا، استعمل /logchat بتحديد واحده جديده.',
- ['7'] = 'تبدو المحادثه جيده سوف ارسل رساله تجريبيه اليها للتاكد فحسب انني املك حقوق ارسال الرسائل!',
- ['8'] = 'مرحبا ايها العالم - هذه رساله تجريبيه - اذا كنت تقراها فان كل شيء على ما يرام!',
- ['9'] = 'تم بنجاح! من الان فصاعدا سوف يرسل الجميع السجلات الى %s - لتغيير المحادثه المرسله اليه الاحداث ارسل /logchat.',
- },
- ['lua'] = {
- ['1'] = 'ادخل معطيات Lua',
- },
- ['lyrics'] = {
- ['1'] = 'Spotify',
- ['2'] = 'اظهار كلمات الاغنيه',
- ['3'] = 'ادخل كلمه البحث(لاغنيه/الفنان الذي تريد مني إحضار كلمات اغنيت، مثال "This is america" سوف يكون رد البوت كلمات هذه الاغنيه.',
- },
- ['minecraft'] = {
- ['1'] = '<b> قام المستخدم %s بتغير اسمه بمرة %s</b>',
- ['2'] = '<b>قام المستخدم %s بتغيير اسمه %s مرات</b>',
- ['3'] = 'السابق',
- ['4'] = 'التالي',
- ['5'] = 'رجوع',
- ['6'] = 'UUID',
- ['7'] = 'الصور الشخصية',
- ['8'] = 'تاريخ المعرف',
- ['9'] = 'حدد اختياراً:',
- ['10'] = 'ادخل اسم لاعب الماينكرافت الذي تريد عرض معلوماته،(مثال ارسال "cucumber" لعرض معلومات اللاعب المسمى cucumber).',
- ['11'] = 'اسماء الماينكرافت تتراوح بين 3 إلى 16 كحد أقصى.'
- },
- ['msglink'] = {
- ['1'] = 'الامر المجموعات فقط و القنوات.',
- ['2'] = 'هذا %s يجب أن يكون عام ليس خاصا.',
- ['3'] = 'رد على الرسالة المطلوبة رابطه.'
- },
- ['mute'] = {
- ['1'] = 'من يجب علي كتمه؟ حدد بواسطه المعرف @username او ID أو الرد.',
- ['2'] = 'لا استطيع كتم هذا الشخص لانه مكتوم اصلا .',
- ['3'] = 'لا استطيع كتم المشرفين او منشئين.',
- ['4'] = 'لا استطيع كتم هذا المستخدم لانه غادر المجموعه بالفعل -او قد طرد منه هو-.',
- ['5'] = 'احتاج أوامر الإشراف لكي احظر المستخدمين، رجاءا اصلح هذا وحاول مجددا.',
- },
- ['myspotify'] = {
- ['1'] = 'الصفحه شخصيه',
- ['2'] = 'يتابع',
- ['3'] = 'المشغله مؤخرا',
- ['4'] = 'يتم التشغيل الان',
- ['5'] = 'الاغاني المشهوره',
- ['6'] = 'صناع الاغاني المشهورين',
- ['7'] = 'لست تتابع اي فنانين!',
- ['8'] = 'الفنانين المفضلين لديك',
- ['9'] = 'لاتملك اي اغاني في قائمة التشغيل!',
- ['10'] = 'اغانيك المفضله',
- ['11'] = 'لا يبدو انك تتابعوا اية فنانين',
- ['12'] = 'الفنانين الذين تتابعهم',
- ['13'] = 'لا تملك اغاني تم تشغيلها مؤخرا!',
- ['14'] = '<b>المشغله مؤخرا</b>\n%s %s\n%s %s\n%sتم الاستماع عند %s:%s في %s/%s/%s.',
- ['15'] = 'تم قبول طلب التكمله ولكن العمليه لم تكتمل.',
- ['16'] = 'لا يبدو انك تستمع على اية اغاني الان!',
- ['17'] = 'يتم تشغيلها حاليا',
- ['18'] = 'حدثت مشكله عند اعاده اعطاء الاذن لحسابك!',
- ['19'] = 'تم اعاده اعطاء الاذن بنجاح لحساب Spotify! جاري اكمال طلبك السابق...',
- ['20'] = 'جاري اعاده اعطاء الاذن لحسابك في Spotify, يرجى الانتظار...',
- ['21'] = 'يجب ان تعطي الاذن ل mattata إذن اتصال مع حسابك في. اضغط [هنا](https://accounts.spotify.com/en/authorize؟client_id=%s&response_type=code&redirect_uri=%s&scope=user-library-read,playlist-read-private,playlist-read-collaborative,user-read-private,user-read-email,user-follow-read,user-top-read,user-read-playback-state,user-read-recently-played,user-read-currently-playing,user-modify-playback-state) اضغط على الزر الاخظر"اوكي". لربط حسابك, ارسل الرابط الذي تم تحويلك اليه (يجب ان يبدا هكذا "%s", متبوعا بكود المميز) ردا لهذه الرسالة.',
- ['22'] = 'قائمة تشغيل',
- ['23'] = 'استخدام وضع Inline',
- ['24'] = 'الكلمات',
- ['25'] = 'لم يتم العثور على الاجهزه.',
- ['26'] = 'ليست لديك قائمة تشغيل.',
- ['27'] = 'قائمة تشغيلك',
- ['28'] = '%s %s [%s اغاني]',
- ['29'] = '%s %s [%s]\nSpotify %s المستخدم\n\n<b>الاجهزة:</b>\n%s',
- ['30'] = 'جاري تشغيل الاغنيه السابقه...',
- ['31'] = 'انت الان مستخدمون مدفوع!',
- ['32'] = 'لم اعثر على اي اجهزه.',
- ['33'] = 'جاري تشغيل الاغنيه التاليه...',
- ['34'] = 'جاري استئناف الاغنيه...',
- ['35'] = 'اجهزتك غير متاحه مؤقتا...',
- ['36'] = 'لم احصل على الاجهزه!',
- ['37'] = 'جاري ايقاف الاغنيه...',
- ['38'] = 'مشغل حاليا',
- ['39'] = 'اختيار عشوائي لأغانيك...',
- ['40'] = 'الصوت غير مدعوم يرجى الاختيار قيمه تتراوح من 0 الى 100.',
- ['41'] = 'تم ضبط الصوت الى %s%%!',
- ['42'] = 'هذه الرساله تستخدمه اضافه من اصدار قديم، طلب واحده جديده بارسال /myspotify!'
- },
- ['name'] = {
- ['1'] = 'الاسم الذي ارد عليه حاليا هي "%s" - لو اردت تغييره ارسل /name <نص> (حيث <نص> هو ما تريدني ان ارد عليه).',
- ['2'] = 'اسمي الجديد يجب ان يتراوح بين 2 الى 32 احرف!',
- ['3'] = 'اسمي يمكن هو الاحتواء وعلى الأحرف اللاتينية فقط!',
- ['4'] = 'سوف اجيب الى "%s", بدل امين "%s" - لتغيير هذا مجددا ارسل /name <كلمه> حيث <كلمه> هي ما تريدني ان اجيب عليه.)'
- },
- ['netflix'] = {
- ['1'] = 'اقرا المزيد.'
- },
- ['news'] = {
- ['1'] = '"<code>%s</code>" ليست صيغه Lua صالحة.',
- ['2'] = 'لم استطع الحصول على لائحه المصادر.',
- ['3'] = '<b> تم الحصول على موارد الاخباريه تطابق </b> "<code>%s</code>":\n\n%s',
- ['4'] = '<b> قائمه المصادر الاخبار </b> /news<b>. Use</b> /nsources &lt;query&gt; <b> البحث في قائمه الاخبار في نتيجه اكثر دقه،، تطابق نتائج البحث هي باستعمال اللغه Lua</b>\n\n%s',
- ['5'] = 'لا تملك مصدر أخبار مفظلة. ارسل /setnews <المصدر> لضبط واحدة. اظهر لائحة المصادر بإرسال /nsources, أو قلل النتائج باستعمال /nsources <المعطيات>.',
- ['6'] = 'مصدرك الاخباري المفظل هي %s. استعمل /setnews <المصدر> لتغييره. أعرض اللائحة من /nsources, أو قلل النتائج باستعمال /nsources <المعطيات>',
- ['7'] = 'مصدرك المغزى بالفعل %s! استعمل /news لعرض آخر الاحداث.',
- ['8'] = 'المصدر غير مدعوم، أعرض اللائحة من /nsources ,أو قلل النتائج باستعمال /nsources <المعطيات>.',
- ['9'] = 'مصدرك المفضل تم تحديثه إلى %s! استعمل /news لعرض آخر الأخبار.',
- ['10'] = 'المصدر غير مدعوم، أعرض اللائحة المصادر من /nsources. إذا لديك مصدر مفظل استعمل /setnews <المصدر> لتحصل على الأخبار منها عند إرسال /news, بدون جمل اضافيه',
- ['11'] = 'اقرا المزيد.'
- },
- ['nick'] = {
- ['1'] = ' اسمك المستعار تم نسيانه !',
- ['2'] = ' اسمك المستعار تم ضبطه إلى "%s"!'
- },
- ['ninegag'] = {
- ['1'] = 'اقرا المزيد'
- },
- ['optout'] = {--dead util
- ['1'] = 'لقد انضممت إلى تجميع بياناتك المرسلة! ارسل /optout للخروج.',
- ['2'] = 'لقد خرجت من تجميع بياناتك المرسلة! ارسل /optoin للسماح.',
- },
- ['paste'] = {
- ['1'] = 'حدد خدمة لرفع النص إليه:'
- },
- ['pay'] = {
- ['1'] = 'لديك حاليا %s عملات Matt. حصل المزيد بالفوز في الالعاب XO, بأستعمال /game - ستربح 100 عملاتMatt لكل فوز, و ستخسر 50 لكل خسارة.',
- ['2'] = 'يجب استعمال الامر ردا على الشخص، لإرسال العملات له.',
- ['3'] = 'حدد كمية العملات لاعطائها إلى %s.',
- ['4'] = 'الكمية تكون رقمية فقط، واكبر من 0.',
- ['5'] = 'لا يمكن إرسال العملات لنفسك',
- ['6'] = 'لا يوجد رصيد كافي لإكمال التحويل!',
- ['7'] = 'لقد ارسلت%s عملات إلى %s. كمية عملتلك الآن هي %s.'
- },
- ['pin'] = {
- ['1'] = 'لم تضبط رسالة مثبتة سابقاً. استعمل /pin <النص> لتثبيت واحدة. تغييرات الخط،، أي الماركداون مدعومة.',
- ['2'] = 'اخر رسالة تم تثبيتها بالأمر /pin.',
- ['3'] = 'وجدت تثبيتا جديدا في قاعدة البيانات،، ولكن رسالتي المرسولة تبدو محذوفة,فلا يمكنني إيجادها، اضبط واحدة جديدية بالأمر /pin <النص>. تغييرات الخطوط مدعومة.',
- ['4'] = 'فشل تجديد الرسالة المثبتة. اما ان نصك المدخل يحوي كلمات خاطئة، أو أن الرسالة المثبتة ممسوحة. سأرسل لك رسالة مثبتة جديدة- لو أردت تعديلها بعد التأكد من وجودها,استعمل /pin <النص>.',
- ['5'] = 'نصك المدخل يحوي كلمات ماركداون خاطئه.',
- ['6'] = 'اضغك هنا الرواية رسالة التثبيت المحدثة ↬.'
- },
- ['pokedex'] = {
- ['1'] = 'الاسم: %s\nID: %s\nالنوع: %s\nالوصف: %s'
- },
- ['prime'] = {
- ['1'] = 'ادخل رقما بين 1 إلى 99999.',
- ['2'] = ' الرقم %s اساسي!',
- ['3'] = 'الرقم %s ليس اساسياً...'
- },
- ['promote'] = {
- ['1'] = ' لا أستطيع الترقية لأنه من المشرفين و المنشئين.',
- ['2'] = 'لا أستطيع ترقية هذا الشخص لأنه خارج المجموعة.',
- ['3'] = 'لا يمكنني ترقيه هذا الشخص لأنه مطرود من المجموعة.',
- },
- ['quote'] = {
- ['1'] = 'هذا المستخدم رفض خاصية تجميع البيانات.',
- ['2'] = 'لا يوجد "اقتباسات" مخزونة ل %s! أصنع بوساطة /save ردا على رسالتهم .'
- },
- ['randomsite'] = {
- ['1'] = 'اصنع غيرها'
- },
- ['randomword'] = {
- ['1'] = 'تم الصنع',
- ['2'] = 'كلمتك العشوائية هي <b>%s</b>!'
- },
- ['report'] = {
- ['1'] = 'قم بالرد على رسالته، لابلاغ الشخص للمشرفين.',
- ['2'] = 'لا يمكنك إبلاغ نفسك، هل تظن نفسك أضحوكة XD؟',
- ['3'] = '<b>يحتاج %s المساعدة في %s!</b>',
- ['4'] = 'اضغط لعرض الإبلاغ.',
- ['5'] = 'تم إبلاغ الرسالة للمشرفين بنجاح إلى %s من المشرفين!'
- },
- ['rms'] = {
- ['1'] = 'يا ربتاه منك يا GNU!'
- },
- ['save'] = {
- ['1'] = 'هذا المستخدم رفض خاصية تجميع البيانات.',
- ['2'] = 'خزنتها لقاعدتي البيانية, و اضفتها الى الردود المتوقعه عند استعمال /quote ردا على %s!'
- },
- ['sed'] = {
- ['1'] = '%s\n\n<i>%s لم ينوي قول هذا!</i>',
- ['2'] = '%s\n\n<i>%s اعترف بالهزيمة</i>',
- ['3'] = '%s\n\n<i>%s غير متأكد من خطئه ...</i>',
- ['4'] = 'اسكت فحسب, <i>أنا لا اخطى ابدا😌 ؟</i>',
- ['5'] = '"<code>%s</code>" ليس كودا صالحا.',
- ['6'] = 'Hey %s, %s seems to think you meant:\n<i>%s</i>',
- ['7'] = 'نعم',
- ['8'] = 'لا',
- ['9'] = 'ربما',
- ['10'] = 'Just edit your message, idiot.'
- },
- ['setgrouplang'] = {
- ['1'] = 'تم تغيير لغة المجموعة إلى %s!',
- ['2'] = 'لغتنا الحالية هنا هي %s.\nيرجى العلم ان بعض الكلمات غير مترجمة من قبل الناس، حاليا. اضغط لاختيار لغتك المفضلة من اللوحة أدناه :',
- ['3'] = 'الاختيار لاجبار متاتا للرد على الانكليزي فقط معطل حاليا. فعله من الأمر /administration ولكن, لجعلها أسهل لك,وضعتها ادناه.',
- ['4'] = 'تفعيل',
- ['5'] = 'تعطيل'
- },
- ['setlang'] = {
- ['1'] = 'تم ضبط لغتك إلى %s!',
- ['2'] = 'لغتك الحالية %s.\n ربما ليس كل الكلمات مترجمة حاليا. لو أردت تغيير اللغة, حدد من اللوحة المفاتيح:'
- },
- ['setlink'] = {
- ['1'] = 'رابط غيُر صالح.',
- ['2'] = 'تم بنجاح!'
- },
- ['setrules'] = {
- ['1'] = 'خطوط غير مدعومة.',
- ['2'] = 'تم ضبط القوانين!'
- },
- ['setwelcome'] = {
- ['1'] = 'ضبط رسالة الترحيب؟ سيرسل الترحيب للأعضاء الجدد(يمكن تعديلها بارسال /help ثم قسم الادمنية, أو بالأمر /administration). يمكن استعمال أشياء مذهلة ايضا. مثل $name اكتبه بالرسالة الترحيب فيكتب اسم الشخص المرحب به او, $chat_id الكتابه ID المحادثة في الرسالة الترحيبية, $user_id لكتابة ID الشخص المرحب به, $title لادخال اسم المحادثة $username لادخال المعرف الشخص المركزي به برسالة الترحيب( إذا المستخدم لا يتكلم اسم المستخدم سيتم استخدام اسمه بدلا من ذلك،).',
- ['2'] = 'هناك مشكلة بصيغة الملف, تأكد من الماركداون أي كود الخطوط، وحاول مجددا.',
- ['3'] = 'تم حفظ الرسالة ل%s بنجاح!'
- },
- ['share'] = {
- ['1'] = 'شارك'
- },
- ['shorten'] = {
- ['1'] = 'حدد خادما من الأزرار ادناه:'
- },
- ['shsh'] = {
- ['1'] = 'لم استقبل رد السيرفر لأي SHSH، لهذه ECID, تأكد من صحتها وأنك حفظته من https://tsssaver.1conan.com.',
- ['2'] = 'ال SHSH ، لهذا الجهاز متاح لهذه الاصدارات من Ios:\n',
- ['3'] = 'نزل .zip'
- },
- ['statistics'] = {
- ['1'] = 'لم يرسل ايه رسائل هنا!',
- ['2'] = '<b>الإحصائيات لهذا:</b> %s\n\n%s\n<b>إجمالي إرسال الرسائل:</b> %s',
- ['3'] = 'تم المسح الإحصائيات!',
- ['4'] = 'فشلت في المسرح، ربما هي ممسوحة اصلا؟'
- },
- ['steam'] = {
- ['1'] = 'اسم المستخدم تم ضبتها إلى "%s".',
- ['2'] = '"%s" ليست اسما صالحا.',
- ['3'] = 'المسخدم %s عضو منذ %s, عند %s. آخر تسجيل خروج عند %s, في %s. اضغط <a href="%s">هنا</a> لعرض الصفحه في ستيم.',
- ['4'] = '%s, AKA "%s",'
- },
- ['synonym'] = {
- ['1'] = 'الكلمة <b>%s</b>, يبدو احسن من %s.'
- },
- ['thoughts'] = {
- ['1'] = '%s\n\nايجابي: <code>%s%% [%s]</code>\nسلبي: <code>%s%% [%s]</code>\nمحير: <code>%s%% [%s]</code>\nإجمالي الافكار: <code>%s</code>'
- },
- ['tobinary'] = {
- ['1'] = 'ادخل الكلمات لتحويلها إلى أرقام ثنائية.'
- },
- ['trust'] = {
- ['1'] = 'لا أستطيع الثقة لأنه من المشرفين و المنشئين بالفعل.',
- ['2'] = 'لا أستطيع الثقة بهذا الشخص لأنه خارج المجموعة اصلا.',
- ['3'] = 'لا يمكنني الثقة بهذا الشخص لأنه مطرود من المجموعة.',
- },
- ['unmute'] = {
- ['1'] = 'من يجب علي فك كتمه؟ حددهم باستخدام @username او ID.',
- ['2'] = 'لا يمكنني فك الكتم من هذا الشخص لأنه ليس مكتوم اصلا.',
- ['3'] = 'لا أستطيع فك الكتم لأنه من المشرفين و المنشئين.',
- ['4'] = 'لا أستطيع فك الكتم من هذا الشخص لأنه خرج من المجموعة أو انطرد.',
- },
- ['untrust'] = {
- ['1'] = 'من يجب علي إلغاء الثقة به؟ حددهم باستخدام @username او ID.',
- ['2'] = 'لا أستطيع إلغاء الثقة لأنه من المشرفين و المنشئين بالفعل.',
- ['3'] = 'لا أستطيع الغاء الثقة بهذا الشخص لأنه خارج المجموعة اصلا.',
- ['4'] = 'لا يمكنني إلغاء الثقة بهذا الشخص لأنه مطرود من المجموعة.',
- },
- ['upload'] = {
- ['1'] = 'رد على الملف، يجب أن يكون < 20 MB.',
- ['2'] = 'ملف كبير جدا اجعله < 20 MB.',
- ['3'] = 'لا يمكنني الحصول على الملفات القديمة هنا.',
- ['4'] = 'حصلت مشكلة أثناء التنزيل.',
- ['5'] = 'تم التنزيل...- أحصل عليه من هنا <code>%s</code>!'
- },
- ['version'] = {
- ['1'] = '@%s AKA %s `[%s]` is running mattata %s, created by [Matthew Hesketh](https://t.me/wrxck). The source code is available on [GitHub](https://github.com/wrxck/mattata).'
- },
- ['voteban'] = {
- ['1'] = 'من تريدني أن أفتح له الحظر بالتصويت؟ حددهم بواسطة @username أو ID.',
- ['2'] = 'لا استطيع أن أفتح له الحظر بالتصويت لأنه مدير أو مشرف.',
- ['3'] = 'لا استطيع أن أفتح له الحظر بالتصويت لأنه خارج المجموعة.',
- ['4'] = 'هل يجب حظر %s [%s] من %s؟ نحتاج %s من التصويت لحظره ,و %s من رفض التصويت لإغلاق هذا.',
- ['5'] = 'نعم [%s]',
- ['6'] = 'لا [%s]',
- ['7'] = 'هذا مطلب الناس لقد حظرت %s [%s] من %s لأن %s صوتوا لهذا.',
- ['8'] = 'تم تلبية الحظ الأدنى, على كلٍ, لا أستطيع حظر %s - ربما انطردوا أو خرجوا أو تمت ترقيتهم وقت فتح التصويت، أو اخذت مني صلاحية الحظر',
- ['9'] = 'هذا مطلب الناس. لم احظر %s [%s] من %s لأن الناس المطلوبين %s رفضوا الحظر.',
- ['10'] = 'لقد اخترت حظر %s [%s]!',
- ['11'] = ' لقد تراجعت عن اختيارك, اختر من جديد.',
- ['12'] = 'لقد رفضت حظر %s [%s]!',
- ['13'] = 'الحظر بالتصويت مفتوح فعلا لهذا الشخص..!'
- },
- ['weather'] = {
- ['1'] = 'لا موقع لديك. استخدم /setloc <الموقع> لضبط واحدة.',
- ['2'] = 'الان %s (يبدو مثل %s) في %s. %s'
- },
- ['welcome'] = {
- ['1'] = 'قوانين المجموعة'
- },
- ['whitelist'] = {
- ['1'] = 'من علي اعفاءه؟ حدد باستخدام المعرف أو ID.',
- ['2'] = 'لا أستطيع وضعه في القائمة البيضاء لأنه مدير أو مشرف فلا داعي لهذا.',
- ['3'] = 'لا أستطيع وضعه في القائمة البيضاء لأنه خارج المجموعة.',
- ['4'] = 'لا أستطيع وضعه في القائمة البيضاء لأنه محظور.',
- },
- ['wikipedia'] = {
- ['1'] = 'اقرأ المزيد.'
- },
- ['youtube'] = {
- ['1'] = 'السابق',
- ['2'] = 'التالي',
- ['3'] = 'انت في الصفحة %s من %s!'
- }
-}
\ No newline at end of file
diff --git a/languages/de_at.lua b/languages/de_at.lua
deleted file mode 100644
index 81d1151..0000000
--- a/languages/de_at.lua
+++ /dev/null
@@ -1 +0,0 @@
-return require('languages.de_de')
\ No newline at end of file
diff --git a/languages/de_de.lua b/languages/de_de.lua
deleted file mode 100644
index a500f5e..0000000
--- a/languages/de_de.lua
+++ /dev/null
@@ -1,783 +0,0 @@
--- This is a language file for mattata
--- Language: de-de
--- Author: LKD70, CodeNameT1M
-
--- DO NOT CHANGE ANYTHING THAT BEGINS OR ENDS WITH A %
--- THESE ARE PLACEHOLDERS!
-
--- DO NOT CHANGE ANY MARKDOWN/HTML FORMATTING!
--- IF YOU ARE UNSURE, ASK ON TELEGRAM (t.me/mattataDev)
-
-return {
- ['errors'] = {
- ['connection'] = 'Verbindungs-fehler.',
- ['results'] = 'Kein Ergebnis gefunden.',
- ['supergroup'] = 'Dieser Befehl kann nur in Supergruppen benutzt werden.',
- ['admin'] = 'Für diesen Befehl musst du ein Moderator oder Administrator in dieser Gruppe sein.',
- ['unknown'] = 'Ich kann den Benutzer nicht erkennen. Wenn du mich lehren möchtest wer dieser Benutzer ist, dann leite einfach eine Nachricht von diesem Benutzer in eine Gruppe in der ich auch bin .',
- ['generic'] = 'Ein Fehler ist passiert!',
- ['use'] = 'Du hast keine Benutzungserlaubnis!',
- ['private'] = 'Du kannst diesen Command nur im Privatchat nutzen!'
- },
- ['addcommand'] = {
- ['1'] = 'Bitte Spezifiziere den Command so: <code>/command - description</code>',
- ['2'] = 'Ich konnte meine Befehle nicht abrufen!',
- ['3'] = 'Die Beschreibung des Comands darf nicht länger als 256 Zeichen sein!',
- ['4'] = 'Ein unbekannter fehler ist passiert, ich war nicht in der Lage den Command hinzuzufügen!',
- ['5'] = 'Command wurde erfolgreich hinzugefügt.'
- },
- ['addrule'] = {
- ['1'] = 'Bitte spezifiziere die Regel die du hinzufügen willst!',
- ['2'] = 'Du hast keine Regeln zum hinzufügen! Bitte erstelle Regeln mit dem Befehl /setrules!',
- ['3'] = 'Ich konnte diese Regel nicht hinzufügen, da so die Länge der Regel zu lang wäre und Telegram\'s 4096 Zeichen limit überschreiten würde!',
- ['4'] = 'Ich konnte diese Regel nicht hinzufügen, es scheint so als würde es nicht zulässige Markdown-Formatierungen beinhalten!',
- ['5'] = 'Regeln wurden erfolgreich aktualisiert!'
- },
- ['addslap'] = {
- ['1'] = 'Du kannst diesen Befehl nur in Gruppen benutzen!',
- ['2'] = 'Der slap darf keine { oder } außerhalb der Platzhalter haben!',
- ['3'] = 'Der slap darf nicht länger als 256 Zeichen sein!',
- ['4'] = 'Ich habe erfolgreich diesen slap hinzugefügt als eine Möglichkeit für /slap in dieser Gruppe!',
- ['5'] = 'Du musst Platzhalter benutzen im slap. Benutze {ME} für die Person die den Befehl benutzt und {THEM} für das Opfer.'
- },
- ['administration'] = {
- ['1'] = 'Aktiviere Administration',
- ['2'] = 'Deaktiviere Administration',
- ['3'] = 'Anti-Spam Einstellungen',
- ['4'] = 'Warn-Einstellungen',
- ['5'] = 'Vote-Bann Eintellungen',
- ['6'] = 'Neue User begrüßen?',
- ['7'] = 'Regeln senden bei Beitritt?',
- ['8'] = 'Regeln in Gruppe senden?',
- ['9'] = 'Zurück',
- ['10'] = 'Weiter',
- ['11'] = 'Wort Filter',
- ['12'] = 'Anti-Bot',
- ['13'] = 'Anti-Link',
- ['14'] = 'Aktionen loggen?',
- ['15'] = 'Anti-RTL',
- ['16'] = 'Anti-Spam Aktion',
- ['17'] = 'Bann',
- ['18'] = 'Kick',
- ['19'] = 'Commands löschen?',
- ['20'] = 'Gruppen-Sprache erzwingen?',
- ['21'] = 'Einstellungen in Gruppe senden?',
- ['22'] = 'Antwort löschen bei Aktion?',
- ['23'] = 'Captcha benötigt?',
- ['24'] = 'Inline Captcha benutzen?',
- ['25'] = 'Banne SpamWatch-markierte Benutzer?',
- ['26'] = 'Anzahl der Warunungen bis %s:',
- ['27'] = 'Upvotes benötigt für Bann:',
- ['28'] = 'Downvotes benötigt für ignorieren:',
- ['29'] = 'Löschte %s, war ein passender Link von der Database!',
- ['30'] = 'Keine Einträge vorhanden in der database passend zu "%s"!',
- ['31'] = 'Du bist kein Administrator in dieser Gruppe!',
- ['32'] = 'Die minimale Anzahl von upvotes benötigt für einen vote-bann ist %s.',
- ['33'] = 'Die maximale Anzahl von upvotes benötigt für einen vote-bann ist %s.',
- ['34'] = 'Die minimale Anzahl von downvotes benötigt für einen vote-bann ist %s.',
- ['35'] = 'Die maximale Anzahl von downvotes benötigt für einen vote-bann ist %s.',
- ['36'] = 'Die maximale Anzahl von Warnungen ist %s.',
- ['37'] = 'Die minimale Anzahl von Warnungen ist %s.',
- ['38'] = 'Du kannst ein oder mehrere Wörter hinzufügen zum Wort Filter mit /filter <Wort>',
- ['39'] = 'Du wirst nicht länger dran erinnert, das das Administrations-Plugin abgeschaltet ist. Um es anzuschalten, benutze /administration.',
- ['40'] = 'Das ist kein zulässiger Chat!',
- ['41'] = 'Es sieht nicht so aus, als wärst du Administrator in diesem Chat!',
- ['42'] = 'Meine Administrativen funktionen können nur in Gruppen benutzt werden! Wenn du Hilfe brauchst meine administrativen Funktionen zu nutzen, schau mal in den "Administration" Bereich bei /help! Alternativ, wenn du die Winstellungen einer Gruppe ändern willst die du Administrierst, du kannst das Hier tun mit dem Befehl /administration <chat>.',
- ['43'] = 'Benutze die Knöpfe unten um die Administrativen Einstellungen zu ändern von <b>%s</b>:',
- ['44'] = 'Bitte sende mir eine [private message](https://t.me/%s), damit ich dir diese Information schicken kann.',
- ['45'] = 'Ich habe dir die angefragten Informationen privat zugeschickt.',
- ['46'] = 'Entferne Channel Pins?',
- ['47'] = 'Entferne Other Pins?',
- ['48'] = 'Entferne Code?',
- ['49'] = 'Blockiere Inline Bots?',
- ['50'] = 'Kick Medien bei Beitritt?',
- ['51'] = 'Aktiviere Plugins für Admins?',
- ['52'] = 'Kick URLs bei Beitritt?'
- },
- ['afk'] = {
- ['1'] = 'Tut mir leid. Dieses Feature ist nur dann verfügbar, wenn der Benutzer einen öffentlichen @Benutzername hat!',
- ['2'] = '%s ist wieder zurück nachdem er/sie nicht anwesend war für %s!',
- ['3'] = 'Notiz',
- ['4'] = '%s ist nicht anwesend.%s'
- },
- ['antispam'] = {
- ['1'] = 'Abschalten',
- ['2'] = 'Anschalten',
- ['3'] = 'Deaktiviere Limit',
- ['4'] = 'Aktiviere limits von %s',
- ['5'] = 'Alle Administrations-Einstellungen',
- ['6'] = '%s [%s] hat %s [%s] gekickt von %s [%s] für überschreiten des eingestellten anti-spam limits für [%s] Medien.',
- ['7'] = 'Kickte %s für Überschreitung des eingesellten antispam limits für [%s] Medien.',
- ['8'] = 'Das maximale Limit ist 100.',
- ['9'] = 'Das minimale Limit ist 1.',
- ['10'] = 'Ändere die Anti-Spam Einstellungen für %s unten:',
- ['11'] = 'Hey %s, wenn du Code sendest der länger ist als %s Zeichen, bitte nutze stattdessen /paste im <a href="https://t.me/%s">privatem Chat mit mir</a>!',
- ['12'] = '%s <code>[%s]</code> hat %s %s <code>[%s]</code> von %s <code>[%s]</code> für das verschicken von Telegram-Einladungslinks.\n#chat%s #user%s',
- ['13'] = '%s %s für das verschicken von Telegram-Einladungslinks.',
- ['14'] = 'Hey, Ich habe gemerkt das du anti-link aktiviert hast und du deinen Nutzern nicht erlaubst einen Chat zu erwähnen den du gerade erwähnt hast,wenn du das erlauben willst, nutze /allowlink <links>.',
- ['15'] = 'Kickte %s <code>[%s]</code> von %s <code>[%s]</code> für das Senden von Medien in den ersten paar Nachrichten.\n#chat%s #user%s',
- ['16'] = 'Kickte %s <code>[%s]</code> von %s <code>[%s]</code> für das Senden von URLs in den ersten paar Nachrichten.\n#chat%s #user%s',
- ['17'] = 'Action',
- ['18'] = 'Kick',
- ['19'] = 'Ban',
- ['20'] = 'Mute'
- },
- ['appstore'] = {
- ['1'] = 'Ansehen in iTunes',
- ['2'] = 'Bewertung',
- ['3'] = 'Bewertungen'
- },
- ['authspotify'] = {
- ['1'] = 'Du bist schon authorisiert mit diesem Account.',
- ['2'] = 'Authorisierung, bitte warten...',
- ['3'] = 'Ein verbindungs-Fehler ist passiert. Bist du dir sicher das der Link Korrekt war? Es sollte aussehen wie',
- ['4'] = 'Erfolgreich authorisiert mit deinem Spotify-Account!'
- },
- ['avatar'] = {
- ['1'] = 'Ich konnte kein Profilbild für den Benutzer abrufen. Bitte sorge dafür, dass du einen gültigen Benutzername oder eine gültige Identifikationsnummer angegeben hast.',
- ['2'] = 'Dieser Benutzer hat keine Profilbilder.',
- ['3'] = 'Dieser Benutzer hat nicht viele Profilbilder!',
- ['4'] = 'Dieser Benutzer ist opted out(ausgetreten) von der Datensammlung funktionalität, deswegen ist es mir nicht möglich die Profil Bilder anzuzeigen.',
- ['5'] = 'User: %s\nPhoto: %s/%s\nSend /avatar %s [offset] to @%s to view a specific photo of this user',
- ['6'] = 'User: %s\nPhoto: %s/%s\nUse /avatar %s [offset] to view a specific photo of this user'
- },
- ['ban'] = {
- ['1'] = 'Welchen Benutzer soll ich sperren? Du kannst den Benutzer mit dem Benutzernamen oder mit der Identifikationsnummer angeben.',
- ['2'] = 'Ich kann diesen Benutzer nicht sperren, weil er/sie ein Moderator oder Administrator in dieser Gruppe ist.',
- ['3'] = 'Ich kann diesen Benutzer nicht sperren, weil er/sie die Gruppe schon verlassen hat.',
- ['4'] = 'Ich kann diesen Benutzer nicht sperren, weil er/sie für die Gruppe schon gesperrt ist.',
- ['5'] = 'Ich muss Administrationsberechtigung haben damit ich den Benutzer sperren kann. Bitte kümmer dich um das Problem und versuche es noch einmal.',
- ['6'] = '%s <code>[%s]</code> hat %s <code>[%s]</code> gebannt von %s <code>[%s]</code>%s.\n%s %s',
- ['7'] = '%s hat %s%s gebannt.'
- },
- ['bash'] = {
- ['1'] = 'Zum durchführen gebe bitte einen Befehl an!',
- ['2'] = 'Erfolg!'
- },
- ['blocklist'] = {
- ['1'] = 'Welchen Benutzer soll ich auf die Block-Liste setzen? Du kannst den Benutzer mit dem Benutzernamen oder mit der Identifikationsnummer angeben.',
- ['2'] = 'Ich kann diesen Benutzer nicht auf die Block-Liste setzen, weil er/sie ein Moderator oder Administrator in dieser Gruppe ist.',
- ['3'] = 'Ich kann diesen Benutzer nicht auf die Block-Liste setzen, weil er/sie die Gruppe schon verlassen hat.',
- ['4'] = 'Ich kann diesen Benutzer nicht auf die Block-Liste setzen, weil er/sie für die gruppe schon gesperrt ist.',
- ['5'] = '%s <code>[%s]</code> has blocklisted %s <code>[%s]</code> from using %s <code>[%s]</code> in %s <code>[%s]</code>%s.\n%s %s',
- ['6'] = '%s has blocklisted %s from using %s%s.'
- },
- ['blocklistchat'] = {
- ['1'] = '%s ist nun auf der Block-Liste. Ich will euch auch verlassen wenn ich hinzugefügt werde!',
- ['2'] = '%s ist ein Benutzer. Dieser Befehl ist für die Block-Liste von Unterhaltungen wie Gruppen und Kanäle!',
- ['3'] = '%s ist keine gültige Gruppe!'
- },
- ['bugreport'] = {
- ['1'] = 'Erfolg! Dein Fehlerbericht wurde gesendet. Die Identifikationsnummer für diesen Bericht ist #%s.',
- ['2'] = 'Es ist ein Fehler aufgetreten mit dem Fehlerbericht!'
- },
- ['calc'] = {
- ['1'] = 'Zum senden des Ergebnis klicken.',
- ['2'] = '"%s" was an unexpected word!',
- ['3'] = 'You cannot have a unit before a number!'
- },
- ['captionbotai'] = {
- ['1'] = 'Ich kann das Bild wirklich nicht beschreiben!'
- },
- ['cats'] = {
- ['1'] = 'Miau!'
- },
- ['channel'] = {
- ['1'] = 'Du bist nicht berechtigt zum benutzen!',
- ['2'] = 'Es sieht so aus als wärst du nicht mehr ein Administrator dieser Gruppe!',
- ['3'] = 'Ich konnte deine Nachricht nicht senden. Bist du sicher, dass ich immer noch befugt bin zum senden von Nachrichten in dieser Gruppe?',
- ['4'] = 'Deine Nachricht ist gesendet!',
- ['5'] = 'Es war mir nicht möglich eine List mit Administratoren von dieser Gruppe zu bekommen!',
- ['6'] = 'Es sieht so aus als wärst kein Administrator dieser Gruppe!',
- ['7'] = 'Bitte spezifiere die Nachricht und benutze den Syntax /channel <Kanal> <Nachricht>.',
- ['8'] = 'Bist du dir sicher, dass du die nachricht senden möchtest? Das ist wie es ausehen wird:',
- ['9'] = 'Ja, ich bin sicher!',
- ['10'] = 'Diese Nachricht hat ein falsches Format! Bitte korigiere den Syntax und versuche es noch einmal.'
- },
- ['chatroulette'] = {
- ['1'] = 'Hey! Please don\'t send messages longer than %s characters. We don\'t want to annoy the other user!',
- ['2'] = '*Anonymous said:*\n```\n%s\n```\nTo end your session, send /endchat.',
- ['3'] = 'I\'m afraid I lost connection from the other user! To begin a new chat, please send /chatroulette!',
- ['4'] = 'The other person you were chatting with has ended the session. To start a new one, send /chatroulette.',
- ['5'] = 'Successfully ended your session. To start a new one, send /chatroulette.',
- ['6'] = 'I have successfully removed you from the list of available users.',
- ['7'] = 'You don\'t have a session set up at the moment. To start one, send /chatroulette.',
- ['8'] = 'Finding you a session, please wait...',
- ['9'] = 'I\'m afraid there aren\'t any available users right now, but I have added you to the list of available users! To stop this completely, please send /endchat.',
- ['10'] = 'I have successfully paired you with another user to chat to! Please remember to be kind to them! To end the chat, send /endchat.',
- ['11'] = 'I\'m afraid the user who I tried to pair you with has since blocked me. Please try and send /chatroulette again to try and connect to me!',
- ['12'] = 'I have successfully paired you with another user to chat to! Please remember to be kind to them! To end the chat, send /endchat.'
- },
- ['commandstats'] = {
- ['1'] = 'Es wurden keine Befehle in dieser Unterhaltung gesendet!',
- ['2'] = '<b>Befehl Statistiken für:</b> %s\n\n%s\n<b>Summe der gesendeten Befehle:</b> %s',
- ['3'] = 'Die Befehl Statistiken für diese Unterhaltung wurden gelöscht!',
- ['4'] = 'Ich konnte die Befehl Statistiken für diese Unterhaltung nicht löschen. Wurden sie vielleicht schon gelöscht?'
- },
- ['control'] = {
- ['1'] = 'Pfft, wie du willst!',
- ['2'] = '%s ist am Neuladen...'
- },
- ['copypasta'] = {
- ['1'] = 'Der Antowrten-zu text kann nicht länger sein als %s Zeichen!'
- },
- ['coronavirus'] = {
- ['1'] = [[*COVID-19 Statistics for:* %s
-
-*New confirmed cases:* %s
-*Total confirmed cases:* %s
-*New deaths:* %s
-*Total deaths:* %s
-*New recovered cases:* %s
-*Total recovered cases:* %s]]
- },
- ['custom'] = {
- ['1'] = 'Erfolg! Die Nachricht wird nun jedesmal gesendet wen jemand %s benutzt!',
- ['2'] = 'Der Auslöser "%s" existiert nicht!',
- ['3'] = 'Der Auslöser "%s" ist gelöscht!',
- ['4'] = 'Du hast keine eigene Auslöser angegeben!',
- ['5'] = 'Eigene Befehle für %s:\n',
- ['6'] = 'Zum machen von eigenen Befehlen, benutze diesen Syntax:\n/custom new #Auslöser <Wert>. Zum listen aller bestehenden Auslöser, benutze /custom list. Zum löschen eines Auslösers, benutze /custom del #Auslöser.'
- },
- ['delete'] = {
- ['1'] = 'Ich konnte die Nachricht nicht löschen. Ist die Nachricht vielleicht zu alt oder existiert nicht?'
- },
- ['demote'] = {
- ['1'] = 'Welchen Benutzer soll ich degradieren? Du kannst den Benutzer mit dem Benutzernamen oder mit der Identifikationsnummer angeben.',
- ['2'] = 'Ich kann den Benutzer nicht degradieren, weil er/sie ein Moderator oder Administrator in dieser Gruppe ist.',
- ['3'] = 'Ich kann den Benutzer nicht degradieren, weil er/sie die Gruppe schon verlassen hat.',
- ['4'] = 'Ich kann den Benutzer nicht degradieren, weil er/sie von der Gruppe entfernt wurde.'
- },
- ['dice'] = {
- ['1'] = 'Die mindest Spannweite ist %s.',
- ['2'] = 'Die maximal Spannweite und Zählung ist beides %s.',
- ['3'] = 'Die maximal Spannweite ist %s, die maximal Zählung ist %s.',
- ['4'] = '%s rollt mit einer Spannweite von %s:\n'
- },
- ['doge'] = {
- ['1'] = 'Bitte gebe den text ein welchen du in Doge-ify sehen willst. Jeder Satz sollte getrennt sein mit Schrägstrich oder neue Zeile..'
- },
- ['donate'] = {
- ['1'] = '<b>Hello, %s!</b>\n\nIf you\'re feeling generous, you can contribute to the mattata project by making a monetary donation of any amount. This will go towards server costs and any time and resources used to develop mattata. This is an optional act, however it is greatly appreciated and your name will also be listed publically on mattata\'s GitHub page.\n\nIf you\'re still interested, you can donate <a href="https://paypal.me/wrxck">here</a>. Thank you for your continued support!'
- },
- ['duckduckgo'] = {
- ['1'] = 'Ich bin nicht sicher was das ist!'
- },
- ['eightball'] = {
- ['1'] = 'Ja.',
- ['2'] = 'Nein.',
- ['3'] = 'Es ist warscheinlich so.',
- ['4'] = 'Also... Wenn ich du wäre würde ich später noch mal fragen.'
- },
- ['exec'] = {
- ['1'] = 'Bitte wähle die Sprache in der dein Code ausgeführt werden soll:',
- ['2'] = 'Ein Fehler ist aufgetreten! Die Verbindung ist unterbrochen. Hast du versucht mich langsamer zu machen?',
- ['3'] = 'Du hast ausgewählt: "%s" – bist du sicher?',
- ['4'] = 'Zurück',
- ['5'] = 'Ich bin sicher',
- ['6'] = 'Bitte gebe den Schnipsel Code ein, welchen du durchführen willst. Du must keine Sprache wählen, wir machen das später!',
- ['7'] = 'Bitte wähle die Sprache in der dein Code ausgeführt werden soll:'
- },
- ['facebook'] = {
- ['1'] = 'Ein Fehler ist aufgetreten!',
- ['2'] = 'Bitte gebe den Namen von dem Facebook Benutzer ein, von welchem du ein Profilbild bekommen willst.',
- ['3'] = 'Schaue @%s in Facebook an'
- },
- ['fact'] = {
- ['1'] = 'Generiere nochmal'
- },
- ['fban'] = {
- ['1'] = 'Which user would you like me to Fed-ban? You can specify this user by their @username or numerical ID.',
- ['2'] = 'I cannot Fed-ban this user because they are a moderator or an administrator in this chat.'
- },
- ['flickr'] = {
- ['1'] = 'Du hast gesucht für:',
- ['2'] = 'Bitte gebe einen Suchbegriff ein (das ist, was ich in flickr für dich suchen soll, d.h. "Big Ben" will ein Bild vom Big Ben in London senden).',
- ['3'] = 'Mehr Ergebnisse.'
- },
- ['game'] = {
- ['1'] = 'Total gewonnen: %s\nTotal verloren: %s\nGuthaben: %s mattacoins',
- ['2'] = 'Dem Spiel beitreten',
- ['3'] = 'Dieses Spiel hat schon geendet!',
- ['4'] = 'Du bist nicht an der reihe!',
- ['5'] = 'Du bist kein Mitspieler von diesem Spiel!',
- ['6'] = 'Du kannst da nicht hingehen!',
- ['7'] = 'Du bist schon ein Mitspieler von diesem Spiel!',
- ['8'] = 'Dieses Spiel hat schon angefangen!',
- ['9'] = '%s [%s] spielt gegen %s [%s]\nEs ist %s an der reihe!',
- ['10'] = '%s hat das Spiel gewonnen gegen %s!',
- ['11'] = '%s hat das spiel gezogen gegen %s!',
- ['12'] = 'Warte für einen Gegenspieler...',
- ['13'] = 'Tic-Tac-Toe',
- ['14'] = 'Klick zum senden des Spiels in die Unterhaltung!',
- ['15'] = 'Statistik für %s:\n',
- ['16'] = 'Spiel Tic-Tac-Toe!'
- },
- ['gblocklist'] = {
- ['1'] = 'Bitte Antworte-zu dem Benutzer, welchen du global auf der schwarzen Liste haben möchtest, oder gebe ihn/sie mit Benutzername/Identifikationsnummer an.',
- ['2'] = 'Ich kann keine Information über "%s" finden, bitte prüfe nach ob der Benutzername/Identifikationsnummer gültig ist und versuche es noch einmal.',
- ['3'] = 'Das ist ein/e %s, aber kein Benutzer!'
- },
- ['gif'] = {
- ['1'] = 'Bitte gebe einen Suchbegriff ein (das ist, was ich in GIPHY für dich suchen soll, d.h. "Katze" will ein GIF von einer Katze senden).'
- },
- ['gallowlist'] = {
- ['1'] = 'Bitte Antworte-zu dem Benutzer, welchen du global auf der weißen Liste haben möchtest, oder gebe ihn/sie mit Benutzername/Identifikationsnummer an.',
- ['2'] = 'Ich kann keine Information über "%s" finden, bitte prüfe nach ob der Benutzername/Identifikationsnummer gültig ist und versuche es noch einmal.',
- ['3'] = 'Das ist ein/e %s, aber kein Benutzer!'
- },
- ['hackernews'] = {
- ['1'] = 'Top Stories von Hacker News:'
- },
- ['help'] = {
- ['1'] = 'Kein Ergebnis gefunden!',
- ['2'] = 'Keine Eigenschaften gefunden, welche übereinstimmen mit "%s". Bitte versuche ein bischen spezifischer zu sein!',
- ['3'] = '\n\nArguments: <erforderlich> [optional]\n\nSuche für Eigenschaften oder bekomme Hilfe mit der Benutzung von einem Befehl meiner inline Search Funktionalität - erwähne mich in irgendeiner Unterhaltung mit dem Syntax @%s <Suchbegriff>.',
- ['4'] = 'Vorherige',
- ['5'] = 'Nächste',
- ['6'] = 'Zurück',
- ['7'] = 'Suche',
- ['8'] = 'Du bist auf Seite %s von %s!',
- ['9'] = [[
-Ich kann viele administrative Handlungen in deinen Gruppen machen. Du brauchst mich nur als Administrator hinzufügen und sende /administration zum anpassen der Einstellungen für deine Gruppe.
-Hier sind einige administrative Befehle und ein kurzer Kommentar bezüglich was sie tun:
-
-• /pin <text> - Sende einen formatierten Text, welcher auch bearbeitet werden kann mit dem selben Befehl und anderem Text, zum ersparen vom anheften eines textes den du nicht bearbeiten kannst to save you from having to re-pin a message if you can't edit it (was passieren kann, wenn der Text älter als 48 Stunden ist).
-
-• /ban - Sperre einen Benutzer mit einer Antwort zu deren Text, oder mit spezifizieren mit deren Benutzername/Identifikationsnummer.
-
-• /kick - Kick (sperren und dann sperre aufheben) einen Benutzer mit einer Antwort zu deren Text, oder mit spezifizieren mit deren Benutzername/Identifikationsnummer.
-
-• /unban - Die Sperre eines Benutzer aufheben mit einer Antwort zu deren Text, oder mit spezifizieren mit deren Benutzername/Identifikationsnummer.
-
-• /setrules <text> - Mache einen formatierten Text als Gruppenregel, welcher gesendet wird, wenn jemand /rules benutzt.
- ]],
- ['10'] = [[
-• /setwelcome - Mache einen formatierten Text als Wilkommens Text, welcher jedesmal gesendet wird, wenn ein neuer Benutzer der Gruppe beitritt (der Willkommens Text kann ausgeschalted werden im Administration Menü, erreichbar durch /administration). Du kannst Platzhalter benutzen für einen individuellen Willkommens Text für jeden Benutzer. Benutze $user_id zum einfügen des Benutzers Identifikationsnummer, $chat_id zum einfügen der Gruppen Identifikationsnummer, $name zum einfügen des Benutzers name, $title zum einfügen des Gruppennamen und $username zum einfügen des Benutzers Benutzername (wenn der Benutzer keinen @Benutzernamen hat, wird deren Name benutzt, also ist es das beste, dieses zu vermeiden mit der Benutzung von $name).
-
-• /warn - Warne einen Benutzer und sperre ihn/sie, wenn mehr als das Maximum der Warnungen ausgesprochen wurden.
-
-• /mod - Befördere den Antworten-zu Benutzer. Gib im zugriff zu administrative Befehle wie /ban, /kick, /warn usw. (das ist sinnvoll wenn du nicht möchtest, dass jemand Nachrichten löschen kann)
-
-• /demod - Degradiere den Antworten-zu Benutzer. Nehme deren Moderationstatus weg und die Möglichkeit zum benutzen administrativen Befehlen.
-
-• /staff - Sehe den Gruppenerschaffer, Administratoren und Moderatoren in einer schön formatierten Liste.
- ]],
- ['11'] = [[
-• /report - Sendet den Antworten-zu Text zu allen Administratoren und warnt sie vor der aktuellen Situation.
-
-• /setlink <URL> - Ändert den Gruppen Link zu der gegebenen URL, welcher gesendet wird wenn jemand /link benutzt.
-
-• /links <text> - Weiße Liste von allen gefundenen Telegram Links im angegebenen Text (einschließlich @Benutzername links)
- ]],
- ['12'] = 'Nachfolgend sind einige Links die du vielleicht nützlich findest:',
- ['13'] = 'Development',
- ['14'] = 'Channel',
- ['15'] = 'Support',
- ['16'] = 'FAQ',
- ['17'] = 'Source',
- ['18'] = 'Donate',
- ['19'] = 'Rate',
- ['20'] = 'Administration Log',
- ['21'] = 'Admin Settings',
- ['22'] = 'Plugins',
- ['23'] = [[
-<b>Hallo %s! Mein Name ist %s, schön dich zu treffen.</b> %s
-
-Ich verstehe viele Befehle, welche du lernen kannst wenn du den "Commands" Knopf drückst in der angehängten Tastatur.
-
-%s <b>Tip:</b> Benutze den "Settings" Knopf zum verändern wie ich arbeite%s!
-
-%s <b>Wenn du mich für sinnvoll hälst, oder vielleicht nur helfen willst?</b> Spenden sind willkommen, benutze /donate für mehr Information!
- ]],
- ['24'] = 'in'
- },
- ['id'] = {
- ['1'] = 'Ich kann den Benutzer nicht erkennen. Wenn du mich lehren möchtest wer dieser Benutzer ist, dann leite einfach eine Nachricht von diesem Benutzer in eine Gruppe in der ich auch bin .',
- ['2'] = 'Abgefragte Unterhaltung:',
- ['3'] = 'Diese Unterhaltung:',
- ['4'] = 'Klick zum senden des Ergebnis!'
- },
- ['imdb'] = {
- ['1'] = 'Vorherige',
- ['2'] = 'Nächste',
- ['3'] = 'Du bist auf Seite %s von %s!'
- },
- ['import'] = {
- ['1'] = 'Ich kann die Unterhaltung nicht erkennen!',
- ['2'] = 'Dies ist keine Supergruppe, des wegen kann ich keine Einstellungen von da importieren!',
- ['3'] = 'Administrative Einstellungen erfolgreich importiert und ich habe die Plugins umgeschaltet von %s zu %s!'
- },
- ['info'] = {
- ['1'] = [[
-```
-Redis:
-%s Konfigurationsdatei: %s
-%s Modus: %s
-%s TCP Port: %s
-%s Version: %s
-%s Betriebszeit: %s Tage
-%s Verarbeitete Identifikationsnummern: %s
-%s Abgelaufene Schlüssel: %s
-
-%s Benutzeranzahl: %s
-%s Gruppenanzahl: %s
-
-System:
-%s OS: %s
-```
- ]]
- },
- ['instagram'] = {
- ['1'] = '@%s in Instagram'
- },
- ['ipsw'] = {
- ['1'] = '<b>%s</b> iOS %s\n\n<code>MD5 sum: %s\nSHA1 sum: %s\nFile size: %s GB</code>\n\n<i>%s %s</i>',
- ['2'] = 'Diese Firmware ist nicht mehr signiert!',
- ['3'] = 'Diese Firmware ist noch signiert!',
- ['4'] = 'Bitte wähle dein Model:',
- ['5'] = 'Bitte wähle deine Firmware Version:',
- ['6'] = 'Bitte wähle deinen Geräte Typ:',
- ['7'] = 'iPod Touch',
- ['8'] = 'iPhone',
- ['9'] = 'iPad',
- ['10'] = 'Apple TV'
- },
- ['ispwned'] = {
- ['1'] = 'Dieses Konto wurde in folgenden undichten Stellen gefunden:'
- },
- ['itunes'] = {
- ['1'] = 'Name:',
- ['2'] = 'Artist:',
- ['3'] = 'Album:',
- ['4'] = 'Track:',
- ['5'] = 'Disc:',
- ['6'] = 'Die orginale Frage kann nicht gefunden werden. Du hast wahrscheinlich den orginalen Text gelöscht.',
- ['7'] = 'Das Kunstwerk kann weiter unten gefunden werden:',
- ['8'] = 'Bitte gebe einen Suchbegriff ein (das ist, was ich in iTunes für dich suchen soll, d.h. "Green Day American Idiot" gibt dir das erste Ergebnis von American Idiot von Green Day).',
- ['9'] = 'Bekomme Album Kunstwerke'
- },
- ['kick'] = {
- ['1'] = 'Welchen Benutzer soll ich raus werfen? Du kannst ihn/sie mit dem @Benutzernamen oder mit der Identifikationsnummer angeben.',
- ['2'] = 'Ich kann den Benutzer nicht raus werfen, weil er/sie Moderator oder Administrator in dieser Gruppe ist.',
- ['3'] = 'Ich kann den Benutzer nicht raus werfen, weil er/sie hat die Gruppe schon verlassen hat.',
- ['4'] = 'Ich kann den Benutzer nicht raus werfen, weil er/sie schon von der Gruppe entfernt wurde.',
- ['5'] = 'Ich brauche administrative Berechtigung zum raus werfen des Benutzers. Bitte behebe das Problem und versuche es noch einmal.'
- },
- ['lastfm'] = {
- ['1'] = '%s\'s last.fm Benutzername wurde zu "%s" gesendet.',
- ['2'] = 'Dein last.fm Benutzername wurde vergessen!',
- ['3'] = 'Im Moment hast du keinen last.fm Benutzernamen!',
- ['4'] = 'Bitte gebe deinen letzten last.fm Benutzernamen an oder richte ihn mit /fmset ein.',
- ['5'] = 'Keine Vergangenheit für diesen Benutzer gefunden.',
- ['6'] = '%s hört im Moment:\n',
- ['7'] = '%s hörte zuletzt:\n',
- ['8'] = 'Unbekannt',
- ['9'] = 'Klick zum senden des Ergebnis.'
- },
- ['location'] = {
- ['1'] = 'Du hast keinen Standort angegeben. Welchen Standort möchtest du haben?'
- },
- ['logchat'] = {
- ['1'] = 'Bitte gebe den Benutzernamen oder die Identifikationsnummer der Unterhaltung an, in welche du alle administrativen Handlungen senden möchtest.',
- ['2'] = 'Überprüfe ob die Unterhaltungen gültig ist...',
- ['3'] = 'Tut mir leid aber es sieht so aus, also ob du eine ungültige Unterhaltung, oder eine Unterhaltung in der ich nicht drin bin, angegeben hast. Bitte behebe das Problem und versuche es noch einmal.',
- ['4'] = 'Du kannst keinen Benutzer als logchat angeben!',
- ['5'] = 'Es sieht so aus, also ob du kein Administrator der Unterhaltung bistt!',
- ['6'] = 'Es sieht so aus, als ob ich schon administrative Handlungsrechte in dieser Gruppe besitze. Wenn du mir administrative Handlungsrechte in einer anderen Gruppe geben willst benutze /logchat.',
- ['7'] = 'Diese Unterhaltung ist gültig. Ich werde nun einen Testtext zu der Unterhaltung schicken, um zu sehen ob ich die Genehmigung zum schreiben habe!',
- ['8'] = 'Hallo, Welt - dies ist ein Testext zum herausfinden ob ich die Gehnemigung zum schreiben habe - wenn du das liest, dann ist alles OK!',
- ['9'] = 'Alles fertig! Von nun an alle administrativen Handlungen werden auch zu %s gesendet - zum ändern der Unterhaltung, in die du administrative Handlungen senden möchtest, sende /logchat.'
- },
- ['lua'] = {
- ['1'] = 'bitte gebe eine Reihe von Lua ein zum ausführen!'
- },
- ['lyrics'] = {
- ['1'] = 'Spotify',
- ['2'] = 'Zeige Liedtext',
- ['3'] = 'Bitte gebe einen Suchbegriff ein (das ist, zu welchem Lied/Sänger/Gruppe ich den Liedtext suchen soll, d.h. "Green Day Basket Case" gibt dir den Liedtext zu dem Lied song Basket Case von Green Day).'
- },
- ['minecraft'] = {
- ['1'] = '<b>%s hat den Benutzernamen %s mal gewechselt</b>',
- ['2'] = '<b>%s hat den Benutzernamen %s mal gewechselt</b>',
- ['3'] = 'Vorherige',
- ['4'] = 'Nächste',
- ['5'] = 'Zurück',
- ['6'] = 'UUID',
- ['7'] = 'BenutzerBild',
- ['8'] = 'Benutzername Vergangenheit',
- ['9'] = 'Bitte wähle eine Option:',
- ['10'] = 'Bitte gebe den Benutzernamen des Minecraft Spielers an, für welchen du Informationen sehen möchtest (d.h. wen du "Notch" sendest kannst du die Informationen von dem Spieler Notch einsehen).',
- ['11'] = 'Minecraft Benutzernamen sind zwischen 3 und 16 Zeichen lang.'
- },
- ['mute'] = {
- ['1'] = 'Welchen Benutzer soll ich stumm schalten? Du kannst den Benutzer mit dem @Benutzername oder mit der Indetifikationsnummer angeben.',
- ['2'] = 'Ich kann den Benutzer nich stumm schalten, weil der Benutzer in dieser Unterhaltung schon stumm geschaltet ist.',
- ['3'] = 'Ich kann den Benutzer nich stumm schalten, weil der Benutzer in dieser Unterhaltung Moderator oder Administrator ist.',
- ['4'] = 'Ich kann den Benutzer nich stumm schalten, weil der Benutzer diese Unterhaltung schon verlassen hat oder rausgeworfen wurde.',
- ['5'] = 'Zum stumm schalten des Benutzers muss ich Administrationsrechte haben. Bitte ändere meine Rechte und versuche es noch einmal.'
- },
- ['myspotify'] = {
- ['1'] = 'Profil',
- ['2'] = 'Folgende',
- ['3'] = 'Vor kurzem gespielt',
- ['4'] = 'Derzeit spielen',
- ['5'] = 'Top Lieder',
- ['6'] = 'Top Künstler',
- ['7'] = 'Es sieht nicht so aus, als würdest du einem Künstler folgen!',
- ['8'] = 'Dein Top Künstler',
- ['9'] = 'Es sieht so aus, als würdest du keine Lieder in deiner Sammlung haben!',
- ['10'] = 'Deine Top Lieder',
- ['11'] = 'Es sieht nicht so aus, als würdest du einem Künstler folgen!',
- ['12'] = 'Künstler denen du folgst',
- ['13'] = 'Es sieht nicht so aus als hättest du vor kurzem irgendwelche lieder gespielt!',
- ['14'] = '<b>Vor kurzem gespielt</b>\n%s %s\n%s %s\n%s Gehört um %s:%s am %s/%s/%s.',
- ['15'] = 'Deine Anfrage wurde akzeptiert aber die Bearbeitung wurde noch nicht beendet.',
- ['16'] = 'Es sieht nicht so aus als würdest du dir im moment etwas anhören!',
- ['17'] = 'Derzeit spielen',
- ['18'] = 'Beim erneuten Autorisieren deines Spotify Accounts ist ein Fehler aufgetreten!',
- ['19'] = 'Dein Spotify Account wurde erneut erfolgreich Autorisiert! Deine orginal Anfrage wird bearbeitet...',
- ['20'] = 'Erneutes Autorisieren deines Spotify Accounts, bitte warten...',
- ['21'] = 'Zum verbinden deines Spotify Accounts musst du mattata autorisieren. Klick [hier](https://accounts.spotify.com/en/authorize?client_id=%s&response_type=code&redirect_uri=%s&scope=user-library-read,playlist-read-private,playlist-read-collaborative,user-read-private,user-read-email,user-follow-read,user-top-read,user-read-playback-state,user-read-recently-played,user-read-currently-playing,user-modify-playback-state) and press the green "OKAY" button to link mattata to your Spotify account. After you\'ve done that, send the link you were redirected to (it should begin with "%s", followed by a unique code) in reply to this message.',
- ['22'] = 'Wiedergabeliste',
- ['23'] = 'Benutze Inline Mode',
- ['24'] = 'Lyrics',
- ['25'] = 'Keine Geräte gefunden.',
- ['26'] = 'Es sieht so aus, als wenn du keine Wiedergabeliste hast.',
- ['27'] = 'Deine Wiedergabeliste',
- ['28'] = '%s %s [%s Lieder]',
- ['29'] = '%s %s [%s]\nSpotify %s Benutzer\n\n<b>Gerät:</b>\n%s',
- ['30'] = 'Spiele vorheriges Lied...',
- ['31'] = 'Du bist kein Premium Benutzer!',
- ['32'] = 'Ich kann keine Geräte finden.',
- ['33'] = 'Spiele nächstes Lied...',
- ['34'] = 'Lied wird fortgesetzt...',
- ['35'] = 'Dein Gerät ist im moment nicht erreichbar...',
- ['36'] = 'Keine Geräte gefunden!',
- ['37'] = 'Pause Lied...',
- ['38'] = 'Jetzt spielen',
- ['39'] = 'Mixe deine Musik...',
- ['40'] = 'Das ist keine gültig Lautstärke. Gebe bitte eine Nummer zwischen 0 und 100 an.',
- ['41'] = 'Die Lautstärke wurde auf %s%% eingestellt!',
- ['42'] = 'Dies Nachricht benutzt ein altes Plugin, zum anfragen eines neues bitte sende /myspotify!'
- },
- ['name'] = {
- ['1'] = 'Der Name auf den ich im moment antworte ist "%s" - zum ändern, benutze /name <text> ( <text> ist der Name auf den du willst, dass ich andworte).',
- ['2'] = 'Mein neuer Name muss zwischen 2 und 32 Buchstaben lang sein!',
- ['3'] = 'Mein Name kann nur aus Buchstaben bestehen!',
- ['4'] = 'Ich antworten nun auf "%s", und nicht mehr auf "%s" - zum ändern, benutze /name <text> ( <text> ist der Name auf den du willst, dass ich andworte).'
- },
- ['netflix'] = {
- ['1'] = 'Mehr lesen.'
- },
- ['news'] = {
- ['1'] = '"<code>%s</code>" ist kein gültiges Lua Muster.',
- ['2'] = 'Ich konnte keine Quellenliste bekommen.',
- ['3'] = '<b>Nachrichtenquelle gefunden zu</b> "<code>%s</code>":\n\n%s',
- ['4'] = '<b>Hier sind die aktuellen verfügbaren Nachrichtenquellen, welche du mit</b> /news<b> benutzen kannst. Benutze</b> /nsources &lt;query&gt; <b>zum durchsuchen der Liste von Nachrichtenquellen für ein besseres Ergebnis. Die suche wird abgestimmt mit den Lua Mustern</b>\n\n%s',
- ['5'] = 'Du hast keine bevorzugte Nachrichtenquelle. Benutze /setnews <Quelle>. Zum ansehen einer Quellenliste benutze /nsources, oder beschränke das Ergebnis mit /nsources <Abfrage>.',
- ['6'] = 'Deine derzeit bevorzugte Nachrichtenquelle ist %s. Zum ändern benutze /setnews <Quelle>.Zum ansehen einer Quellenliste benutze /nsources, oder beschränke das Ergebnis mit /nsources <Abfrage>.',
- ['7'] = 'Deine derzeit bevorzugte Nachrichtenquelle ist %s! Zum ansehen der derzeiting Top Story benutze /news.',
- ['8'] = 'Dies ist keine gültige Nachrichtenquelle. Zum ansehen einer Quellenliste benutze /nsources, oder beschränke das Ergebnis mit /nsources <Abfrage>.',
- ['9'] = 'Deine bevorzugte Nachrichtenquelle wurde zu %s aktualisiert! Zum ansehen der derzeiting Top Story benutze /news.',
- ['10'] = 'Dies ist keine gültige Nachrichtenquelle. Zum ansehen einer Quellenliste benutze /nsources. Wenn du eine bevorzugte Nachrichtenquelle hast benutze /setnews <Quelle> und do bekommst automatisch von dieser Quelle Nachrichten geschickt wenn du /news sendest.',
- ['11'] = 'Mehr lesen.'
- },
- ['nick'] = {
- ['1'] = 'Dein Spitzname is vergessen!',
- ['2'] = 'Dein Spitzname wurde geändert zu "%s"!'
- },
- ['optout'] = {
- ['1'] = 'Du bist opted-in(beigetreten), dass die Daten, welche du sendest, gesammelt werden! Benutze /optout zum opt-out(austreten).',
- ['2'] = 'Du bist opted-out(ausgetreten), dass die Daten, welche du sendest, gesammelt werden! Benutze /optin zum opt-in(beitreten).'
- },
- ['paste'] = {
- ['1'] = 'Bitte suche einen Service aus zum hochladen und einfügen deines Textes:'
- },
- ['pay'] = {
- ['1'] = 'Du hast im Moment %s mattacoins. Verdiene mehr wenn du das Spiel Tic-Tac-Toe gewinnst. Benutze /game - Du gewinnst 100 mattacoins für jedes gewonnene Spiel und du verlierst 50 für jedes verlorene Spiel.',
- ['2'] = 'Du musst diesen Befehl benutzen als Antwort zu dem Benutzer dem du mattacoins senden willst.',
- ['3'] = 'Bitte gebe die Menge der mattacoins an, welche du zu %s senden möchtest.',
- ['4'] = 'Die Menge sollte in einer Zahl angegeben sein, welche nicht kleiner als 0 sein kann.',
- ['5'] = 'Du kannst kein Geld zu dir selbst schicken!',
- ['6'] = 'Du hast nicht genug Guthaben zum durchführen der Transaktion!',
- ['7'] = '%s mattacoins wurden gesendet zu %s. Dein neues Guthaben ist %s mattacoins.'
- },
- ['pin'] = {
- ['1'] = 'Du hast noch keinen pin gesetzt. Benutze /pin <dein Text> um deinen Text zu pinnen. Markdown formatierung ist verfügbar.',
- ['2'] = 'Hier ist die letzte nachricht die mit /pin generiert wurde',
- ['3'] = 'Ich habe einen bereits existierenden pin in meiner Datenbank gefunden, aber die nachricht, die ich bereits gesendet habe, aber sie wurde gelöscht, und ich finde sie nicht mehr. Benutze /pin <dein Text> um deinen Text zu pinnen. Markdown formatierung ist verfügbar.',
- ['4'] = 'Es ist ein fehler bei der aktualisierung deines pins aufgetreten. Vielleicht hat dein Text eine ungültige Markdown formatierung, oder sie wurde gelöscht. Ich versuche dir einen neuen pin zu senden, welchen du unten findest - falls du es ändern möchtest, wenn die nachricht noch existiert, benutze /pin <dein text>.',
- ['5'] = 'Ich kann den text nicht senden weil er eine ungültige Markdown formatierung hat.',
- ['6'] = 'Klick hier um den pin zu sehen, aktualisiert mit dem Text den du mir gegeben hast.'
- },
- ['pokedex'] = {
- ['1'] = 'Name: %s\nID: %s\nArt: %s\nBeschreibung: %s'
- },
- ['prime'] = {
- ['1'] = 'Bitte gebe eine Zahl zwischen 1 und 99999 ein.',
- ['2'] = '%s ist eine Primzahl!',
- ['3'] = '%s ist KEINE Primzahl...'
- },
- ['promote'] = {
- ['1'] = 'Ich kann diesen Benutzer nicht beförderen, weil er/sie Moderator oder Administrator in dieser Gruppe ist.',
- ['2'] = 'Ich kann diesen Benutzer nicht beförderen, weil er/sie hat die Gruppe schon verlassen hat.',
- ['3'] = 'Ich kann diesen Benutzer nicht beförderen, weil er/sie schon von der Gruppe entfernt wurde.'
- },
- ['quote'] = {
- ['1'] = 'Dieser Benutzer ist opted out(ausgetreten) von der Datensammlung funktionalität.',
- ['2'] = 'Da sind keine Zitate von %s%s! Du kannst Zitate speichern wenn du /save als Antwort zu dem gesendeten text(welchen du als Zitat speichern willst).'
- },
- ['randomsite'] = {
- ['1'] = 'Generiere nochmal'
- },
- ['randomword'] = {
- ['1'] = 'Generiere nochmal',
- ['2'] = 'Dein zufälliges Wort ist <b>%s</b>!'
- },
- ['report'] = {
- ['1'] = 'Bitte Antworte zu der Nachricht die du einem GruppenAdminsitrator melden möchtest.',
- ['2'] = 'Du kannst deine eigenen Nachrichten nicht melden, machst du vielleicht Witze?',
- ['3'] = '<b>%s braucht Hilfe in %s!</b>',
- ['4'] = 'Klicke hier zum ansehen der gemeldeten Nachricht.',
- ['5'] = 'Ich habe die Nachricht erfolgreich gemeldet zu %s admin(s)!'
- },
- ['rms'] = {
- ['1'] = 'Heiliges GNU!'
- },
- ['save'] = {
- ['1'] = 'Dieser Benutzer ist opted out(ausgetreten) von der Datensammlung funktionalität.',
- ['2'] = 'Dieser Text ist gespeichert in meiner Datei und wird zu der List möglicher Antworten hinzugefügt, wenn /quote benutzt wird als Antwort zu %s%s!'
- },
- ['sed'] = {
- ['1'] = '%s\n\n<i>%s wollte das nicht sagen!</i>',
- ['2'] = '%s\n\n<i>%s hat zugegeben verloren zu haben.</i>',
- ['3'] = '%s\n\n<i>%s ist sich nicht sicher obe er/sie missverstanden ist...</i>',
- ['4'] = 'Ach halt die Klappe, <i>wann habe ich jemals nicht recht?</i>',
- ['5'] = '"<code>%s</code>" ist kein gültiges Lua Muster.',
- ['6'] = 'Hey %s, %s seems to think you meant:\n<i>%s</i>',
- ['7'] = 'Ja',
- ['8'] = 'Nein',
- ['9'] = 'Bin nicht sicher',
- ['10'] = 'Just edit your message, idiot.'
- },
- ['setgrouplang'] = {
- ['1'] = 'Die Sprache in dieser Gruppe wurde eingstellet zu %s!',
- ['2'] = 'Die Sprache in dieser Gruppe ist im moment %s.\nBitte nehme zur Kenntnis, dass vielleicht noch nicht alles vollständig Übersetzt ist. Wenn du die Sprache ändern möchtest, wähle unten auf der Tastatur eine aus:',
- ['3'] = 'Die Möglichkeit, dass alle Benutzer in dieser Gruppe die selbe Sprache benutzent müssen, ist im moment ausgeschaltet. Diese Einstellung sollte von /administration eingestellet werden, damit es einfacher ist für dich, habe ich unten Knöpfe zum einstellen hinzugefügt.',
- ['4'] = 'Einschalten',
- ['5'] = 'Ausschalten'
- },
- ['setlang'] = {
- ['1'] = 'Deine Sprache wurde eingestellt zu %s!',
- ['2'] = 'Deine Sprache ist im Moment eingestellt zu %s.\nBitte beachte, dass manche Wörter oder Sätze noch nicht übersetzet sind. Wenn du deine Sprache ändern möchtest, suche dir eine aus in der Tastatur unten:'
- },
- ['setlink'] = {
- ['1'] = 'Das ist keine gültige URL.',
- ['2'] = 'Link erfolgreich gesetzt!'
- },
- ['setrules'] = {
- ['1'] = 'Ungültige Markdown-Formatierung.',
- ['2'] = 'Neue Regeln erfolgreich eingestellt!'
- },
- ['setwelcome'] = {
- ['1'] = 'Was möchtest als Willkommens Text haben? Den angegebenen Text wird formatiert und jedesmal gesendet, wenn ein Benutzer der Gruppe beitritt (Der Willkommens Text kann ausgeschaltet werden im Administrations Menue, erreichbar mit /administration). Du kannst Platzhalter benutzen für einen individuellen Willkommens Text für jeden Benutzer. Benutze $user_id zum einfügen des Benutzers Identifikationsnummer, $chat_id zum einfügen der Gruppen Identifikationsnummer, $name zum einfügen des Benutzers name, $title zum einfügen des Gruppennamen und $username zum einfügen des Benutzers Benutzername (wenn der Benutzer keinen @Benutzernamen hat, wird deren Name benutzt, also ist es das beste, dieses zu vermeiden mit der Benutzung von $name).',
- ['2'] = 'Da ist ein Fehler mit dem Format deines Textes aufgetreten. Bitte Überprüfe die Syntax und versuche es noch einmal.',
- ['3'] = 'Der Willkommens Text für %s wurde erfolgreich aktualisiert!'
- },
- ['share'] = {
- ['1'] = 'Teilen'
- },
- ['shorten'] = {
- ['1'] = 'Bitte wähle einen URL Verkürzer aus mit den Buttons unten:'
- },
- ['shsh'] = {
- ['1'] = 'Für den ECID konnte ich keine SHSH blobs holen. Bitte mache sicher, dass sie gültig sind und das to sie gespeichert hast auf https://tsssaver.1conan.com.',
- ['2'] = 'SHSH blobs sind verfügbar für das Gerät mit der folgenden Version von iOS:\n',
- ['3'] = 'Download .zip'
- },
- ['statistics'] = {
- ['1'] = 'Es wurden keine Nachrichten in dieser Unterhaltung gesendet!',
- ['2'] = '<b>Statistiken für:</b> %s\n\n%s\n<b>Summe der gesendeten Nachrichten:</b> %s',
- ['3'] = 'Die Statistiken für diese Unterhaltung wurde gelöscht!',
- ['4'] = 'Ich konnte die Statistiken für dies Unterhaltung nicht löschen. Vielleicht wurde sie schon gelöscht?'
- },
- ['steam'] = {
- ['1'] = 'Dein Steam Benutzername wurde gespeichert mit "%s".',
- ['2'] = '"%s" ist kein gültiger Steam Benutzername.',
- ['3'] = '%s ist ein Steam Benutzer seit %s, in %s. Er/Sie hat sich das letzte mal ausgelogt am %s, in %s. Klick <a href="%s">here</a> zum ansehen von deren Steam Profil.',
- ['4'] = '%s, alias "%s",'
- },
- ['synonym'] = {
- ['1'] = 'Du könntest das Wort <b>%s</b> benutzen, wäre besser als %s.'
- },
- ['thoughts'] = {
- ['1'] = '%s\n\nPositive: <code>%s%% [%s]</code>\nNegative: <code>%s%% [%s]</code>\nGleichgültige: <code>%s%% [%s]</code>\nSumme Gedanken: <code>%s</code>'
- },
- ['tobinary'] = {
- ['1'] = 'Bitte gebe ein Wort oder Satz ein, welchen du umwandeln willst zu Binary.'
- },
- ['trust'] = {
- ['1'] = 'Ich kann den Benutzer nicht zu trust(vertrauen) einstellen, weil er Moderator oder Administrator in dieser Gruppe ist.',
- ['2'] = 'Ich kann den Benutzer nicht zu trust(vertrauen) einstellen, weil er die Gruppe schon verlassen hat.',
- ['3'] = 'Ich kann den Benutzer nicht zu trust(vertrauen) einstellen, weil er von dieser Gruppe entfernt wurde.'
- },
- ['unmute'] = {
- ['1'] = 'Welchen Benutzer soll ich zu Stören einstellen? Gebe den Benutzer mit dem @Benutzername oder der Identifikationsnummer an.',
- ['2'] = 'Ich kann den Benutzer nicht zu Stören einstellen, weil er im moment nicht stumm geschalted ist..',
- ['3'] = 'Ich kann den Benutzer nicht zu Stören einstellen, weil er Moderator oder Administrator dieser Gruppe ist.',
- ['4'] = 'Ich kann den Benutzer nicht zu Stören einstellen, weil er die Gruppe schon verlassen hat oder von der Gruppe entfernt wurde.'
- },
- ['untrust'] = {
- ['1'] = 'Welchen Benutzer soll ich zu untrust(nicht vertrauen) einstellen? Gebe den Benutzer mit dem @Benutzername oder der Identifikationsnummer an.',
- ['2'] = 'Ich kann den Benutzer nicht zu untrust(nicht vertrauen) einstellen, weil er Moderator oder Administrator in dieser Gruppe ist.',
- ['3'] = 'Ich kann den Benutzer nicht zu untrust(nicht vertrauen) einstellen, weil er die Gruppe schon verlassen hat.',
- ['4'] = 'Ich kann den Benutzer nicht zu untrust(nicht vertrauen) einstellen, weil er von dieser Gruppe entfernt wurde.'
- },
- ['upload'] = {
- ['1'] = 'Bitte antworte zu der Datei, welche du hochlanden willst zum Server. Sie muss <= 20 MB sein.',
- ['2'] = 'Die Datei ist zu groß. Sie muss <= 20 MB sein.',
- ['3'] = 'Ich konnte die Datei nicht bekommen, wahrscheinlich ist sie zu alt.',
- ['4'] = 'Es ist ein Fehler aufgetreten beim abrufen der Datei.',
- ['5'] = 'Die Datei wurde erfolgreich hochgelanden zum Server - sie kan gefunden werden mit <code>%s</code>!'
- },
- ['version'] = {
- ['1'] = '@%s alias %s `[%s]` läuft mit mattata %s, kreiert von [Matthew Hesketh](https://t.me/wrxck). Der Quellcode ist auf [GitHub](https://github.com/wrxck/mattata) zu bekommen.'
- },
- ['voteban'] = {
- ['1'] = 'Für welchen Benutzer möchtest einen vote-ban(Wahl zur Sperre) eröffnen? Gebe den Benutzer mit dem @Benutzername oder der Identifikationsnummer an.',
- ['2'] = 'Ich kann keinen vote-ban(Wahl zur Sperre) für diesen Benutzer aufsetzen, weil er Moderator oder Administrator in dieser Gruppe ist.',
- ['3'] = 'Ich kann keinen vote-ban(Wahl zur Sperre) für diesen Benutzer aufsetzen, weil er die Gruppe schon verlassen hat oder von der Gruppe entfernt wurde.',
- ['4'] = 'Soll %s [%s] gesperrt werden von %s? %s dafür(Yes) werden gebraucht für eine sofortige Sperre und %s dagegen(No) werden gebraucht zum sofortigen schliessen der Wahl.',
- ['5'] = 'Ja [%s]',
- ['6'] = 'Nein [%s]',
- ['7'] = 'Die Leute haben gesprochen. Ich have %s [%s] von %s gesperrt, weil %s Leute dafür gewählt haben.',
- ['8'] = 'Der erfordliche Anzahl dafür wurde erreicht, aber es war mir nicht möglich %s zu sperren - vielleicht hat er/sie die Gruppe schon verlassen oder wurde befördert seit die Wahl eröffnet wurde? Es ist entweder das, oder ich habe keine Administrationsrechte mehr.',
- ['9'] = 'Die Leute haben gesprochen. Ich habe %s [%s] nicht von %s gesperrt, weil %s Leute dagegen gewählt haben.',
- ['10'] = 'Du hast dafür gewählt %s [%s] zu sperren!',
- ['11'] = 'Deine Wahl wurde zurückgezogen,zum eingeben einer neuen Wahl benutze die Knöpfe nocheinmal.',
- ['12'] = 'Du hast dagegen gewählt %s [%s] zu sperren!',
- ['13'] = 'Eine Wahl zum bannen des Benutzers wurde schon eröffnet!'
- },
- ['weather'] = {
- ['1'] = 'Du hast keinen Standort ausgewählt. Zum auswählen benutze /setloc <Standort>.',
- ['2'] = 'Im Moment ist es %s (fühlt sich an wie %s) in %s. %s'
- },
- ['welcome'] = {
- ['1'] = 'Group Rules'
- },
- ['allowlist'] = {
- ['1'] = 'Welchen Benutzer soll ich auf die Weiße Liste setzen? Gebe den Benutzer mit dem @Benutzername oder der Identifikationsnummer an.',
- ['2'] = 'Ich kann den Benutzer nicht auf die Weiße Liste setzen, weil er Moderator oder Administrator in dieser Gruppe ist.',
- ['3'] = 'Ich kann den Benutzer nicht auf die Weiße Liste setzen, weil er die Gruppe schon verlassen hat.',
- ['4'] = 'Ich kann den Benutzer nicht auf die Weiße Liste setzen, weil er von der Gruppe entfernt wurde.'
- },
- ['wikipedia'] = {
- ['1'] = 'Mehr lesen.'
- },
- ['youtube'] = {
- ['1'] = 'Vorherige',
- ['2'] = 'Nächste',
- ['3'] = 'Du bist auf Seite %s von %s!'
- }
-}
\ No newline at end of file
diff --git a/languages/en_gb.lua b/languages/en_gb.lua
deleted file mode 100644
index bf6f7cd..0000000
--- a/languages/en_gb.lua
+++ /dev/null
@@ -1 +0,0 @@
-return require('languages.en_us')
\ No newline at end of file
diff --git a/languages/en_us.lua b/languages/en_us.lua
deleted file mode 100644
index 85c5346..0000000
--- a/languages/en_us.lua
+++ /dev/null
@@ -1,814 +0,0 @@
--- This is a language file for mattata
--- Language: en-us
--- Author: wrxck
-
--- DO NOT CHANGE ANYTHING THAT BEGINS OR ENDS WITH A %
--- THESE ARE PLACEHOLDERS!
-
--- DO NOT CHANGE ANY MARKDOWN/HTML FORMATTING!
--- IF YOU ARE UNSURE, ASK ON TELEGRAM (t.me/mattataDev)
-
-return {
- ['errors'] = {
- ['connection'] = 'Connection error.',
- ['results'] = 'I couldn\'t find any results for that.',
- ['supergroup'] = 'This command can only be used in supergroups.',
- ['admin'] = 'You need to be a moderator or an administrator in this chat in order to use this command.',
- ['unknown'] = 'I don\'t recognize that user. If you would like to teach me who they are, forward a message from them to any chat that I\'m in.',
- ['generic'] = 'An error occured!',
- ['use'] = 'You are not allowed to use this!',
- ['private'] = 'You can only use this command in private chat!'
- },
- ['addcommand'] = {
- ['1'] = 'Please specify the command in the format <code>/command - description</code>',
- ['2'] = 'I couldn\'t retrieve my commands!',
- ['3'] = 'The command description can\'t be longer than 256 characters!',
- ['4'] = 'An unknown error occurred! I couldn\'t add your command!',
- ['5'] = 'Success! Command added.'
- },
- ['addrule'] = {
- ['1'] = 'Please specify the rule you would like to add!',
- ['2'] = 'You don\'t have any rules to add to! Please set group rules using /setrules!',
- ['3'] = 'I couldn\'t add that rule, as it would make the length of the rules longer than Telegram\'s 4096 character limit!',
- ['4'] = 'I couldn\'t add that rule, it appears it contains invalid Markdown formatting!',
- ['5'] = 'Successfully updated the rules!'
- },
- ['addslap'] = {
- ['1'] = 'You can only use this command in groups!',
- ['2'] = 'The slap cannot contain curly braces apart from placeholders!',
- ['3'] = 'The slap cannot be any longer than 256 characters in length!',
- ['4'] = 'I\'ve successfully added that slap as a possibility for /slap in this group!',
- ['5'] = 'You must include placeholders in your slap. Use {ME} for the person executing and {THEM} for the victim.'
- },
- ['administration'] = {
- ['1'] = 'Enable Administration',
- ['2'] = 'Disable Administration',
- ['3'] = 'Anti-Spam Settings',
- ['4'] = 'Warning Settings',
- ['5'] = 'Vote-Ban Settings',
- ['6'] = 'Welcome New Users?',
- ['7'] = 'Send Rules On Join?',
- ['8'] = 'Send Rules In Group?',
- ['9'] = 'Back',
- ['10'] = 'Next',
- ['11'] = 'Word Filter',
- ['12'] = 'Anti-Bot',
- ['13'] = 'Anti-Link',
- ['14'] = 'Log Actions?',
- ['15'] = 'Anti-RTL',
- ['16'] = 'Anti-Spam Action',
- ['17'] = 'Ban',
- ['18'] = 'Kick',
- ['19'] = 'Delete Commands?',
- ['20'] = 'Force Group Language?',
- ['21'] = 'Send Settings In Group?',
- ['22'] = 'Delete Reply On Action?',
- ['23'] = 'Require Captcha?',
- ['24'] = 'Use Inline Captcha?',
- ['25'] = 'Ban SpamWatch-flagged users?',
- ['26'] = 'Number of warnings until %s:',
- ['27'] = 'Upvotes needed to ban:',
- ['28'] = 'Downvotes needed to dismiss:',
- ['29'] = 'Deleted %s, and its matching link from the database!',
- ['30'] = 'There were no entries found in the database matching "%s"!',
- ['31'] = 'You\'re not an administrator in that chat!',
- ['32'] = 'The minimum number of upvotes required for a vote-ban is %s.',
- ['33'] = 'The maximum number of upvotes required for a vote-ban is %s.',
- ['34'] = 'The minimum number of downvotes required for a vote-ban is %s.',
- ['35'] = 'The maximum number of downvotes required for a vote-ban is %s.',
- ['36'] = 'The maximum number of warnings is %s.',
- ['37'] = 'The minimum number of warnings is %s.',
- ['38'] = 'You can add one or more words to the word filter by using /filter <word(s)>',
- ['39'] = 'You will no longer be reminded that the administration plugin is disabled. To enable it, use /administration.',
- ['40'] = 'That\'s not a valid chat!',
- ['41'] = 'You don\'t appear to be an administrator in that chat!',
- ['42'] = 'My administrative functionality can only be used in groups/channels! If you\'re looking for help with using my administrative functionality, check out the "Administration" section of /help! Alternatively, if you wish to manage the settings for a group you administrate, you can do so here by using the syntax /administration <chat>.',
- ['43'] = 'Use the keyboard below to adjust the administration settings for <b>%s</b>:',
- ['44'] = 'Please send me a [private message](https://t.me/%s), so that I can send you this information.',
- ['45'] = 'I have sent you the information you requested via private chat.',
- ['46'] = 'Remove Channel Pins?',
- ['47'] = 'Remove Other Pins?',
- ['48'] = 'Remove Pasted Code?',
- ['49'] = 'Prevent Inline Bots?',
- ['50'] = 'Kick Media On Join?',
- ['51'] = 'Enable Plugins For Admins?',
- ['52'] = 'Kick URLs On Join?'
- },
- ['afk'] = {
- ['1'] = 'Sorry, I\'m afraid this feature is only available to users with a public @username!',
- ['2'] = '%s has returned after being AFK for %s!',
- ['3'] = 'Note',
- ['4'] = '%s is now AFK.%s'
- },
- ['antispam'] = {
- ['1'] = 'Disable',
- ['2'] = 'Enable',
- ['3'] = 'Disable limit',
- ['4'] = 'Enable limits on %s',
- ['5'] = 'All Administration Settings',
- ['6'] = '%s [%s] has kicked %s [%s] from %s [%s] for hitting the configured anti-spam limit for [%s] media.',
- ['7'] = 'Kicked %s for hitting the configured antispam limit for [%s] media.',
- ['8'] = 'The maximum limit is 100.',
- ['9'] = 'The minimum limit is 1.',
- ['10'] = 'Modify the anti-spam settings for %s below:',
- ['11'] = 'Hey %s, if you\'re going to send code that is longer than %s characters in length, please do so using /paste in <a href="https://t.me/%s">private chat with me</a>!',
- ['12'] = '%s <code>[%s]</code> has %s %s <code>[%s]</code> from %s <code>[%s]</code> for sending Telegram invite link(s).\n#chat%s #user%s',
- ['13'] = '%s %s for sending Telegram invite link(s).',
- ['14'] = 'Hey, I noticed you\'ve got anti-link enabled and you\'re currently not allowing your users to mention a chat you\'ve just mentioned, if you\'d like to allowlist it, use /allowlink <links>.',
- ['15'] = 'Kicked %s <code>[%s]</code> from %s <code>[%s]</code> for sending media within their first few messages.\n#chat%s #user%s',
- ['16'] = 'Kicked %s <code>[%s]</code> from %s <code>[%s]</code> for sending a URL within their first few messages.\n#chat%s #user%s',
- ['17'] = 'Action',
- ['18'] = 'Kick',
- ['19'] = 'Ban',
- ['20'] = 'Mute'
- },
- ['appstore'] = {
- ['1'] = 'View on iTunes',
- ['2'] = 'rating',
- ['3'] = 'ratings'
- },
- ['authspotify'] = {
- ['1'] = 'You are already authorised using that account.',
- ['2'] = 'Authorising, please wait...',
- ['3'] = 'A connection error occured. Are you sure you replied with the correct link? It should look like',
- ['4'] = 'Successfully authorised your Spotify account!'
- },
- ['avatar'] = {
- ['1'] = 'I couldn\'t retrieve the profile photos for that user, please ensure you specified a valid username or numerical ID.',
- ['2'] = 'That user doesn\'t have any profile photos.',
- ['3'] = 'That user doesn\'t have that many profile photos!',
- ['4'] = 'That user has opted-out of data-collecting functionality, therefore I am not able to show you any of their profile photos.',
- ['5'] = 'User: %s\nPhoto: %s/%s\nSend /avatar %s [offset] to @%s to view a specific photo of this user',
- ['6'] = 'User: %s\nPhoto: %s/%s\nUse /avatar %s [offset] to view a specific photo of this user'
- },
- ['ban'] = {
- ['1'] = 'Which user would you like me to ban? You can specify this user by their @username or numerical ID.',
- ['2'] = 'I cannot ban this user because they are a moderator or an administrator in this chat.',
- ['3'] = 'I cannot ban this user because they have already left this chat.',
- ['4'] = 'I cannot ban this user because they have already been banned from this chat.',
- ['5'] = 'I need to have administrative permissions in order to ban this user. Please amend this issue, and try again.',
- ['6'] = '%s <code>[%s]</code> has banned %s <code>[%s]</code> from %s <code>[%s]</code>%s.\n%s %s',
- ['7'] = '%s has banned %s%s.'
- },
- ['bash'] = {
- ['1'] = 'Please specify a command to run!',
- ['2'] = 'Success!'
- },
- ['blocklist'] = {
- ['1'] = 'Which user would you like me to blocklist? You can specify this user by their @username or numerical ID.',
- ['2'] = 'I cannot blocklist this user because they are a moderator or an administrator in this chat.',
- ['3'] = 'I cannot blocklist this user because they have already left this chat.',
- ['4'] = 'I cannot blocklist this user because they have already been banned from this chat.',
- ['5'] = '%s <code>[%s]</code> has blocklisted %s <code>[%s]</code> from using %s <code>[%s]</code> in %s <code>[%s]</code>%s.\n%s %s',
- ['6'] = '%s has blocklisted %s from using %s%s.'
- },
- ['blocklistchat'] = {
- ['1'] = '%s has now been blocklisted, and I will leave whenever I am added there!',
- ['2'] = '%s is a user, this command is only for blocklisting chats such as groups and channels!',
- ['3'] = '%s doesn\'t appear to be a valid chat!'
- },
- ['bugreport'] = {
- ['1'] = 'Success! Your bug report has been sent. The ID of this report is #%s.',
- ['2'] = 'There was a problem whilst reporting that bug! Ha, the irony!'
- },
- ['calc'] = {
- ['1'] = 'Click to send the result.',
- ['2'] = '"%s" was an unexpected word!',
- ['3'] = 'You cannot have a unit before a number!'
- },
- ['captionbotai'] = {
- ['1'] = 'I really cannot describe that picture!'
- },
- ['cats'] = {
- ['1'] = 'Meow!'
- },
- ['channel'] = {
- ['1'] = 'You are not allowed to use this!',
- ['2'] = 'You don\'t appear to be an administrator in that chat anymore!',
- ['3'] = 'I couldn\'t send your message, are you sure I still have permission to send messages in that chat?',
- ['4'] = 'Your message has been sent!',
- ['5'] = 'I was unable to retrieve a list of administrators for that chat!',
- ['6'] = 'You don\'t appear to be an administrator in that chat!',
- ['7'] = 'Please specify the message to send, using the syntax /channel <channel> <message>.',
- ['8'] = 'Are you sure you want to send this message? This is how it will look:',
- ['9'] = 'Yes, I\'m sure!',
- ['10'] = 'That message contains invalid Markdown formatting! Please correct your syntax and try again.'
- },
- ['chatroulette'] = {
- ['1'] = 'Hey! Please don\'t send messages longer than %s characters. We don\'t want to annoy the other user!',
- ['2'] = '*Anonymous said:*\n```\n%s\n```\nTo end your session, send /endchat.',
- ['3'] = 'I\'m afraid I lost connection from the other user! To begin a new chat, please send /chatroulette!',
- ['4'] = 'The other person you were chatting with has ended the session. To start a new one, send /chatroulette.',
- ['5'] = 'Successfully ended your session. To start a new one, send /chatroulette.',
- ['6'] = 'I have successfully removed you from the list of available users.',
- ['7'] = 'You don\'t have a session set up at the moment. To start one, send /chatroulette.',
- ['8'] = 'Finding you a session, please wait...',
- ['9'] = 'I\'m afraid there aren\'t any available users right now, but I have added you to the list of available users! To stop this completely, please send /endchat.',
- ['10'] = 'I have successfully paired you with another user to chat to! Please remember to be kind to them! To end the chat, send /endchat.',
- ['11'] = 'I\'m afraid the user who I tried to pair you with has since blocked me. Please try and send /chatroulette again to try and connect to me!',
- ['12'] = 'I have successfully paired you with another user to chat to! Please remember to be kind to them! To end the chat, send /endchat.'
- },
- ['commandstats'] = {
- ['1'] = 'No commands have been sent in this chat!',
- ['2'] = '<b>Command statistics for:</b> %s\n\n%s\n<b>Total commands sent:</b> %s',
- ['3'] = 'The command statistics for this chat have been reset!',
- ['4'] = 'I could not reset the command statistics for this chat. Perhaps they have already been reset?'
- },
- ['control'] = {
- ['1'] = 'Pfft, you wish!',
- ['2'] = '%s is reloading...'
- },
- ['copypasta'] = {
- ['1'] = 'The replied-to text musn\'t be any longer than %s characters!'
- },
- ['coronavirus'] = {
- ['1'] = [[*COVID-19 Statistics for:* %s
-
-*New confirmed cases:* %s
-*Total confirmed cases:* %s
-*New deaths:* %s
-*Total deaths:* %s
-*New recovered cases:* %s
-*Total recovered cases:* %s]]
- },
- ['counter'] = {
- ['1'] = 'I couldn\'t add a counter to that message!'
- },
- ['custom'] = {
- ['1'] = 'Success! That message will now be sent every time somebody uses %s!',
- ['2'] = 'The trigger "%s" does not exist!',
- ['3'] = 'The trigger "%s" has been deleted!',
- ['4'] = 'You don\'t have any custom triggers set!',
- ['5'] = 'Custom commands for %s:\n',
- ['6'] = 'To create a new, custom command, use the following syntax:\n/custom new #trigger <value>. To list all current triggers, use /custom list. To delete a trigger, use /custom del #trigger.'
- },
- ['delete'] = {
- ['1'] = 'I could not delete that message. Perhaps the message is too old or non-existent?'
- },
- ['demote'] = {
- ['1'] = 'Which user would you like me to demote? You can specify this user by their @username or numerical ID.',
- ['2'] = 'I cannot demote this user because they are not a moderator or an administrator in this chat.',
- ['3'] = 'I cannot demote this user because they have already left this chat.',
- ['4'] = 'I cannot demote this user because they have already been kicked from this chat.'
- },
- ['dice'] = {
- ['1'] = 'The minimum range is %s.',
- ['2'] = 'The maximum range and count are both %s.',
- ['3'] = 'The maximum range is %s, and the maximum count is %s.',
- ['4'] = '%s rolls with a range of %s:\n'
- },
- ['doge'] = {
- ['1'] = 'Please enter the text you want to Doge-ify. Each sentence should be separated using slashes or new lines.'
- },
- ['donate'] = {
- ['1'] = '<b>Hello, %s!</b>\n\nIf you\'re feeling generous, you can contribute to the mattata project by making a monetary donation of any amount. This will go towards server costs and any time and resources used to develop mattata. This is an optional act, however it is greatly appreciated and your name will also be listed publically on mattata\'s GitHub page.\n\nIf you\'re still interested, you can donate <a href="https://paypal.me/wrxck">here</a>. Thank you for your continued support!'
- },
- ['duckduckgo'] = {
- ['1'] = 'I\'m not sure what that is!'
- },
- ['eightball'] = {
- ['1'] = 'Yes.',
- ['2'] = 'No.',
- ['3'] = 'It is likely so.',
- ['4'] = 'Well, uh... I\'d ask again later, if I were you.'
- },
- ['exec'] = {
- ['1'] = 'Please select the language you would like to execute your code in:',
- ['2'] = 'An error occured! The connection timed-out. Were you trying to make me lag?',
- ['3'] = 'You have selected "%s" – are you sure?',
- ['4'] = 'Back',
- ['5'] = 'I\'m sure',
- ['6'] = 'Please enter a snippet of code that you would like to run. You don\'t need to specify the language, we will do that afterwards!',
- ['7'] = 'Please select the language you would like to execute your code in:'
- },
- ['facebook'] = {
- ['1'] = 'An error occured!',
- ['2'] = 'Please enter the name of the Facebook user you would like to get the profile picture of.',
- ['3'] = 'View @%s on Facebook'
- },
- ['fact'] = {
- ['1'] = 'Generate Another'
- },
- ['fban'] = {
- ['1'] = 'Which user would you like me to Fed-ban? You can specify this user by their @username or numerical ID.',
- ['2'] = 'I cannot Fed-ban this user because they are a moderator or an administrator in this chat.'
- },
- ['flickr'] = {
- ['1'] = 'You searched for:',
- ['2'] = 'Please enter a search query (that is, what you want me to search Flickr for, i.e. "Big Ben" will return a photograph of Big Ben in London).',
- ['3'] = 'More Results'
- },
- ['fortune'] = {
- ['1'] = 'Click to send your fortune!'
- },
- ['frombinary'] = {
- ['1'] = 'Please enter the binary value you would like to convert to a string.',
- ['2'] = 'Malformed binary!'
- },
- ['game'] = {
- ['1'] = 'Total wins: %s\nTotal losses: %s\nBalance: %s mattacoins',
- ['2'] = 'Join Game',
- ['3'] = 'This game has already ended!',
- ['4'] = 'It\'s not your turn!',
- ['5'] = 'You are not part of this game!',
- ['6'] = 'You cannot go here!',
- ['7'] = 'You are already part of this game!',
- ['8'] = 'This game has already started!',
- ['9'] = '%s [%s] is playing against %s [%s]\nIt is currently %s\'s turn!',
- ['10'] = '%s won the game against %s!',
- ['11'] = '%s drew the game against %s!',
- ['12'] = 'Waiting for opponent...',
- ['13'] = 'Tic-Tac-Toe',
- ['14'] = 'Click to send the game to your chat!',
- ['15'] = 'Statistics for %s:\n',
- ['16'] = 'Play Tic-Tac-Toe!'
- },
- ['gblocklist'] = {
- ['1'] = 'Please reply-to the user you\'d like to globally blocklist, or specify them by username/ID.',
- ['2'] = 'I couldn\'t get information about "%s", please check it\'s a valid username/ID and try again.',
- ['3'] = 'That\'s a %s, not a user!'
- },
- ['gif'] = {
- ['1'] = 'Please enter a search query (that is, what you want me to search GIPHY for, i.e. "cat" will return a GIF of a cat).'
- },
- ['godwords'] = {
- ['1'] = 'Please enter a numerical value, between 1 and 64!',
- ['2'] = 'That number is too small, please specify one between 1 and 64!',
- ['3'] = 'That number is too large, please specify one between 1 and 64!'
- },
- ['gallowlist'] = {
- ['1'] = 'Please reply-to the user you\'d like to globally allowlist, or specify them by username/ID.',
- ['2'] = 'I couldn\'t get information about "%s", please check it\'s a valid username/ID and try again.',
- ['3'] = 'That\'s a %s, not a user!'
- },
- ['hackernews'] = {
- ['1'] = 'Top Stories from Hacker News:'
- },
- ['help'] = {
- ['1'] = 'No results found!',
- ['2'] = 'There were no features found matching "%s", please try and be more specific!',
- ['3'] = '\n\nArguments: <required> [optional]\n\nSearch for a feature or get help with a command by using my inline search functionality - just mention me in any chat using the syntax @%s <search query>.',
- ['4'] = 'Previous',
- ['5'] = 'Next',
- ['6'] = 'Back',
- ['7'] = 'Search',
- ['8'] = 'You are on page %s of %s!',
- ['9'] = [[
-I can perform many administrative actions in your groups, just add me as an administrator and send /administration to adjust the settings for your group.
-Here are some administrative commands and a brief comment regarding what they do:
-
-• /pin <text> - Send a Markdown-formatted message which can be edited by using the same command with different text, to save you from having to re-pin a message if you can't edit it (which happens if the message is older than 48 hours)
-
-• /ban - Ban a user by replying to one of their messages, or by specifying them by username/ID
-
-• /kick - Kick (ban and then unban) a user by replying to one of their messages, or by specifying them by username/ID
-
-• /unban - Unban a user by replying to one of their messages, or by specifying them by username/ID
-
-• /setrules <text> - Set the given Markdown-formatted text as the group rules, which will be sent whenever somebody uses /rules
- ]],
- ['10'] = [[
-• /setwelcome - Set the given Markdown-formatted text as a welcome message that will be sent every time a user joins your group (the welcome message can be disabled in the administration menu, accessible via /administration). You can use placeholders to automatically customise the welcome message for each user. Use $user\_id to insert the user's numerical ID, $chat\_id to insert the chat's numerical ID, $name to insert the user's name, $title to insert the chat title and $username to insert the user's username (if the user doesn't have an @username, their name will be used instead, so it is best to avoid using this with $name)
-
-• /warn - Warn a user, and ban them when they hit the maximum number of warnings
-
-• /mod - Promote the replied-to user, giving them access to administrative commands such as /ban, /kick, /warn etc. (this is useful when you don't want somebody to have the ability to delete messages!)
-
-• /demod - Demote the replied-to user, stripping them from their moderation status and revoking their ability to use administrative commands
-
-• /staff - View the group's creator, administrators, and moderators in a neatly-formatted list
- ]],
- ['11'] = [[
-• /report - Forwards the replied-to message to all administrators and alerts them of the current situation
-
-• /setlink <URL> - Set the group's link to the given URL, which will be sent whenever somebody uses /link
-
-• /links <text> - Allowlists all of the Telegram links found in the given text (includes @username links)
- ]],
- ['12'] = 'Below are some links you might find useful:',
- ['13'] = 'Development',
- ['14'] = 'Channel',
- ['15'] = 'Support',
- ['16'] = 'FAQ',
- ['17'] = 'Source',
- ['18'] = 'Donate',
- ['19'] = 'Rate',
- ['20'] = 'Administration Log',
- ['21'] = 'Admin Settings',
- ['22'] = 'Plugins',
- ['23'] = [[
-<b>Hi %s! My name's %s, it's a pleasure to meet you</b> %s
-
-I understand many commands, which you can learn more about by pressing the "Commands" button using the attached keyboard.
-
-%s <b>Tip:</b> Use the "Settings" button to change how I work%s!
-
-%s <b>Find me useful, or just want to help?</b> Donations are very much appreciated, use /donate for more information!
- ]],
- ['24'] = 'in'
- },
- ['id'] = {
- ['1'] = 'I\'m sorry, but I don\'t recognize that user. To teach me who they are, forward a message from them to me or get them to send me a message.',
- ['2'] = 'Queried Chat:',
- ['3'] = 'This Chat:',
- ['4'] = 'Click to send the result!'
- },
- ['imdb'] = {
- ['1'] = 'Previous',
- ['2'] = 'Next',
- ['3'] = 'You are on page %s of %s!'
- },
- ['import'] = {
- ['1'] = 'I don\'t recognize that chat!',
- ['2'] = 'That\'s not a supergroup, therefore I cannot import any settings from it!',
- ['3'] = 'Successfully imported administrative settings & toggled plugins from %s to %s!'
- },
- ['info'] = {
- ['1'] = [[
-```
-Redis:
-%s Config File: %s
-%s Mode: %s
-%s TCP Port: %s
-%s Version: %s
-%s Uptime: %s days
-%s Process ID: %s
-%s Expired Keys: %s
-
-%s User Count: %s
-%s Group Count: %s
-
-System:
-%s OS: %s
-```
- ]]
- },
- ['instagram'] = {
- ['1'] = '@%s on Instagram'
- },
- ['ipsw'] = {
- ['1'] = '<b>%s</b> iOS %s\n\n<code>MD5 sum: %s\nSHA1 sum: %s\nFile size: %s GB</code>\n\n<i>%s %s</i>',
- ['2'] = 'This firmware is no longer being signed!',
- ['3'] = 'This firmware is still being signed!',
- ['4'] = 'Please select your model:',
- ['5'] = 'Please select your firmware version:',
- ['6'] = 'Please select your device type:',
- ['7'] = 'iPod Touch',
- ['8'] = 'iPhone',
- ['9'] = 'iPad',
- ['10'] = 'Apple TV'
- },
- ['ispwned'] = {
- ['1'] = 'That account was found in the following leaks:'
- },
- ['isup'] = {
- ['1'] = 'This website appears to be up, maybe it\'s just you?',
- ['2'] = 'That doesn\'t appear to be a valid site!',
- ['3'] = 'It\'s not just you, this website looks down from here.'
- },
- ['itunes'] = {
- ['1'] = 'Name:',
- ['2'] = 'Artist:',
- ['3'] = 'Album:',
- ['4'] = 'Track:',
- ['5'] = 'Disc:',
- ['6'] = 'The original query could not be found, you\'ve probably deleted the original message.',
- ['7'] = 'The artwork can be found below:',
- ['8'] = 'Please enter a search query (that is, what you want me to search iTunes for, i.e. "Green Day American Idiot" will return information about the first result for American Idiot by Green Day).',
- ['9'] = 'Get Album Artwork'
- },
- ['kick'] = {
- ['1'] = 'Which user would you like me to kick? You can specify this user by their @username or numerical ID.',
- ['2'] = 'I cannot kick this user because they are a moderator or an administrator in this chat.',
- ['3'] = 'I cannot kick this user because they have already left this chat.',
- ['4'] = 'I cannot kick this user because they have already been kicked from this chat.',
- ['5'] = 'I need to have administrative permissions in order to kick this user. Please amend this issue, and try again.'
- },
- ['lastfm'] = {
- ['1'] = '%s\'s last.fm username has been set to "%s".',
- ['2'] = 'Your last.fm username has been forgotten!',
- ['3'] = 'You don\'t currently have a last.fm username set!',
- ['4'] = 'Please specify your last.fm username or set it with /fmset.',
- ['5'] = 'No history was found for this user.',
- ['6'] = '%s is currently listening to:\n',
- ['7'] = '%s last listened to:\n',
- ['8'] = 'Unknown',
- ['9'] = 'Click to send the result.'
- },
- ['lmgtfy'] = {
- ['1'] = 'Let me Google that for you!'
- },
- ['location'] = {
- ['1'] = 'You don\'t have a location set. What would you like your new location to be?'
- },
- ['logchat'] = {
- ['1'] = 'Please enter the username or numerical ID of the chat you wish to log all administrative actions into.',
- ['2'] = 'Checking to see whether that chat is valid...',
- ['3'] = 'I\'m sorry, it appears you\'ve either specified an invalid chat, or you\'ve specified a chat I haven\'t been added to yet. Please rectify this and try again.',
- ['4'] = 'You can\'t set a user as your log chat!',
- ['5'] = 'You don\'t appear to be an administrator in that chat!',
- ['6'] = 'It seems I\'m already logging administrative actions into that chat! Use /logchat to specify a new one.',
- ['7'] = 'That chat is valid, I\'m now going to try and send a test message to it, just to ensure I have permission to post!',
- ['8'] = 'Hello, World - this is a test message to check my posting permissions - if you\'re reading this, then everything went OK!',
- ['9'] = 'All done! From now on, any administrative actions in this chat will be logged into %s - to change the chat you want me to log administrative actions into, just send /logchat.'
- },
- ['lua'] = {
- ['1'] = 'Please enter a string of Lua to execute!'
- },
- ['lyrics'] = {
- ['1'] = 'Spotify',
- ['2'] = 'Show Lyrics',
- ['3'] = 'Please enter a search query (that is, what song/artist/lyrics you want me to get lyrics for, i.e. "Green Day Basket Case" will return the lyrics for the song Basket Case by Green Day).'
- },
- ['minecraft'] = {
- ['1'] = '<b>%s has changed his/her username %s time</b>',
- ['2'] = '<b>%s has changed his/her username %s times</b>',
- ['3'] = 'Previous',
- ['4'] = 'Next',
- ['5'] = 'Back',
- ['6'] = 'UUID',
- ['7'] = 'Avatar',
- ['8'] = 'Username History',
- ['9'] = 'Please select an option:',
- ['10'] = 'Please enter the username of the Minecraft player you would like to view information about (i.e. sending "Notch" will view information about the player Notch).',
- ['11'] = 'Minecraft usernames are between 3 and 16 characters long.'
- },
- ['msglink'] = {
- ['1'] = 'You can only use this command in supergroups and channels.',
- ['2'] = 'This %s must be public, with a @username.',
- ['3'] = 'Please reply to the message you\'d like to get a link for.'
- },
- ['mute'] = {
- ['1'] = 'Which user would you like me to mute? You can specify this user by their @username or numerical ID.',
- ['2'] = 'I cannot mute this user because they are already muted in this chat.',
- ['3'] = 'I cannot mute this user because they are a moderator or an administrator in this chat.',
- ['4'] = 'I cannot mute this user because they have already left (or been kicked from) this chat.',
- ['5'] = 'I need to have administrative permissions in order to mute this user. Please amend this issue, and try again.'
- },
- ['myspotify'] = {
- ['1'] = 'Profile',
- ['2'] = 'Following',
- ['3'] = 'Recently Played',
- ['4'] = 'Currently Playing',
- ['5'] = 'Top Tracks',
- ['6'] = 'Top Artists',
- ['7'] = 'You don\'t appear to be following any artists!',
- ['8'] = 'Your Top Artists',
- ['9'] = 'You don\'t appear to have any tracks in your library!',
- ['10'] = 'Your Top Tracks',
- ['11'] = 'You don\'t appear to be following any artists!',
- ['12'] = 'Artists You Follow',
- ['13'] = 'You don\'t appear to have recently played any tracks!',
- ['14'] = '<b>Recently Played</b>\n%s %s\n%s %s\n%s Listened to at %s:%s on %s/%s/%s.',
- ['15'] = 'The request has been accepted for processing, but the processing has not been completed.',
- ['16'] = 'You don\'t appear to be listening to anything right now!',
- ['17'] = 'Currently Playing',
- ['18'] = 'An error occured whilst re-authorising your Spotify account!',
- ['19'] = 'Successfully re-authorised your Spotify account! Processing your original request...',
- ['20'] = 'Re-authorising your Spotify account, please wait...',
- ['21'] = 'You need to authorise mattata in order to connect your Spotify account. Click [here](https://accounts.spotify.com/en/authorize?client_id=%s&response_type=code&redirect_uri=%s&scope=user-library-read,playlist-read-private,playlist-read-collaborative,user-read-private,user-read-email,user-follow-read,user-top-read,user-read-playback-state,user-read-recently-played,user-read-currently-playing,user-modify-playback-state) and press the green "OKAY" button to link mattata to your Spotify account. After you\'ve done that, send the link you were redirected to (it should begin with "%s", followed by a unique code) in reply to this message.',
- ['22'] = 'Playlists',
- ['23'] = 'Use Inline Mode',
- ['24'] = 'Lyrics',
- ['25'] = 'No devices were found.',
- ['26'] = 'You don\'t appear to have any playlists.',
- ['27'] = 'Your Playlists',
- ['28'] = '%s %s [%s tracks]',
- ['29'] = '%s %s [%s]\nSpotify %s user\n\n<b>Devices:</b>\n%s',
- ['30'] = 'Playing previous track...',
- ['31'] = 'You are not a premium user!',
- ['32'] = 'I could not find any devices.',
- ['33'] = 'Playing next track...',
- ['34'] = 'Resuming track...',
- ['35'] = 'Your device is temporarily unavailable...',
- ['36'] = 'No devices were found!',
- ['37'] = 'Pausing track...',
- ['38'] = 'Now playing',
- ['39'] = 'Shuffling your music...',
- ['40'] = 'That\'s not a valid volume. Please specify a number between 0 and 100.',
- ['41'] = 'The volume has been set to %s%%!',
- ['42'] = 'This message is using an old version of this plugin, please request a new one by sending /myspotify!'
- },
- ['name'] = {
- ['1'] = 'The name I currently respond to is "%s" - to change this, use /name <text> (where <text> is what you want me to respond to).',
- ['2'] = 'My new name needs to be between 2 and 32 characters long!',
- ['3'] = 'My name may only contain alphanumeric characters!',
- ['4'] = 'I will now respond to "%s", instead of "%s" - to change this, use /name <text> (where <text> is what you want me to respond to).'
- },
- ['netflix'] = {
- ['1'] = 'Read more.'
- },
- ['news'] = {
- ['1'] = '"<code>%s</code>" isn\'t a valid Lua pattern.',
- ['2'] = 'I couldn\'t retrieve a list of sources.',
- ['3'] = '<b>News sources found matching</b> "<code>%s</code>":\n\n%s',
- ['4'] = '<b>Here are the current available news sources you can use with</b> /news<b>. Use</b> /nsources &lt;query&gt; <b>to search the list of news sources for a more specific set of results. Searches are matched using Lua patterns</b>\n\n%s',
- ['5'] = 'You don\'t have a preferred news source. Use /setnews <source> to set one. View a list of sources using /nsources, or narrow down the results by using /nsources <query>.',
- ['6'] = 'Your current preferred news source is %s. Use /setnews <source> to change it. View a list of sources using /nsources, or narrow down the results by using /nsources <query>.',
- ['7'] = 'Your preferred source is already set to %s! Use /news to view the current top story.',
- ['8'] = 'That\'s not a valid news source. View a list of sources using /nsources, or narrow down the results by using /nsources <query>.',
- ['9'] = 'Your preferred news source has been updated to %s! Use /news to view the current top story.',
- ['10'] = 'That\'s not a valid source, use /nsources to view a list of available sources. If you have a preferred source, use /setnews <source> to automatically have news from that source sent when you send /news, without any arguments needed.',
- ['11'] = 'Read more.'
- },
- ['nick'] = {
- ['1'] = 'Your nickname has now been forgotten!',
- ['2'] = 'Your nickname has been set to "%s"!'
- },
- ['ninegag'] = {
- ['1'] = 'Read More'
- },
- ['optout'] = {
- ['1'] = 'You have opted-in to having data you send collected! Use /optout to opt-out.',
- ['2'] = 'You have opted-out of having data you send collected! Use /optin to opt-in.'
- },
- ['paste'] = {
- ['1'] = 'Please select a service to upload your paste to:'
- },
- ['pay'] = {
- ['1'] = 'You currently have %s mattacoins. Earn more by winning games of Tic-Tac-Toe, using /game - You will win 100 mattacoins for every game you win, and you will lose 50 for every game you lose.',
- ['2'] = 'You must use this command in reply to the user you\'d like to send mattacoins to.',
- ['3'] = 'Please specify the amount of mattacoins you\'d like to give %s.',
- ['4'] = 'The amount specified should be a numerical value, of which can be no less than 0.',
- ['5'] = 'You can\'t send money to yourself!',
- ['6'] = 'You don\'t have enough funds to complete that transaction!',
- ['7'] = '%s mattacoins have been sent to %s. Your new balance is %s mattacoins.'
- },
- ['pin'] = {
- ['1'] = 'You haven\'t set a pin before. Use /pin <text> to set one. Markdown formatting is supported.',
- ['2'] = 'Here is the last message generated using /pin.',
- ['3'] = 'I found an existing pin in the database, but the message I sent it in seems to have been deleted, and I can\'t find it anymore. You can set a new one with /pin <text>. Markdown formatting is supported.',
- ['4'] = 'There was an error whilst updating your pin. Either the text you entered contained invalid Markdown syntax, or the pin has been deleted. I\'m now going to try and send you a new pin, which you\'ll be able to find below - if you need to modify it then, after ensuring the message still exists, use /pin <text>.',
- ['5'] = 'I couldn\'t send that text because it contains invalid Markdown syntax.',
- ['6'] = 'Click here to see the pin, updated to contain the text you gave me.'
- },
- ['pokedex'] = {
- ['1'] = 'Name: %s\nID: %s\nType: %s\nDescription: %s'
- },
- ['prime'] = {
- ['1'] = 'Please enter a number between 1 and 99999.',
- ['2'] = '%s is a prime number!',
- ['3'] = '%s is NOT a prime number...'
- },
- ['promote'] = {
- ['1'] = 'I cannot promote this user because they are a moderator or an administrator of this chat.',
- ['2'] = 'I cannot promote this user because they have already left this chat.',
- ['3'] = 'I cannot promote this user because they have already been kicked from this chat.'
- },
- ['quote'] = {
- ['1'] = 'This user has opted out of data-storing functionality.',
- ['2'] = 'There are no saved quotes for %s! You can save one by using /save in reply to a message they send.'
- },
- ['randomsite'] = {
- ['1'] = 'Generate Another'
- },
- ['randomword'] = {
- ['1'] = 'Generate Another',
- ['2'] = 'Your random word is <b>%s</b>!'
- },
- ['report'] = {
- ['1'] = 'Please reply to the message you would like to report to the group\'s administrators.',
- ['2'] = 'You can\'t report your own messages, are you just trying to be funny?',
- ['3'] = '<b>%s needs help in %s!</b>',
- ['4'] = 'Click here to view the reported message.',
- ['5'] = 'I\'ve successfully reported that message to %s admin(s)!'
- },
- ['rms'] = {
- ['1'] = 'Holy GNU!'
- },
- ['save'] = {
- ['1'] = 'This user has opted out of data-storing functionality.',
- ['2'] = 'That message has been saved in my database, and added to the list of possible responses for when /quote is used in reply to %s!'
- },
- ['sed'] = {
- ['1'] = '%s\n\n<i>%s didn\'t mean to say this!</i>',
- ['2'] = '%s\n\n<i>%s has admitted defeat.</i>',
- ['3'] = '%s\n\n<i>%s isn\'t sure if they were mistaken...</i>',
- ['4'] = 'Screw you, <i>when am I ever wrong?</i>',
- ['5'] = '"<code>%s</code>" isn\'t a valid Lua pattern.',
- ['6'] = 'Hey %s, %s seems to think you meant:\n<i>%s</i>',
- ['7'] = 'Yes',
- ['8'] = 'No',
- ['9'] = 'Not sure',
- ['10'] = 'Just edit your message, idiot.'
- },
- ['setgrouplang'] = {
- ['1'] = 'This group\'s language has been set to %s!',
- ['2'] = 'This group\'s language is currently %s.\nPlease note that some strings may not be translated as of yet. If you\'d like to change your language, select one using the keyboard below:',
- ['3'] = 'The option to force users to use the same language in this group is currently disabled. This setting should be toggled from /administration but, to make things easier for you, I\'ve included a button below.',
- ['4'] = 'Enable',
- ['5'] = 'Disable'
- },
- ['setlang'] = {
- ['1'] = 'Your language has been set to %s!',
- ['2'] = 'Your language is currently %s.\nPlease note that some strings may not be translated as of yet. If you\'d like to change your language, select one using the keyboard below:'
- },
- ['setlink'] = {
- ['1'] = 'That\'s not a valid URL.',
- ['2'] = 'Link set successfully!'
- },
- ['setrules'] = {
- ['1'] = 'Invalid Markdown formatting.',
- ['2'] = 'Successfully set the new rules!'
- },
- ['setwelcome'] = {
- ['1'] = 'What would you like the welcome message to be? The text you specify will be Markdown-formatted and sent every time a user joins the chat (the welcome message can be disabled in the administration menu, accessible via /administration). You can use placeholders to automatically customise the welcome message for each user. Use $user_id to insert the user\'s numerical ID, $chat_id to insert the chat\'s numerical ID, $name to insert the user\'s name, $title to insert the chat\'s title and $username to insert the user\'s username (if the user doesn\'t have an @username, their name will be used instead, so it is best to avoid using this in conjunction with $name).',
- ['2'] = 'There was an error formatting your message, please check your Markdown syntax and try again.',
- ['3'] = 'The welcome message for %s has successfully been updated!'
- },
- ['share'] = {
- ['1'] = 'Share'
- },
- ['shorten'] = {
- ['1'] = 'Please select a URL shortener using the buttons below:'
- },
- ['shsh'] = {
- ['1'] = 'I couldn\'t fetch any SHSH blobs for that ECID, please ensure it\'s valid and you have saved them using https://tsssaver.1conan.com.',
- ['2'] = 'SHSH blobs for that device are available for the following versions of iOS:\n',
- ['3'] = 'Download .zip'
- },
- ['statistics'] = {
- ['1'] = 'No messages have been sent in this chat!',
- ['2'] = '<b>Statistics for:</b> %s\n\n%s\n<b>Total messages sent:</b> %s',
- ['3'] = 'The statistics for this chat have been reset!',
- ['4'] = 'I could not reset the statistics for this chat. Perhaps they have already been reset?'
- },
- ['steam'] = {
- ['1'] = 'Your Steam username has been set to "%s".',
- ['2'] = '"%s" isn\'t a valid Steam username.',
- ['3'] = '%s has been a user on Steam since %s, on %s. They last logged off at %s, on %s. Click <a href="%s">here</a> to view their Steam profile.',
- ['4'] = '%s, AKA "%s",'
- },
- ['synonym'] = {
- ['1'] = 'You could use the word <b>%s</b>, instead of %s.'
- },
- ['thoughts'] = {
- ['1'] = '%s\n\nPositive: <code>%s%% [%s]</code>\nNegative: <code>%s%% [%s]</code>\nIndifferent: <code>%s%% [%s]</code>\nTotal thoughts: <code>%s</code>'
- },
- ['tobinary'] = {
- ['1'] = 'Please enter the string you would like to convert to binary.'
- },
- ['trust'] = {
- ['1'] = 'I cannot trust this user because they are a moderator or an administrator of this chat.',
- ['2'] = 'I cannot trust this user because they have already left this chat.',
- ['3'] = 'I cannot trust this user because they have already been kicked from this chat.'
- },
- ['unmute'] = {
- ['1'] = 'Which user would you like me to unmute? You can specify this user by their @username or numerical ID.',
- ['2'] = 'I cannot unmute this user because they are not currently muted in this chat.',
- ['3'] = 'I cannot unmute this user because they are a moderator or an administrator in this chat.',
- ['4'] = 'I cannot unmute this user because they have already left (or been kicked from) this chat.'
- },
- ['untrust'] = {
- ['1'] = 'Which user would you like me to untrust? You can specify this user by their @username or numerical ID.',
- ['2'] = 'I cannot untrust this user because they are a moderator or an administrator in this chat.',
- ['3'] = 'I cannot untrust this user because they have already left this chat.',
- ['4'] = 'I cannot untrust this user because they have already been kicked from this chat.'
- },
- ['upload'] = {
- ['1'] = 'Please reply to the file you\'d like to download to the server. It must be <= 20 MB.',
- ['2'] = 'That file is too large. It must be <= 20 MB.',
- ['3'] = 'I couldn\'t get this file, it\'s probably too old.',
- ['4'] = 'There was an error whilst retrieving this file.',
- ['5'] = 'Successfully downloaded the file to the server - it can be found at <code>%s</code>!'
- },
- ['version'] = {
- ['1'] = '@%s AKA %s `[%s]` is running mattata %s, created by [Matthew Hesketh](https://t.me/wrxck). The source code is available on [GitHub](https://github.com/wrxck/mattata).'
- },
- ['voteban'] = {
- ['1'] = 'Which user would you like to open up a vote-ban for? You can specify this user by their @username or numerical ID.',
- ['2'] = 'I cannot setup a vote-ban for this user because they are a moderator or an administrator in this chat.',
- ['3'] = 'I cannot setup a vote-ban for this user because they have already left (or been kicked from) this chat.',
- ['4'] = 'Should %s [%s] be banned from %s? %s upvotes are required for an immediate ban, and %s downvotes are required for this vote to be closed.',
- ['5'] = 'Yes [%s]',
- ['6'] = 'No [%s]',
- ['7'] = 'The people have spoken. I have banned %s [%s] from %s because %s people voted for me to do so.',
- ['8'] = 'The required upvote amount was reached, however, I was unable to ban %s - perhaps they\'ve left the group or been promoted since we opened the vote to ban them? It\'s either that, or I no longer have the administrative privileges required in order to perform this action!',
- ['9'] = 'The people have spoken. I haven\'t banned %s [%s] from %s because the required %s people downvoted the decision to ban them.',
- ['10'] = 'You upvoted the decision to ban %s [%s]!',
- ['11'] = 'Your current vote has been retracted, use the buttons again to re-submit your vote.',
- ['12'] = 'You downvoted the decision to ban %s [%s]!',
- ['13'] = 'A vote-ban has already been opened for this user!'
- },
- ['weather'] = {
- ['1'] = 'You don\'t have a location set. Use /setloc <location> to set one.',
- ['2'] = 'It\'s currently %s (feels like %s) in %s. %s'
- },
- ['welcome'] = {
- ['1'] = 'Group Rules'
- },
- ['allowlist'] = {
- ['1'] = 'Which user would you like me to allowlist? You can specify this user by their @username or numerical ID.',
- ['2'] = 'I cannot allowlist this user because they are a moderator or an administrator in this chat.',
- ['3'] = 'I cannot allowlist this user because they have already left this chat.',
- ['4'] = 'I cannot allowlist this user because they have already been banned from this chat.'
- },
- ['wikipedia'] = {
- ['1'] = 'Read more.'
- },
- ['youtube'] = {
- ['1'] = 'Previous',
- ['2'] = 'Next',
- ['3'] = 'You are on page %s of %s!'
- }
-}
\ No newline at end of file
diff --git a/languages/pl_pl.lua b/languages/pl_pl.lua
deleted file mode 100644
index 7e4b502..0000000
--- a/languages/pl_pl.lua
+++ /dev/null
@@ -1,811 +0,0 @@
--- This is a language file for mattata
--- Language: pl-pl
--- Author: GingerPlusPlus
-
--- DO NOT CHANGE ANYTHING THAT BEGINS OR ENDS WITH A %
--- THESE ARE PLACEHOLDERS!
-
--- DO NOT CHANGE ANY MARKDOWN/HTML FORMATTING!
--- IF YOU ARE UNSURE, ASK ON TELEGRAM (t.me/mattataDev)
-
-return {
- ['errors'] = {
- ['connection'] = 'Błąd połączenia.',
- ['results'] = 'Brak pasujących wyników.',
- ['supergroup'] = 'Ta komenda może być używana tylko w supergrupach.',
- ['admin'] = 'Aby użyć tej komendy, musisz być moderatorem lub administratorem w tej grupie.',
- ['unknown'] = 'Nieznany użytkownik. Aby pokazać mi kto to, przekaż wiadomość od niego do dowolnego czatu w którym jestem.',
- ['generic'] = 'Wystąpił błąd!',
- ['use'] = 'You are not allowed to use this!',
- ['private'] = 'You can only use this command in private chat!'
- },
- ['addcommand'] = {
- ['1'] = 'Please specify the command in the format <code>/command - description</code>',
- ['2'] = 'I couldn\'t retrieve my commands!',
- ['3'] = 'The command description can\'t be longer than 256 characters!',
- ['4'] = 'An unknown error occurred! I couldn\'t add your command!',
- ['5'] = 'Success! Command added.'
- },
- ['addrule'] = {
- ['1'] = 'Please specify the rule you would like to add!',
- ['2'] = 'You don\'t have any rules to add to! Please set group rules using /setrules!',
- ['3'] = 'I couldn\'t add that rule, as it would make the length of the rules longer than Telegram\'s 4096 character limit!',
- ['4'] = 'I couldn\'t add that rule, it appears it contains invalid Markdown formatting!',
- ['5'] = 'Successfully updated the rules!'
- },
- ['addslap'] = {
- ['1'] = 'You can only use this command in groups!',
- ['2'] = 'The slap cannot contain curly braces apart from placeholders!',
- ['3'] = 'The slap cannot be any longer than 256 characters in length!',
- ['4'] = 'I\'ve successfully added that slap as a possibility for /slap in this group!',
- ['5'] = 'You must include placeholders in your slap. Use {ME} for the person executing and {THEM} for the victim.'
- },
- ['administration'] = {
- ['1'] = 'Enable Administration',
- ['2'] = 'Disable Administration',
- ['3'] = 'Anti-Spam Settings',
- ['4'] = 'Warning Settings',
- ['5'] = 'Vote-Ban Settings',
- ['6'] = 'Welcome New Users?',
- ['7'] = 'Send Rules On Join?',
- ['8'] = 'Send Rules In Group?',
- ['9'] = 'Back',
- ['10'] = 'Next',
- ['11'] = 'Word Filter',
- ['12'] = 'Anti-Bot',
- ['13'] = 'Anti-Link',
- ['14'] = 'Log Actions?',
- ['15'] = 'Anti-RTL',
- ['16'] = 'Anti-Spam Action',
- ['17'] = 'Ban',
- ['18'] = 'Kick',
- ['19'] = 'Delete Commands?',
- ['20'] = 'Force Group Language?',
- ['21'] = 'Send Settings In Group?',
- ['22'] = 'Delete Reply On Action?',
- ['23'] = 'Require Captcha?',
- ['24'] = 'Use Inline Captcha?',
- ['25'] = 'Ban SpamWatch-flagged users?',
- ['26'] = 'Number of warnings until %s:',
- ['27'] = 'Upvotes needed to ban:',
- ['28'] = 'Downvotes needed to dismiss:',
- ['29'] = 'Deleted %s, and its matching link from the database!',
- ['30'] = 'There were no entries found in the database matching "%s"!',
- ['31'] = 'You\'re not an administrator in that chat!',
- ['32'] = 'The minimum number of upvotes required for a vote-ban is %s.',
- ['33'] = 'The maximum number of upvotes required for a vote-ban is %s.',
- ['34'] = 'The minimum number of downvotes required for a vote-ban is %s.',
- ['35'] = 'The maximum number of downvotes required for a vote-ban is %s.',
- ['36'] = 'The maximum number of warnings is %s.',
- ['37'] = 'The minimum number of warnings is %s.',
- ['38'] = 'You can add one or more words to the word filter by using /filter <word(s)>',
- ['39'] = 'You will no longer be reminded that the administration plugin is disabled. To enable it, use /administration.',
- ['40'] = 'That\'s not a valid chat!',
- ['41'] = 'You don\'t appear to be an administrator in that chat!',
- ['42'] = 'My administrative functionality can only be used in groups/channels! If you\'re looking for help with using my administrative functionality, check out the "Administration" section of /help! Alternatively, if you wish to manage the settings for a group you administrate, you can do so here by using the syntax /administration <chat>.',
- ['43'] = 'Use the keyboard below to adjust the administration settings for <b>%s</b>:',
- ['44'] = 'Please send me a [private message](https://t.me/%s), so that I can send you this information.',
- ['45'] = 'I have sent you the information you requested via private chat.',
- ['46'] = 'Remove Channel Pins?',
- ['47'] = 'Remove Other Pins?',
- ['48'] = 'Remove Pasted Code?',
- ['49'] = 'Prevent Inline Bots?',
- ['50'] = 'Kick Media On Join?',
- ['51'] = 'Enable Plugins For Admins?',
- ['52'] = 'Kick URLs On Join?'
- },
- ['afk'] = {
- ['1'] = 'Ta funkcja jest dostępna tylko dla użytkowników posiadających @username.',
- ['2'] = '%s powrócił(a) po nieobecności trwającej %s!',
- ['3'] = 'Komentarz',
- ['4'] = '%s jest teraz AFK.%s'
- },
- ['antispam'] = {
- ['1'] = 'Disable',
- ['2'] = 'Enable',
- ['3'] = 'Disable limit',
- ['4'] = 'Enable limits on %s',
- ['5'] = 'All Administration Settings',
- ['6'] = '%s [%s] has kicked %s [%s] from %s [%s] for hitting the configured anti-spam limit for [%s] media.',
- ['7'] = 'Kicked %s for hitting the configured antispam limit for [%s] media.',
- ['8'] = 'The maximum limit is 100.',
- ['9'] = 'The minimum limit is 1.',
- ['10'] = 'Modify the anti-spam settings for %s below:',
- ['11'] = 'Hey %s, if you\'re going to send code that is longer than %s characters in length, please do so using /paste in <a href="https://t.me/%s">private chat with me</a>!',
- ['12'] = '%s <code>[%s]</code> has %s %s <code>[%s]</code> from %s <code>[%s]</code> for sending Telegram invite link(s).\n#chat%s #user%s',
- ['13'] = '%s %s for sending Telegram invite link(s).',
- ['14'] = 'Hey, I noticed you\'ve got anti-link enabled and you\'re currently not allowing your users to mention a chat you\'ve just mentioned, if you\'d like to allowlist it, use /allowlink <links>.',
- ['15'] = 'Kicked %s <code>[%s]</code> from %s <code>[%s]</code> for sending media within their first few messages.\n#chat%s #user%s',
- ['16'] = 'Kicked %s <code>[%s]</code> from %s <code>[%s]</code> for sending a URL within their first few messages.\n#chat%s #user%s',
- ['17'] = 'Action',
- ['18'] = 'Kick',
- ['19'] = 'Ban',
- ['20'] = 'Mute'
- },
- ['appstore'] = {
- ['1'] = 'Zobacz na iTunes',
- ['2'] = 'rating',
- ['3'] = 'ratings'
- },
- ['authspotify'] = {
- ['1'] = 'You are already authorised using that account.',
- ['2'] = 'Authorising, please wait...',
- ['3'] = 'A connection error occured. Are you sure you replied with the correct link? It should look like',
- ['4'] = 'Successfully authorised your Spotify account!'
- },
- ['avatar'] = {
- ['1'] = 'Nie mogę dostać zdjęć profilowych tego użytkownika, upewnij się że podano poprawne @username lub ID.',
- ['2'] = 'Ten użytkownik nie ma żadnych zdjęć profilowych.',
- ['3'] = 'Ten użytkownik nie ma aż tylu zdjęć profilowych!',
- ['4'] = 'Ten użytkownik zrezygnował ze zbierania danych na jego temat, toteż nie mogę pokazać Ci jego zdjęć profilowych.',
- ['5'] = 'User: %s\nPhoto: %s/%s\nSend /avatar %s [offset] to @%s to view a specific photo of this user',
- ['6'] = 'User: %s\nPhoto: %s/%s\nUse /avatar %s [offset] to view a specific photo of this user'
- },
- ['ban'] = {
- ['1'] = 'Kogo mam zbanować? Podaj @username lub ID.',
- ['2'] = 'Nie mogę zbanować tego użytkownika, ponieważ jest to moderator lub administrator tej grupy.',
- ['3'] = 'Nie mogę zbanować tego użytkownika, ponieważ opuścił on tę grupę.',
- ['4'] = 'Nie mogę zbanować tego użytkownika, ponieważ został on zbanowany już wcześniej.',
- ['5'] = 'Potrzebuję uprawnień administratora aby móc banować.',
- ['6'] = '%s <code>[%s]</code> has banned %s <code>[%s]</code> from %s <code>[%s]</code>%s.\n%s %s',
- ['7'] = '%s has banned %s%s.'
- },
- ['bash'] = {
- ['1'] = 'Podaj komendę to uruchomienia.',
- ['2'] = 'Sukces!'
- },
- ['blocklist'] = {
- ['1'] = 'Kogo mam ignorować? Podaj @username lub ID.',
- ['2'] = 'Nie mogę ignorować tego użytkownika, ponieważ jest to moderator lub administrator tej grupy.',
- ['3'] = 'Nie mogę ignorować tego użytkownika, ponieważ opuścił on tę grupę.',
- ['4'] = 'Nie mogę ignorować tego użytkownika, ponieważ został on zbanowany.',
- ['5'] = '%s <code>[%s]</code> has blocklisted %s <code>[%s]</code> from using %s <code>[%s]</code> in %s <code>[%s]</code>%s.\n%s %s',
- ['6'] = '%s has blocklisted %s from using %s%s.'
- },
- ['blocklistchat'] = {
- ['1'] = '%s został dodany do czarnej listy, nie pozwolę się tam dodać!',
- ['2'] = '%s jest użytkownikiem, ta komenda służy do blokowanie grup i kanałów!',
- ['3'] = '%s wydaje się nie istnieć!'
- },
- ['bugreport'] = {
- ['1'] = 'Twój raport o błędzie został wysłany; ID Twojego raportu to #%s.',
- ['2'] = 'Wystąpił problem podczas raportowania błędu...'
- },
- ['calc'] = {
- ['1'] = 'Klinknij aby wysłać.',
- ['2'] = '"%s" was an unexpected word!',
- ['3'] = 'You cannot have a unit before a number!'
- },
- ['captionbotai'] = {
- ['1'] = 'Nie potrafię opisać tego obrazka.'
- },
- ['cats'] = {
- ['1'] = 'Miau!'
- },
- ['channel'] = {
- ['1'] = 'Nie masz wymaganych uprawnień.',
- ['2'] = 'Wygląda na to że już nie administrujesz tamtą grupą.',
- ['3'] = 'Twoja wiadomość nie mogła zostać wysłana, upewnij się że mam uprawnienia administratora w tamtym kanale.',
- ['4'] = 'Twoja wiadomość została wysłana.',
- ['5'] = 'Nie mogę pobrać listy admistratorów tamtej grupy.',
- ['6'] = 'Wygląda na to że nie jesteś administratorem w tamtej grupie.',
- ['7'] = 'Podaj wiadomość do wysłania, używając /channel <kanał> <wiadomość>.',
- ['8'] = 'Czy jesteś pewien że chcesz wysłać tą wiadomość? Będzie ona wyglądać tak:',
- ['9'] = 'Potwierdź',
- ['10'] = 'Wiadmość zawiera niepoprawny Markdown! Popraw składnię i spróbuj ponownie.'
- },
- ['chatroulette'] = {
- ['1'] = 'Hey! Please don\'t send messages longer than %s characters. We don\'t want to annoy the other user!',
- ['2'] = '*Anonymous said:*\n```\n%s\n```\nTo end your session, send /endchat.',
- ['3'] = 'I\'m afraid I lost connection from the other user! To begin a new chat, please send /chatroulette!',
- ['4'] = 'The other person you were chatting with has ended the session. To start a new one, send /chatroulette.',
- ['5'] = 'Successfully ended your session. To start a new one, send /chatroulette.',
- ['6'] = 'I have successfully removed you from the list of available users.',
- ['7'] = 'You don\'t have a session set up at the moment. To start one, send /chatroulette.',
- ['8'] = 'Finding you a session, please wait...',
- ['9'] = 'I\'m afraid there aren\'t any available users right now, but I have added you to the list of available users! To stop this completely, please send /endchat.',
- ['10'] = 'I have successfully paired you with another user to chat to! Please remember to be kind to them! To end the chat, send /endchat.',
- ['11'] = 'I\'m afraid the user who I tried to pair you with has since blocked me. Please try and send /chatroulette again to try and connect to me!',
- ['12'] = 'I have successfully paired you with another user to chat to! Please remember to be kind to them! To end the chat, send /endchat.'
- },
- ['commandstats'] = {
- ['1'] = 'Nie wysłano jeszcze żadnych komend w tej grupie!',
- ['2'] = '<b>Statystyki komend w:</b> %s\n\n%s\n<b>Liczba wszystkich komend:</b> %s',
- ['3'] = 'Zresetowano statystyki komend w tej grupie!',
- ['4'] = 'Błąd podczas resetowania statystyk, może zostały one zresetowane już wcześniej?'
- },
- ['control'] = {
- ['1'] = 'Heh, chciałbyś!',
- ['2'] = '%s restartuje się...'
- },
- ['copypasta'] = {
- ['1'] = 'Wiadomość na którą odpowiadasz tą komendą nie może być dłuższa niż %s znaków!'
- },
- ['coronavirus'] = {
- ['1'] = [[*COVID-19 Statistics for:* %s
-
-*New confirmed cases:* %s
-*Total confirmed cases:* %s
-*New deaths:* %s
-*Total deaths:* %s
-*New recovered cases:* %s
-*Total recovered cases:* %s]]
- },
- ['counter'] = {
- ['1'] = 'Dodawanie licznika do wiadomości nie powiodło się!'
- },
- ['custom'] = {
- ['1'] = 'Sukces! Ta wiadomość zostanie wysłana za każdym razem gdy ktoś napisze %s!',
- ['2'] = 'Wyzwalacz "%s" nie istnieje!',
- ['3'] = 'Wyzwalacz "%s" został usunięty!',
- ['4'] = 'Nie utworzono żadnych wyzwalaczy',
- ['5'] = 'Wyzwalacze w %s:\n',
- ['6'] = 'Aby utworzyć nowy wyzwalacz, napisz:\n/custom new #wyzwalacz <wartość>.\nAby zobaczyć listę wyzwalaczy, napisz /custom list. Aby usunąć wyzwalacz, napisz, use /custom del #wyzwalacz.'
- },
- ['delete'] = {
- ['1'] = 'Nie mogę usunąć tej wiadomości. Może jest za stara, albo nie istnieje?'
- },
- ['demote'] = {
- ['1'] = 'Kogo mam zdegradować? Podaj @username lub ID.',
- ['2'] = 'Nie mogę zdegradować tego użytkownika, ponieważ nie jest to moderator tej grupy.',
- ['3'] = 'Nie mogę zdegradować tego użytkownika, ponieważ opuścił on tę grupę.',
- ['4'] = 'Nie mogę zdegradować tego użytkownika, ponieważ został on wyrzucony z tej grupy.',
- },
- ['dice'] = {
- ['1'] = 'Najmniejsza dopuszczalna liczba ścian to %s.',
- ['2'] = '%s to limit liczby ścian, i liczby rzutów.',
- ['3'] = 'Limit liczby ścian to %s, a limit liczby rzutów to %s.',
- ['4'] = '%s rzutów %s-ścienną kostką:\n'
- },
- ['doge'] = {
- ['1'] = 'Podaj tekst do umieszczenia na obrazku z Piesełem. Rozdziel wypowiedzi ukośnikiem lub nową linią.'
- },
- ['duckduckgo'] = {
- ['1'] = 'Nie wiem co to jest!'
- },
- ['donate'] = {
- ['1'] = '<b>Hello, %s!</b>\n\nIf you\'re feeling generous, you can contribute to the mattata project by making a monetary donation of any amount. This will go towards server costs and any time and resources used to develop mattata. This is an optional act, however it is greatly appreciated and your name will also be listed publically on mattata\'s GitHub page.\n\nIf you\'re still interested, you can donate <a href="https://paypal.me/wrxck">here</a>. Thank you for your continued support!'
- },
- ['eightball'] = {
- ['1'] = 'Tak.',
- ['2'] = 'Nie.',
- ['3'] = 'Prawdopodobnie.',
- ['4'] = 'Uh... spytaj ponownie później.'
- },
- ['exec'] = {
- ['1'] = 'Wybierz język:',
- ['2'] = 'To trwało zbyt długo... Czy próbowałeś mnie zawiesić?',
- ['3'] = 'Wybrano %s – jesteś pewien?',
- ['4'] = 'Powrót',
- ['5'] = 'Potwierdź',
- ['6'] = 'Podaj fragment kodu który chcesz uruchomić, o język zapytam za chwilę.',
- ['7'] = 'Wybierz język:'
- },
- ['facebook'] = {
- ['1'] = 'Wystąpił błąd!',
- ['2'] = 'Podaj Facebookową nazwę użytkownika.',
- ['3'] = 'Zobacz %s na Facebooku'
- },
- ['fact'] = {
- ['1'] = 'Wygeneruj inny'
- },
- ['fban'] = {
- ['1'] = 'Which user would you like me to Fed-ban? You can specify this user by their @username or numerical ID.',
- ['2'] = 'I cannot Fed-ban this user because they are a moderator or an administrator in this chat.'
- },
- ['flickr'] = {
- ['1'] = 'Szukano:',
- ['2'] = 'Czego chcesz szukać na Flickr?',
- ['3'] = 'Więcej wyników'
- },
- ['fortune'] = {
- ['1'] = 'Kliknij aby wysłać.'
- },
- ['frombinary'] = {
- ['1'] = 'Wprowadź liczbę binarną którą chcesz przeliczyć na tekst.',
- ['2'] = 'Nie jest to poprawna liczba binarna!'
- },
- ['game'] = {
- ['1'] = 'Zwycięstwa: %s\nPorażki: %s\nSaldo: %s mattamonet',
- ['2'] = 'Dołącz',
- ['3'] = 'Gra się już skończyła!',
- ['4'] = 'Nie Twój ruch!',
- ['5'] = 'Nie jesteś w tej grze!',
- ['6'] = 'To pole jest już zajęte, wybierz inne!',
- ['7'] = 'Już jesteś w grze!',
- ['8'] = 'Gra została rozpoczęta już wcześniej!',
- ['9'] = '%s [%s] gra przeciwko %s [%s]\nKolej na ruch gracza %s!',
- ['10'] = '%s wygrał(a) z %s!',
- ['11'] = '%s zremisował(a) z %s!',
- ['12'] = 'Czekanie na przeciwnika...',
- ['13'] = 'Kółko i krzyżyk',
- ['14'] = 'Klinkij aby rozpocząć grę w tej grupie!',
- ['15'] = 'Statystyki dla %s:\n',
- ['16'] = 'Zagraj w kółko i krzyżyk!'
- },
- ['gblocklist'] = {
- ['1'] = 'Odpowiedz do użytkownika którego mam wszędzie ignorować, bądź podaj jego @username lub ID.',
- ['2'] = 'Nie mogę dostać informacji o "%s", upewnij się że jest to poprawny @username lub ID.',
- ['3'] = 'To %s, a nie użytkownik!'
- },
- ['gif'] = {
- ['1'] = 'Co mam wyszukać na Giphy?'
- },
- ['godwords'] = {
- ['1'] = 'Podaj liczbę naturalną pomiędzy 1 a 64!',
- ['2'] = 'Liczba zbyt mała, musi należeć do przedziału od 1 do 64!',
- ['3'] = 'Liczba zbyt duża, musi należeć do przedziału od 1 do 64!'
- },
- ['gallowlist'] = {
- ['1'] = 'Odpowiedz do użytkownika któremu mam znowu odpowiedać, bądź podaj jego @username lub ID.',
- ['2'] = 'Nie mogę dostać informacji o "%s", upewnij się że jest to poprawny @username lub ID.',
- ['3'] = 'To %s, a nie użytkownik!'
- },
- ['hackernews'] = {
- ['1'] = 'Najlepsze historie z Hacker News:'
- },
- ['help'] = {
- ['1'] = 'Brak pasujących wyników!',
- ['2'] = 'Brak funkcji których nazwa pasuje do "%s"!',
- ['3'] = '\n\nArgumenty: <wymagane> [opcjonalne]\n\nSzukaj funkcji lub przeczytaj pomoc do komendy używając wyszukiwania inline - w dowolnym czacie, napisz @%s <czego szukasz>.',
- ['4'] = 'Poprzednia',
- ['5'] = 'Następna',
- ['6'] = 'Powrót',
- ['7'] = 'Szukaj',
- ['8'] = 'Strona %s z %s',
- ['9'] = [[
-Mogę wykonywać wiele akcji administracyjnych w Twoich grupach, dodaj mnie do grupy jako administrator i wyślij /administration żeby dostosować ustawienia dla swojej grupy.
-Niektóre polecenia administracyjne i ich krótki opis:
-
-• /pin <tekst> - Tworzy wiadomość do przypięcia (używane jest formatowanie Markdown). Użyj ponownie aby zedytować przypiętą wiadomość bez konieczności przypinania nowej wiadomości.
-
-• /ban - Zbanuj użytkownika, odpowiadając tą komendą na jego wiadomość, bądź podając jego ID lub @username jako argument
-
-• /kick - Wyrzuć (ban, następnie unban) użytkownika, odpowiadając tą komendą na jego wiadomość, bądź podając jego ID lub @username jako argument
-
-• /unban - Anuluj bana użytkownika, odpowiadając tą komendą na jego wiadomość, bądź podając jego ID lub @username jako argument
-
-• /setrules <tekst> - Ustaw tekst (sformatowany Markdownem) jako zasady grupy, które można przeczytać pisząc /rules
- ]],
- ['10'] = [[
-• /setwelcome <tekst> - Co chcesz powiedzieć każdemu nowemu członkowi? Możesz używać Markdown do formatowania. (Wiadomość powitalną można wyłączyć w menu administracyjnym, pisząc /administration). Użyj $user\_id aby wstawić ID dołączającego użytkownika, $chat\_id aby wstawić ID grupy, $name aby wstawić the imię użytkownika, $title aby wstawić nazwę grupy i $username aby wstawić @username użytkownika (jeśli użytkownik nie ma @username, zostanie wstawione jego imię, więc najlepiej nie używać $name i $username koło siebie)
-
-• /warn - Ostrzeż użytkownika. Użytkownik zostanie zbanowany jeśli osiągnie limit ostrzeżeń
-
-• /mod - Awansuj użytkownika na moderatora, pozwalając im używać poleceń administracyjnych, takich jak /ban, /kick, /warn itp.
-
-• /demod - Zdegraduj moderatora do zwykłego użytkownika, odbierając im możliwość używania poleceń administracyjnych
-
-• /staff - Wyświetl twórcę grupy, administratorów i moderatorów
- ]],
- ['11'] = [[
-• /report - Przekazuje wiadomość na którą odpowiadasz administratorom, ostrzegając ich o zaistniałej sytuacji
-
-• /setlink <URL> - Ustaw link do grupy, który można zobaczyć poleceniem /link
-
-• /links <tekst> - Pozwól na wysyłanie linków znalezionych w tekście (także linki zapisane jako @username)
- ]],
- ['12'] = 'Poniżej jest parę linków które mogą Ci się przydać:',
- ['13'] = 'Development',
- ['14'] = 'Kanał',
- ['15'] = 'Wsparcie',
- ['16'] = 'Częste pytania',
- ['17'] = 'Kod źródłowy',
- ['18'] = 'Wspomóż finansowo',
- ['19'] = 'Oceń',
- ['20'] = 'Log administracyjny',
- ['21'] = 'Ustawienia administracyjne',
- ['22'] = 'Plugins', --!
- ['23'] = [[
-<b>Cześć %s! Mam na imię %s, miło Cię poznać</b> %s
-
-Rozumiem wiele poleceń, które możesz poznać klikając przycisk "Commands".
-
-%s <b>Wskazówka:</b> Użyj przycisku "Settings" poniżej aby dostosować moje zachowanie%s!
-
-%s <b>Find me useful, or just want to help?</b> Donations are very much appreciated, use /donate for more information!
- ]],
- ['24'] = 'w'
- },
- ['id'] = {
- ['1'] = 'Nieznany użytkownik. Aby pokazać mi kto to, przekaż wiadomość od niego do dowolnego czatu w którym jestem.',
- ['2'] = 'Czat o który pytano:',
- ['3'] = 'Ten czat:',
- ['4'] = 'Kliknij aby wysłać.'
- },
- ['imdb'] = {
- ['1'] = 'Poprzednia',
- ['2'] = 'Następna',
- ['3'] = 'Strona %s z %s'
- },
- ['import'] = {
- ['1'] = 'Nie rozpoznaję tamtego czatu!',
- ['2'] = 'To nie jest supergrupa, więc nie mogę zaimportować z niej żadnych ustawień!',
- ['3'] = 'Pomyślnie zaimportowano ustawienia administracyjne i stan pluginów z %s do %s!'
- },
- ['info'] = {
- ['1'] = [[
-```
-Redis:
-%s plik konfiguracyjny: %s
-%s tryb: %s
-%s port TCP: %s
-%s wersja: %s
-%s czas pracy: %s days
-%s ID procesu: %s
-%s Przeterminowane wpisy: %s
-
-%s liczba użytkowników: %s
-%s liczba grup: %s
-
-System:
-%s OS: %s
-```
- ]]
- },
- ['instagram'] = {
- ['1'] = '@%s na Instagramie'
- },
- ['ipsw'] = {
- ['1'] = '<b>%s</b> iOS %s\n\n<code>Suma kontrolna MD5: %s\nSuma kontrolna SHA1: %s\nRozmiar pliku: %s GB</code>\n\n<i>%s %s</i>',
- ['2'] = 'To firmware nie jest już podpisywane!',
- ['3'] = 'To firmware jest wciąż podpisywane!',
- ['4'] = 'Wybierz swój model:',
- ['5'] = 'Wybierz swoją wersję firmware:',
- ['6'] = 'Wybierz swój typ urządzenia:',
- ['7'] = 'iPod Touch',
- ['8'] = 'iPhone',
- ['9'] = 'iPad',
- ['10'] = 'Apple TV'
- },
- ['ispwned'] = {
- ['1'] = 'To konto zostało znalezione w następujących wyciekach:'
- },
- ['isup'] = {
- ['1'] = 'Ta strona internetowa wydaje się działać, może tylko u Ciebie nie działa?',
- ['2'] = 'Nie wygląda mi to na poprawny adres strony internetowej...',
- ['3'] = 'Nie tylko u Ciebie, tutaj też ta strona internetowa wydaje się nie działać.'
- },
- ['itunes'] = {
- ['1'] = 'Nazwa:',
- ['2'] = 'Artysta:',
- ['3'] = 'Album:',
- ['4'] = 'Utwór:',
- ['5'] = 'Płyta:',
- ['6'] = 'Wiadomość zawierająca polecenie została usunięta.',
- ['7'] = 'Okładka poniżej:',
- ['8'] = 'Co mam wyszukać na iTunes?',
- ['9'] = 'Okładka albumu'
- },
- ['kick'] = {
- ['1'] = 'Kogo mam wyrzucić? Podaj @username lub ID.',
- ['2'] = 'Nie mogę wyrzucić tego użytkownika, ponieważ jest to moderator lub administrator tej grupy.',
- ['3'] = 'Nie mogę wyrzucić tego użytkownika, ponieważ opuścił on tę grupę.',
- ['4'] = 'Nie mogę wyrzucić tego użytkownika, ponieważ został on wyrzucony już wcześniej.',
- ['5'] = 'Potrzebuję uprawnień administratora aby móc wyrzucać.'
- },
- ['lastfm'] = {
- ['1'] = 'Nazwa użytkownika last.fm użytkownika %s została ustawiona na "%s".',
- ['2'] = 'Twoja nazwa użytkownika last.fm została zapomniana!',
- ['3'] = 'Nie masz ustawionej nazwy użytkownika last.fm!',
- ['4'] = 'Proszę podaj swoją nazwę użytkownika last.fm bądź ustaw ją używając /fmset.',
- ['5'] = 'Nie znaleziono historii tego użytkownika.',
- ['6'] = '%s słucha w tej chwili:\n',
- ['7'] = '%s ostatnio słuchał(a):\n',
- ['8'] = 'Nieznany',
- ['9'] = 'Kliknij aby wysłać.'
- },
- ['lmgtfy'] = {
- ['1'] = 'Wygoogluję to za Ciebie!'
- },
- ['location'] = {
- ['1'] = 'Nie masz ustawionej lokalizacji. Co mam ustawić jako Twoją nową lokalizację?'
- },
- ['logchat'] = {
- ['1'] = 'Podaj @username bądź ID grupy w której mam rejestrować akcje administracyjnych.',
- ['2'] = 'Sprawdzam czy tamta grupa jest ok...',
- ['3'] = 'Przepraszam, wygląda na to, że grupa nie istnieje, bądź nie jestem jej członkiem. Napraw to i spróbuj ponownie.',
- ['4'] = 'Nie możesz ustawić użytkownika jako dziennik akcji administracyjnych!',
- ['5'] = 'Nie jesteś administratorem w tamtej grupie!',
- ['6'] = 'Wygląda na to że już rejestruję akcje administracyjne w tamtej grupie! Użyj /logchat by wybrać inną.',
- ['7'] = 'Jak na razie wszystko w porządku, spróbuję wysłać tam testową wiadomość żeby upawnić się że mogę wywyłać tam wiadomości...',
- ['8'] = 'Witaj świecie - to wiadomość testowa, żeby sprawdzić czy mogę tu pisać - jeśli to czytasz, wszystko poszło zgodnie z planem!',
- ['9'] = 'Wszystko ok! Od teraz, każda akcja administracyjna w tej grupie będzie rejestrowana w %s - aby wybrać inne miejsce, napisz /logchat.'
- },
- ['lua'] = {
- ['1'] = 'Podaj proszę fragment kodu Lua do uruchomienia:'
- },
- ['lyrics'] = {
- ['1'] = 'Spotify',
- ['2'] = 'Pokaż tekst',
- ['3'] = 'Podaj tytuł piosenki/artystę/fragment tekstu.'
- },
- ['minecraft'] = {
- ['1'] = '<b>%s zmienił(a) nazwę użytkownika %s raz</b>',
- ['2'] = '<b>%s zmienił(a) nazwę użytkownika %s razy</b>',
- ['3'] = 'Poprzednia',
- ['4'] = 'Następna',
- ['5'] = 'Powrót',
- ['6'] = 'UUID',
- ['7'] = 'Avatar',
- ['8'] = 'Historia nazwy użytkownika',
- ['9'] = 'Wybierz:',
- ['10'] = 'Podaj nazwę użytkownika gracza Minecraft.',
- ['11'] = 'Nazwy użytkownika w Minecraft mają długość od 3 do 16 znaków.'
- },
- ['msglink'] = {
- ['1'] = 'Ta komenda może być używana tylko w supergrupach i kanałach.',
- ['2'] = 'Ta %s musi być publiczna, musi mieć @username.',
- ['3'] = 'Odpisz tą komendą na wiadomość aby otrzymać linka do wiadomości.'
- },
- ['mute'] = {
- ['1'] = 'Kogo mam wyciszyć? Podaj @username lub ID.',
- ['2'] = 'Nie mogę wyciszyć tego użytkownika, ponieważ został on wyciszony już wcześniej.',
- ['3'] = 'Nie mogę wyciszyć tego użytkownika, ponieważ jest to moderator lub administrator tej grupy.',
- ['4'] = 'Nie mogę wyciszyć tego użytkownika, ponieważ opuścił on tę grupę lub został z niej wyrzucony.',
- ['5'] = 'Potrzebuję uprawnień administratora aby móc wyciszać.'
- },
- ['myspotify'] = {
- ['1'] = 'Profil',
- ['2'] = 'Śledzący',
- ['3'] = 'Niedawno odtwarzane',
- ['4'] = 'Aktualnie odtwarzane',
- ['5'] = 'Najczęściej odtwarzane utwory',
- ['6'] = 'Top Artists', --!
- ['7'] = 'Wygląda na to, że nie śledzisz żadnych artystów!',
- ['8'] = 'Your Top Artists',
- ['9'] = 'Wygląda na to, że nie masz żadnych utworów w bibliotece!',
- ['10'] = 'Utwory najczęściej odtwarzane przez Ciebie',
- ['11'] = 'Wygląda na to, że nie śledzisz żadnych artystów!',
- ['12'] = 'Artyści których śledzisz',
- ['13'] = 'Nie odtwarzano ostatnie żadnych utworów!',
- ['14'] = '<b>Niedawno odtwarzane</b>\n%s %s\n%s %s\n%s Słuchano o %d:%d dnia %d/%d/%d.',
- ['15'] = 'Zaakceptowano żądanie, trwa przetwarzanie.',
- ['16'] = 'Wygląda na to, że niczego teraz nie słuchasz!',
- ['17'] = 'Aktualnie odtwarzane',
- ['18'] = 'Wystąpił błąd podczas ponownej autoryzacji Twojego konta Spotify!',
- ['19'] = 'Ponowna autoryzacja Twojego konta Spotify powiodła się! Przetwarzanie Twojego oryginalnego żądania...',
- ['20'] = 'Trwa ponowna autoryzacja Twojego konta Spotify, proszę czekać...',
- ['21'] = 'Potrzebujesz autoryzować Mattatę aby połączyć się ze swoim kontem Spotify. Kliknij [tutaj](https://accounts.spotify.com/en/authorize?client_id=%s&response_type=code&redirect_uri=%s&scope=user-library-read%%20playlist-read-private%%20playlist-read-collaborative%%20user-read-private%%20user-read-birthdate%%20user-read-email%%20user-follow-read%%20user-top-read%%20user-read-playback-state%%20user-read-recently-played%%20user-read-currently-playing) i kliknij zielony przycisk "OKAY" aby połączyć Mattatę do Twojego konta Spotify. Następnie wyślij link do którego Cię przekierowano (powinien się zaczynać od "%s", a następnie zawierać unikatowy kod) w odpowiedzi na tę wiadomość.',
- ['22'] = 'Listy odtwarzania',
- ['23'] = 'Użyj trybu inline',
- ['24'] = 'Tekst piosenki',
- ['25'] = 'Nie znaleziono żadnych urządzeń.',
- ['26'] = 'Wygląda na to, że nie masz żadnych list odtwarzania.',
- ['27'] = 'Twoje listy odtwarzania',
- ['28'] = '%s %s [%s utworów]',
- ['29'] = '%s %s [%s]\nSpotify %s user\n\n<b>Urządzenia:</b>\n%s', --!
- ['30'] = 'Włączam poprzedni utwor...',
- ['31'] = 'Nie masz konta premium!',
- ['32'] = 'Nie znaleziono żadnych urządzeń.',
- ['33'] = 'Włączam następny utwór...',
- ['34'] = 'Wznawiam odtwarzanie...',
- ['35'] = 'Twoje urządzenie jest tymczasowo niedostępne...',
- ['36'] = 'Nie znaleziono żadnych urządzeń!',
- ['37'] = 'Wstrzymuję odtwarzanie...',
- ['38'] = 'Trwa odtwarzanie',
- ['39'] = 'Losuję kolejność odtwarzania...',
- ['40'] = 'To nie jest poprawny poziom głośności. Podaj liczbę między 0 a 100.',
- ['41'] = 'Głośność została ustawiona na %s%%!',
- ['42'] = 'Ta wiadomość została wysłana przez wcześniejszą wersję pluginu, poproś o nową wysyłając /myspotify!'
- },
- ['name'] = {
- ['1'] = 'Aktualnie reaguję na imię "%s" - aby to zmienić, użyj /name <imię>.',
- ['2'] = 'Moje nowe imię musi mieć długość od 2 do 32 znaków!',
- ['3'] = 'Moje nowe imię musi się składać tylko z liter i cyfr!',
- ['4'] = 'Będę od teraz reagować na "%s", zamiast "%s" - aby to zmienić, użyj /name <imię>.'
- },
- ['netflix'] = {
- ['1'] = 'Czytaj więcej'
- },
- ['news'] = {
- ['1'] = '"<code>%s</code>" isn\'t a valid Lua pattern.', --!
- ['2'] = 'Nie mogę pobrać listy źródeł.',
- ['3'] = '<b>Źródła newsów pasujących do wzorca</b> "<code>%s</code>":\n\n%s',
- ['4'] = '<b>Aktualnie dostępne źródła newsów których możesz używać w </b> /news<b>. Użyj</b> /nsources &lt;Lua_pattern&gt; <b>aby przeszukać tę listę pod kątem bardziej specyficznych rezultatów.</b>\n\n%s',
- ['5'] = 'Nie masz preferowanego źródła newsów. Użyj /setnews <źródło> aby ustawić. Przejrzyj listę źródeł używając /nsources, lub zawęź wyniki używając /nsources <Lua_pattern>.',
- ['6'] = 'Twoje aktualne preferowane źródło newsów to %s. Użyj /setnews <źródło> aby to zmienić. Przejrzyj listę źródeł używając /nsources, lub zawęź wyniki używając /nsources <Lua_pattern>.',
- ['7'] = 'Twoje preferowane źródło informacji jest już ustawione na %s! Użyj /news aby zobaczyć aktualną najlepszą historię.',
- ['8'] = 'Nieznane źródło newsów. Przejrzyj listę źródeł używając /nsources, lub zawęź wyniki używając /nsources <Lua_pattern>.',
- ['9'] = 'Twoje preferowane źródło newsów zostało zmienione na %s! Użyj /news aby zobaczyć aktualną najlepszą historię.',
- ['10'] = 'Nieznane źródło newsów. Przejrzyj listę źródeł używając /nsources. Jeśli masz ulubione źródło, użyj /setnews <źródło> żeby pobierać zeń newsy kiedy użyjesz /news bez argumentów.',
- ['11'] = 'Czytaj więcej'
- },
- ['nick'] = {
- ['1'] = 'Twoja ksywka została zapomniana!',
- ['2'] = 'Twoja ksywka została ustawiona na "%s"!'
- },
- ['ninegag'] = {
- ['1'] = 'Czytaj więcej'
- },
- ['optout'] = {
- ['1'] = 'Pozwoliłeś na zbieranie danych które wysyłasz! Użyj /optout aby zrezygnować.',
- ['2'] = 'Zrezygnowałeś ze zbieranie danych które wysyłasz! Użyj /optin aby pozwolić na zbieranie danych.'
- },
- ['paste'] = {
- ['1'] = 'Wybierz serwis do którego mam wysłać Twój tekst:'
- },
- ['pay'] = {
- ['1'] = 'Masz aktualnie %s mattamonet. Zdobądź więcej wygrywając w kółko i krzyżyk, używając /game - wygrasz 100 mattamonet za każdą wygraną, i stracisz 50 za każdą przegraną.',
- ['2'] = 'Musisz użyć tej komendy w odpowiedzi do użytkownika któremu chcesz przelać mattamonety',
- ['3'] = 'Ile mettamonet chcesz przelać do %s?',
- ['4'] = 'Podana ilość musi być liczbą nieujemną.',
- ['5'] = 'Nie możesz przelać mattamonet do siebie!',
- ['6'] = 'Nie masz tylu mattamonet!',
- ['7'] = '%s mattamonet zostało przelanych do to %s. Masz teraz %s mattamonet.'
- },
- ['pokedex'] = {
- ['1'] = 'Nazwa: %s\nID: %s\nTyp: %s\nOpis: %s'
- },
- ['pin'] = {
- ['1'] = 'Nie utworzono wcześniej żadnej wiadomości do przypięcia. Użyj /pin <tekst> aby utworzyć. Użyj Markdown do formatowania.',
- ['2'] = 'Oto ostatnia wiadomość utworzona przez /pin.',
- ['3'] = 'Znaleziono wiadomość do przypięcia w bazie danych, ale wygląda na to że została ona usunięta z grupy. Utwórz nową używając /pin <tekst>. Użyj Markdown do formatowania.',
- ['4'] = 'Wystąpił błąd podczas aktualizowania wiadomości do przypięcia. Wprowadzony tekst mógł zawierać nieprawidłowy Markdown, bądź wiadomość do przypięcia została usunięta. Spróbuję wysłać nową wiadomość do przypięcia, znajdziesz ją poniżej - jeśli potrzebujesz ją zmodyfikować, po upewnieniu się że istnieje, użyj /pin <tekst>.',
- ['5'] = 'Tekst zawiera nieprawidłowy Markdown.',
- ['6'] = 'Kliknij tutaj aby zobaczyć zaktualizowaną przypiętą wiadomość.'
- },
- ['prime'] = {
- ['1'] = 'Podaj liczbę między 1 a 99999.',
- ['2'] = '%s jest liczbą piewszą!',
- ['3'] = '%s NIE jest liczbą pierwszą...'
- },
- ['promote'] = {
- ['1'] = 'Nie mogę awansować tego użytkownika na moderatora, ponieważ jest to moderator lub administrator tej grupy.',
- ['2'] = 'Nie mogę awansować tego użytkownika na moderatora, ponieważ opuścił on tę grupę.',
- ['3'] = 'Nie mogę awansować tego użytkownika na moderatora, ponieważ został on wyrzucony z tej grupy.'
- },
- ['quote'] = {
- ['1'] = 'Ten użytkownik zrezygnował ze zbierania danych na jego temat',
- ['2'] = 'Brak zapisanych cytatów użytkownika %s! Odpisz na wiadomość poleceniem /save aby zapisać.'
- },
- ['randomsite'] = {
- ['1'] = 'Wygeneruj inną'
- },
- ['randomword'] = {
- ['1'] = 'Wygeneruj inne',
- ['2'] = 'Twoje losowe słowo to <b>%s</b>!'
- },
- ['report'] = {
- ['1'] = 'Please reply to the message you would like to report to the group\'s administrators.',
- ['2'] = 'You can\'t report your own messages, are you just trying to be funny?',
- ['3'] = '<b>%s needs help in %s!</b>',
- ['4'] = 'Click here to view the reported message.',
- ['5'] = 'I\'ve successfully reported that message to %s admin(s)!'
- },
- ['save'] = {
- ['1'] = 'Ten użytkownik zrezygnował ze zbierania danych na jego temat',
- ['2'] = 'Wiadomość zapisana w bazie danych i dodana do listy możliwych odpowiedzi gdy /quote jest użyte w odpowiedzi do %s!'
- },
- ['sed'] = {
- ['1'] = '%s\n\n<i>%s nie miał(a) tego na myśli!</i>',
- ['2'] = '%s\n\n<i>%s przyznał(a) się do porażki.</i>',
- ['3'] = '%s\n\n<i>%s nie ma pewności czy się nie pomylił(a)...</i>',
- ['4'] = 'Odczep się, ja <i>nigdy</i> się nie mylę!',
- ['5'] = '"<code>%s</code>" isn\'t a valid Lua pattern.', --!
- ['6'] = 'Hey %s, %s seems to think you meant:\n<i>%s</i>',
- ['7'] = 'Tak',
- ['8'] = 'Nie',
- ['9'] = 'Nie wiem',
- ['10'] = 'Just edit your message, idiot.'
- },
- ['setgrouplang'] = {
- ['1'] = 'Język tej grupy został ustawiony na %s!',
- ['2'] = 'Aktualnu język tej grupy to %s.\nPamiętaj że tłumaczenie może nie być kompletne. Aby zmienić język, użyj klawiatury poniżej:',
- ['3'] = 'Wspólny język dla tej grupy jest wyłączony. Aby to zmienić, użyj przycisku poniżej lub menu /administration.',
- ['4'] = 'Włącz',
- ['5'] = 'Wyłącz'
- },
- ['setlang'] = {
- ['1'] = 'Twój język został ustawiony na %s!',
- ['2'] = 'Aktualnie wybrany język %s.\nPamiętaj że tłumaczenie może nie być kompletne. Jeśli chcesz zmienić język, użyj klawiatury poniżej:'
- },
- ['setlink'] = {
- ['1'] = 'To nie jest poprawny URL.',
- ['2'] = 'Link został ustawiony!'
- },
- ['setrules'] = {
- ['1'] = 'Niepoprawny Markdown.',
- ['2'] = 'Ustawienie zasad powiodło się!'
- },
- ['setwelcome'] = {
- ['1'] = 'Co chcesz powiedzieć każdemu nowemu członkowi? Możesz używać Markdown do formatowania. (Wiadomość powitalną można wyłączyć w menu administracyjnym, pisząc /administration). Użyj $user_id aby wstawić ID dołączającego użytkownika, $chat_id aby wstawić ID grupy, $name aby wstawić the imię użytkownika, $title aby wstawić nazwę grupy i $username aby wstawić @username użytkownika (jeśli użytkownik nie ma @username, zostanie wstawione jego imię, więc najlepiej nie używać $name i $username koło siebie).',
- ['2'] = 'Twoja wiadomość jest niepoprawnie sformatowana, sprawdź swój Markdown i spróbuj ponownie.',
- ['3'] = 'Zapisano wiadomość powitalną dla %s!'
- },
- ['share'] = {
- ['1'] = 'Udostępnij'
- },
- ['shorten'] = {
- ['1'] = 'Wybierz skracacz linków używając przycisków poniżej:'
- },
- ['shsh'] = {
- ['1'] = 'Nie mogę pobrać żadnych SHSH blobs dla tego ECID, upewnij się że jest poprawny i zapisałeś go używając https://tsssaver.1conan.com.',
- ['2'] = 'SHSH blobs dla tego urządzenia są dostępne dla następujących wersji iOS:\n',
- ['3'] = 'Pobierz .zip'
- },
- ['statistics'] = {
- ['1'] = 'W tej grupie nie wysłano jeszcze żadnej wiadomości!',
- ['2'] = '<b>Statystyki w:</b> %s\n\n%s\n<b>Liczba wszystkich wiadomości:</b> %s',
- ['3'] = 'Zresetowano statystyki w tej grupie!',
- ['4'] = 'Błąd podczas resetowania statystyk, może zostały one zresetowane już wcześniej?'
- },
- ['steam'] = {
- ['1'] = 'Twoja nazwa użytkownika na Steamie została ustawiona na "%s".',
- ['2'] = '"%s" nie jest poprawną nazwą użytkownika na Steamie.',
- ['3'] = '%s jest użytkownikiem Steama od %s, %s.\nData ostatniego wylogowania: %s, %s.\n<a href="%s">Profil na Steamie</a>',
- ['4'] = '%s, AKA "%s",'
- },
- ['synonym'] = {
- ['1'] = 'Możesz użyć słowa <b>%s</b> zamiast %s.'
- },
- ['thoughts'] = {
- ['1'] = '%s\n\nPozytywnie: <code>%s%% [%s]</code>\nNegatywnie: <code>%s%% [%s]</code>\nObojętnie: <code>%s%% [%s]</code>\nWszystkich przemyśleń: <code>%s</code>'
- },
- ['tobinary'] = {
- ['1'] = 'Podaj ciąg znaków który chcesz skonwertować do liczby binarnej.'
- },
- ['trust'] = {
- ['1'] = 'Nie mogę zaufać temu użytkownikowi, ponieważ jest to moderator lub administrator tej grupy.',
- ['2'] = 'Nie mogę zaufać temu użytkownikowi, ponieważ opuścił on tę grupę.',
- ['3'] = 'Nie mogę zaufać temu użytkownikowi, ponieważ został on wyrzucony już wcześniej.',
- },
- ['unmute'] = {
- ['1'] = 'Komu mam pozwolić mówić? Podaj @username lub ID.',
- ['2'] = 'Nie mogę pozwolić mówić temu użytkownikowi, ponieważ nie został on wyciszony.',
- ['3'] = 'Nie mogę pozwolić mówić temu użytkownikowi, ponieważ jest to moderator lub administrator tej grupy.',
- ['4'] = 'Nie mogę pozwolić mówić temu użytkownikowi, ponieważ opuścił on tę grupę lub został z niej wyrzucony.',
- },
- ['untrust'] = {
- ['1'] = 'Komu mam przestać ufać? Podaj @username lub ID.',
- ['2'] = 'Nie mogę przestać ufać temu użytkownikowi, ponieważ jest to moderator lub administrator tej grupy.',
- ['3'] = 'Nie mogę przestać ufać temu użytkownikowi, ponieważ opuścił on tę grupę.',
- ['4'] = 'Nie mogę przestać ufać temu użytkownikowi, ponieważ został on wyrzucony z tej grupy.',
- },
- ['upload'] = {
- ['1'] = 'Odpowiedz na plik który chcesz ściągnąć na serwer. Plik musi ważyć <= 20 MB.',
- ['2'] = 'Plik zbyt duży, limit to 20 MB.',
- ['3'] = 'Nie można pobrać pliku, prawdopodobnie jest zbyt stary.',
- ['4'] = 'Wystąpił błąd podczas pobierania pliku.',
- ['5'] = 'Pobrano plik na serwer, ścieżka: <code>%s</code>.'
- },
- ['version'] = {
- ['1'] = '@%s AKA %s `[%s]` działa pod kontrolą mattata %s, stworzona przez [Matthew Hesketh](https://t.me/wrxck). Kod źródłowy jest dostępny na [GitHubie](https://github.com/wrxck/mattata).'
- },
- ['voteban'] = {
- ['1'] = 'Dla kogo mam otworzyć głosowanie nad banem? Podaj @username lub ID.',
- ['2'] = 'Nie mogę otworzyć głosowania nad banem tego użytkownika, ponieważ jest to moderator lub administrator tej grupy.',
- ['3'] = 'Nie mogę otworzyć głosowania nad banem tego użytkownika, ponieważ opuścił on tę grupę lub został z niej wyrzucony.',
- ['4'] = 'Czy %s [%s] powinien zostać zbanowany z %s? %s głosów za jest wymaganych aby zbanować, a %s głosów przeciw jest wymaganych aby zamknąć to głosowanie bez banowania.',
- ['5'] = 'Tak [%s]',
- ['6'] = 'Nie [%s]',
- ['7'] = 'Grupa zdecydowała. %s [%s] został zbanowany z %s ponieważ %s ludzi tak zagłosowało.',
- ['8'] = 'Osiągnięto wymaganą liczba głosów za banem, jednakże nie mogę zbanować %s - może opuścił(a) on(a) groupę, lub otrzymał(a) nominację na moderatora w międzyczasie, albo ja nie mam już uprawnień administratora.',
- ['9'] = 'Grupa zdecydowała. Nie banuję %s [%s] z %s ponieważ wymaganych %s ludzi zagłosowało przeciwko banowi.',
- ['10'] = 'Głosowałeś za banem dla %s [%s]!',
- ['11'] = 'Głos został cofnięty, możesz zagłosować ponownie.',
- ['12'] = 'Zagłosowałeś przeciwko banowi dla %s [%s]!',
- ['13'] = 'A vote-ban has already been opened for this user!'
- },
- ['weather'] = {
- ['1'] = 'Nie masz ustawionej lokalizacji. Użyj /setloc <lokalizacja> aby ustawić.',
- ['2'] = 'Aktualna temperatura: %s (odczuwalna: %s) w %s. %s'
- },
- ['welcome'] = {
- ['1'] = 'Przeczytaj zasady'
- },
- ['allowlist'] = {
- ['1'] = 'Kogo mam przestać ignorować? Podaj @username lub ID.',
- ['2'] = 'Nie mogę przestać ignorować tego użytkownika, ponieważ jest to moderator lub administrator tej grupy.',
- ['3'] = 'Nie mogę przestać ignorować tego użytkownika, ponieważ opuścił on tę grupę.',
- ['4'] = 'Nie mogę przestać ignorować tego użytkownika, ponieważ został on zbanowany.',
- },
- ['wikipedia'] = {
- ['1'] = 'Czytaj więcej'
- },
- ['youtube'] = {
- ['1'] = 'Poprzedni',
- ['2'] = 'Następny',
- ['3'] = 'Strona %s z %s'
- }
-}
\ No newline at end of file
diff --git a/languages/pt_br.lua b/languages/pt_br.lua
deleted file mode 100644
index ba38931..0000000
--- a/languages/pt_br.lua
+++ /dev/null
@@ -1,735 +0,0 @@
--- This is a language file for mattata
--- Language: pt-br
--- Author: American_Jesus
-
--- DO NOT CHANGE ANYTHING THAT BEGINS OR ENDS WITH A %
--- THESE ARE PLACEHOLDERS!
-
--- DO NOT CHANGE ANY MARKDOWN/HTML FORMATTING!
--- IF YOU ARE UNSURE, ASK ON TELEGRAM (t.me/mattataDev)
-
-return {
- ['errors'] = {
- ['connection'] = 'Erro de conexão.',
- ['results'] = 'Eu não consegui encontrar nenhum resultado para isso.',
- ['supergroup'] = 'Este comando só pode ser usado em super grupos.',
- ['admin'] = 'Precisa ser moderador ou administrador neste grupo para usar este comando.',
- ['unknown'] = 'Eu não reconheço esse(s) utilizador(es). Se gostaria de me ensinar quem ele(s) são, encaminhe-me uma mensagem dele(s) para qualquer conversa que eu estou.',
- ['generic'] = 'Ocorreu um erro!',
- ['use'] = 'Você não tem permissão para usar isso!',
- ['private'] = 'You can only use this command in private chat!'
- },
- ['addcommand'] = {
- ['1'] = 'Please specify the command in the format <code>/command - description</code>',
- ['2'] = 'I couldn\'t retrieve my commands!',
- ['3'] = 'The command description can\'t be longer than 256 characters!',
- ['4'] = 'An unknown error occurred! I couldn\'t add your command!',
- ['5'] = 'Success! Command added.'
- },
- ['addrule'] = {
- ['1'] = 'Please specify the rule you would like to add!',
- ['2'] = 'You don\'t have any rules to add to! Please set group rules using /setrules!',
- ['3'] = 'I couldn\'t add that rule, as it would make the length of the rules longer than Telegram\'s 4096 character limit!',
- ['4'] = 'I couldn\'t add that rule, it appears it contains invalid Markdown formatting!',
- ['5'] = 'Successfully updated the rules!'
- },
- ['addslap'] = {
- ['1'] = 'You can only use this command in groups!',
- ['2'] = 'The slap cannot contain curly braces apart from placeholders!',
- ['3'] = 'The slap cannot be any longer than 256 characters in length!',
- ['4'] = 'I\'ve successfully added that slap as a possibility for /slap in this group!',
- ['5'] = 'You must include placeholders in your slap. Use {ME} for the person executing and {THEM} for the victim.'
- },
- ['administration'] = {
- ['1'] = 'Enable Administration',
- ['2'] = 'Disable Administration',
- ['3'] = 'Anti-Spam Settings',
- ['4'] = 'Warning Settings',
- ['5'] = 'Vote-Ban Settings',
- ['6'] = 'Welcome New Users?',
- ['7'] = 'Send Rules On Join?',
- ['8'] = 'Send Rules In Group?',
- ['9'] = 'Back',
- ['10'] = 'Next',
- ['11'] = 'Word Filter',
- ['12'] = 'Anti-Bot',
- ['13'] = 'Anti-Link',
- ['14'] = 'Log Actions?',
- ['15'] = 'Anti-RTL',
- ['16'] = 'Anti-Spam Action',
- ['17'] = 'Ban',
- ['18'] = 'Kick',
- ['19'] = 'Delete Commands?',
- ['20'] = 'Force Group Language?',
- ['21'] = 'Send Settings In Group?',
- ['22'] = 'Delete Reply On Action?',
- ['23'] = 'Require Captcha?',
- ['24'] = 'Use Inline Captcha?',
- ['25'] = 'Ban SpamWatch-flagged users?',
- ['26'] = 'Number of warnings until %s:',
- ['27'] = 'Upvotes needed to ban:',
- ['28'] = 'Downvotes needed to dismiss:',
- ['29'] = 'Deleted %s, and its matching link from the database!',
- ['30'] = 'There were no entries found in the database matching "%s"!',
- ['31'] = 'You\'re not an administrator in that chat!',
- ['32'] = 'The minimum number of upvotes required for a vote-ban is %s.',
- ['33'] = 'The maximum number of upvotes required for a vote-ban is %s.',
- ['34'] = 'The minimum number of downvotes required for a vote-ban is %s.',
- ['35'] = 'The maximum number of downvotes required for a vote-ban is %s.',
- ['36'] = 'The maximum number of warnings is %s.',
- ['37'] = 'The minimum number of warnings is %s.',
- ['38'] = 'You can add one or more words to the word filter by using /filter <word(s)>',
- ['39'] = 'You will no longer be reminded that the administration plugin is disabled. To enable it, use /administration.',
- ['40'] = 'That\'s not a valid chat!',
- ['41'] = 'You don\'t appear to be an administrator in that chat!',
- ['42'] = 'My administrative functionality can only be used in groups/channels! If you\'re looking for help with using my administrative functionality, check out the "Administration" section of /help! Alternatively, if you wish to manage the settings for a group you administrate, you can do so here by using the syntax /administration <chat>.',
- ['43'] = 'Use the keyboard below to adjust the administration settings for <b>%s</b>:',
- ['44'] = 'Please send me a [private message](https://t.me/%s), so that I can send you this information.',
- ['45'] = 'I have sent you the information you requested via private chat.',
- ['46'] = 'Remove Channel Pins?',
- ['47'] = 'Remove Other Pins?',
- ['48'] = 'Remove Pasted Code?',
- ['49'] = 'Prevent Inline Bots?',
- ['50'] = 'Kick Media On Join?',
- ['51'] = 'Enable Plugins For Admins?',
- ['52'] = 'Kick URLs On Join?'
- },
- ['afk'] = {
- ['1'] = 'Desculpe, receio que este elemento esteja disponível somente para utilizadores com um @utilizador público!',
- ['2'] = '%s voltou depois de estar AFK por %s!',
- ['3'] = 'Nota',
- ['4'] = '%s está agora AFK.%s'
- },
- ['antispam'] = {
- ['1'] = 'Desabilitar',
- ['2'] = 'Habilitar',
- ['3'] = 'Desabilitar limite',
- ['4'] = 'Habilitar limite para %s',
- ['5'] = 'Todas as Configurações de Administração',
- ['6'] = '%s [%s] has kicked %s [%s] from %s [%s] for hitting the configured anti-spam limit for [%s] media.',
- ['7'] = 'Kicked %s for hitting the configured antispam limit for [%s] media.',
- ['8'] = 'The maximum limit is 100.',
- ['9'] = 'The minimum limit is 1.',
- ['10'] = 'Modificar as configurações de anti-spam para %s abaixo:',
- ['11'] = 'Hey %s, if you\'re going to send code that is longer than %s characters in length, please do so using /paste in <a href="https://t.me/%s">private chat with me</a>!',
- ['12'] = '%s <code>[%s]</code> has %s %s <code>[%s]</code> from %s <code>[%s]</code> for sending Telegram invite link(s).\n#chat%s #user%s',
- ['13'] = '%s %s for sending Telegram invite link(s).',
- ['14'] = 'Hey, I noticed you\'ve got anti-link enabled and you\'re currently not allowing your users to mention a chat you\'ve just mentioned, if you\'d like to allowlist it, use /allowlink <links>.',
- ['15'] = 'Kicked %s <code>[%s]</code> from %s <code>[%s]</code> for sending media within their first few messages.\n#chat%s #user%s',
- ['16'] = 'Kicked %s <code>[%s]</code> from %s <code>[%s]</code> for sending a URL within their first few messages.\n#chat%s #user%s',
- ['17'] = 'Action',
- ['18'] = 'Kick',
- ['19'] = 'Ban',
- ['20'] = 'Mute'
- },
- ['appstore'] = {
- ['1'] = 'Ver no iTunes',
- ['2'] = 'rating',
- ['3'] = 'ratings'
- },
- ['authspotify'] = {
- ['1'] = 'You are already authorised using that account.',
- ['2'] = 'Authorising, please wait...',
- ['3'] = 'A connection error occured. Are you sure you replied with the correct link? It should look like',
- ['4'] = 'Successfully authorised your Spotify account!'
- },
- ['avatar'] = {
- ['1'] = 'Não consegui obter fotos de perfil para esse utilizador, verifique se especificou um nome de utilizador ou ID numérico válido.',
- ['2'] = 'Esse utilizador não tem fotos de perfil.',
- ['3'] = 'Esse utilizador não tem assim tantas de perfil!',
- ['4'] = 'That user has opted-out of data-collecting functionality, therefore I am not able to show you any of their profile photos.',
- ['5'] = 'User: %s\nPhoto: %s/%s\nSend /avatar %s [offset] to @%s to view a specific photo of this user',
- ['6'] = 'User: %s\nPhoto: %s/%s\nUse /avatar %s [offset] to view a specific photo of this user'
- },
- ['ban'] = {
- ['1'] = 'Qual utilizador gostaria que eu bane? Pode especificar esse utilizador pelo seu @username ou ID numérico.',
- ['2'] = 'Não consigo banir esse utilizador porque ele é um moderador ou um administrador neste grupo.',
- ['3'] = 'Não consigo banir este utilizador porque ele saiu deste grupo.',
- ['4'] = 'Não consigo banir este utilizador porque ele já foi banido deste grupo.',
- ['5'] = 'Eu preciso ter permissões administrativas para banir esse utilizador. Corrija este problema e tente novamente.',
- ['6'] = '%s <code>[%s]</code> has banned %s <code>[%s]</code> from %s <code>[%s]</code>%s.\n%s %s',
- ['7'] = '%s has banned %s%s.'
- },
- ['bash'] = {
- ['1'] = 'Especifique um comando para executar!',
- ['2'] = 'Sucesso!'
- },
- ['blocklist'] = {
- ['1'] = 'Qual utilizador gostaria de adicionar a lista negra? Pode especificar este utilizador pelo seu @username ou ID numérico.',
- ['2'] = 'Não consigo adicionar a lista negra esse utilizador porque ele é um moderador ou um administrador neste grupo.',
- ['3'] = 'Não consigo adicionar a lista negra esse utilizador porque ele já deixou este grupo.',
- ['4'] = 'Não consigo adicionar a lista negra esse utilizador porque ele já foi banido neste grupo.',
- ['5'] = '%s <code>[%s]</code> has blocklisted %s <code>[%s]</code> from using %s <code>[%s]</code> in %s <code>[%s]</code>%s.\n%s %s',
- ['6'] = '%s has blocklisted %s from using %s%s.'
- },
- ['blocklistchat'] = {
- ['1'] = '%s foi adicionado a lista negra, e vou deixar lá quem eu adicionar!',
- ['2'] = '%s é um utilizador, este comando é apenas para lista negras em conversas como grupos e canais!',
- ['3'] = '%s não parece ser uma conversa valida!'
- },
- ['bugreport'] = {
- ['1'] = 'Sucesso! Seu relatório de bug foi enviado. O ID deste relatório é #%s.',
- ['2'] = 'Ocorreu um problema enquanto relatava esse bug! Ah, a ironia!'
- },
- ['calc'] = {
- ['1'] = 'Clique para enviar o resultado.',
- ['2'] = '"%s" was an unexpected word!',
- ['3'] = 'You cannot have a unit before a number!'
- },
- ['captionbotai'] = {
- ['1'] = 'Eu realmente não posso descrever essa imagem!'
- },
- ['cats'] = {
- ['1'] = 'Meow!'
- },
- ['channel'] = {
- ['1'] = 'Não tem permissão para usar isso!',
- ['2'] = 'Parece já não ser um administrador nesse grupo!',
- ['3'] = 'Não consegui enviar a sua mensagem, tem certeza de que ainda tenho permissão para enviar mensagens nesse grupo?',
- ['4'] = 'A sua mensagem foi enviada!',
- ['5'] = 'Não consegui recuperar uma lista de administradores para desse grupo!',
- ['6'] = 'Não parece ser um administrador desse grupo!',
- ['7'] = 'Especifique a mensagem a enviar, utilizando a sintaxe /channel <canal> <mensagem>.',
- ['8'] = 'Tem certeza de que deseja enviar esta mensagem? É assim que vai aparecer:',
- ['9'] = 'Sim, tenho a certeza!',
- ['10'] = 'Essa mensagem contém formatação Markdown inválida! Corrija a sintaxe e tente novamente.'
- },
- ['chatroulette'] = {
- ['1'] = 'Hey! Please don\'t send messages longer than %s characters. We don\'t want to annoy the other user!',
- ['2'] = '*Anonymous said:*\n```\n%s\n```\nTo end your session, send /endchat.',
- ['3'] = 'I\'m afraid I lost connection from the other user! To begin a new chat, please send /chatroulette!',
- ['4'] = 'The other person you were chatting with has ended the session. To start a new one, send /chatroulette.',
- ['5'] = 'Successfully ended your session. To start a new one, send /chatroulette.',
- ['6'] = 'I have successfully removed you from the list of available users.',
- ['7'] = 'You don\'t have a session set up at the moment. To start one, send /chatroulette.',
- ['8'] = 'Finding you a session, please wait...',
- ['9'] = 'I\'m afraid there aren\'t any available users right now, but I have added you to the list of available users! To stop this completely, please send /endchat.',
- ['10'] = 'I have successfully paired you with another user to chat to! Please remember to be kind to them! To end the chat, send /endchat.',
- ['11'] = 'I\'m afraid the user who I tried to pair you with has since blocked me. Please try and send /chatroulette again to try and connect to me!',
- ['12'] = 'I have successfully paired you with another user to chat to! Please remember to be kind to them! To end the chat, send /endchat.'
- },
- ['commandstats'] = {
- ['1'] = 'Nenhum comando foi enviado neste chat!',
- ['2'] = '<b>Estatísticas de comandos para:</b> %s\n\n%s\n<b>Total de comandos enviados:</b> %s',
- ['3'] = 'As estatísticas de comandos para este chat foram resetadas!',
- ['4'] = 'Não consegui resetar as estatísticas de comandos para este chat. Talvez eu já as tenha resetado?'
- },
- ['control'] = {
- ['1'] = 'Pfft, querias!',
- ['2'] = '%s está recarregando...'
- },
- ['copypasta'] = {
- ['1'] = 'O texto respondido não deverá exceder %s caracteres!'
- },
- ['coronavirus'] = {
- ['1'] = [[*COVID-19 Statistics for:* %s
-
-*New confirmed cases:* %s
-*Total confirmed cases:* %s
-*New deaths:* %s
-*Total deaths:* %s
-*New recovered cases:* %s
-*Total recovered cases:* %s]]
- },
- ['counter'] = {
- ['1'] = 'Eu não pude adicionar um contador a essa mensagem!'
- },
- ['custom'] = {
- ['1'] = 'Sucesso! Essa mensagem será enviada toda vez que alguém usar %s!',
- ['2'] = 'O trigger "%s" não existe!',
- ['3'] = 'O trigger "%s" foi apagado!',
- ['4'] = 'Ainda não tem triggers personalizado definidos!',
- ['5'] = 'Comandos personalizados para %s:\n',
- ['6'] = 'Para criar um novo comando personalizado, use a seguinte sintaxe:\n/custom new #trigger <valor>. Para listar todos os triggers atuais, use /custom list. Para apagar um trigger, use /custom del #trigger.'
- },
- ['delete'] = {
- ['1'] = 'Não consegui apagar essa mensagem. Talvez a mensagem seja muito antiga ou inexistente?'
- },
- ['demote'] = {
- ['1'] = 'Qual utilizador gostaria que eu despromovesse? Pode especificar este utilizador pelo seu @username ou ID numérico.',
- ['2'] = 'Eu não posso despromover esse utilizador porque ele não é um moderador ou um administrador neste grupo.',
- ['3'] = 'Eu não posso despromover esse utilizador porque ele já deixou este grupo.',
- ['4'] = 'Não consigo despromover esse utilizador porque ele já foi expulso deste grupo.'
- },
- ['doge'] = {
- ['1'] = 'Por favor, escreva o texto que deseja para Doge-ify. Cada sentença deve ser separada usando barras (/) ou novas linhas.'
- },
- ['donate'] = {
- ['1'] = '<b>Hello, %s!</b>\n\nIf you\'re feeling generous, you can contribute to the mattata project by making a monetary donation of any amount. This will go towards server costs and any time and resources used to develop mattata. This is an optional act, however it is greatly appreciated and your name will also be listed publically on mattata\'s GitHub page.\n\nIf you\'re still interested, you can donate <a href="https://paypal.me/wrxck">here</a>. Thank you for your continued support!'
- },
- ['exec'] = {
- ['1'] = 'Selecione a linguagem em que gostaria de executar o seu código:',
- ['2'] = 'Ocorreu um erro! Tempo de ligação expirou. Está tentando me engasgar?',
- ['3'] = 'Selecionou "%s" – tem a certeza?',
- ['4'] = 'Voltar',
- ['5'] = 'Tenho certeza',
- ['6'] = 'Introduza um fragmento de código que pretende executar. Não precisa especificar a linguagem, faremos isso depois!',
- ['7'] = 'Selecione a linguagem em que gostaria de executar o seu código:'
- },
- ['facebook'] = {
- ['1'] = 'Ocorreu um erro!',
- ['2'] = 'Escreva o nome de utilizador do Facebook do qual gostaria de obter a foto do perfil.',
- ['3'] = 'Visitas @%s no Facebook'
- },
- ['fact'] = {
- ['1'] = 'Gerar Outro'
- },
- ['fban'] = {
- ['1'] = 'Which user would you like me to Fed-ban? You can specify this user by their @username or numerical ID.',
- ['2'] = 'I cannot Fed-ban this user because they are a moderator or an administrator in this chat.'
- },
- ['flickr'] = {
- ['1'] = 'Pesquisou por:',
- ['2'] = 'Introduza uma consulta de pesquisa (Ou seja, o que quer que eu procure no Flickr, i.e. "Big Ben" mostrara uma fotografia do Big Ben em Londres).',
- ['3'] = 'Mais Resultados'
- },
- ['game'] = {
- ['1'] = 'Total de vitórias: %s\nTotal de derrotas: %s\nBalanço: %s mattacoins',
- ['2'] = 'Entrar no Jogo',
- ['3'] = 'Este jogo já acabou!',
- ['4'] = 'Não é a sua vez!',
- ['5'] = 'Não faz parte deste jogo!',
- ['6'] = 'Não pode ser ai!',
- ['7'] = 'Já faz parte deste jogo!',
- ['8'] = 'Este jogo já começou!',
- ['9'] = '%s [%s] está a jogar contra %s [%s]\nE é a vez de %s\'s a jogar!',
- ['10'] = '%s ganhou o jogo contra %s!',
- ['11'] = '%s criou um jogo contra %s!',
- ['12'] = 'A espera pelo oponente...',
- ['13'] = 'Jogo do Galo',
- ['14'] = 'Clique para enviar o jogo para o seu grupo!',
- ['15'] = 'Estatísticas %s:\n',
- ['16'] = 'Jogar ao Jogo do Galo!'
- },
- ['gblocklist'] = {
- ['1'] = 'Responda ao utilizador que deseja incluir na lista negra global ou especifique-o por nome de utilizador/ID.',
- ['2'] = 'Não conseguir obter informações sobre "%s", verifique se é um nome de utilizador/ID válido e tente novamente.',
- ['3'] = 'Isso é um %s, não um utilizador!'
- },
- ['gif'] = {
- ['1'] = 'Introduza uma consulta de pesquisa (Que é, o que quer que eu procure no GIPHY, ex: "cat" irá mostrar um GIF de um gato).'
- },
- ['gallowlist'] = {
- ['1'] = 'Responda ao utilizador que deseja incluir na lista branca global ou especifique-o por nome de utilizador/ID.',
- ['2'] = 'Não conseguir obter informações sobre "%s", verifique se é um nome de utilizador/ID válido e tente novamente.',
- ['3'] = 'Isso é um %s, não um utilizador!'
- },
- ['hackernews'] = {
- ['1'] = 'Histórias principais de Hacker News:'
- },
- ['help'] = {
- ['1'] = 'Nenhum resultado encontrado!',
- ['2'] = 'Não foram encontrados elementos que correspondam a "%s", Por favor, tente ser mais específico!',
- ['3'] = '\n\nArgumentos: <requer> [opcional]\n\nProcurar um elemento ou obter ajuda com um comando usando minha funcionalidade de pesquisa inline - apenas me mencione em qualquer grupo usando a sintaxe @%s <texto de procura>.',
- ['4'] = 'Anterior',
- ['5'] = 'Seguinte',
- ['6'] = 'Voltar',
- ['7'] = 'Procurar',
- ['8'] = 'Está na pagina %s de %s!',
- ['9'] = [[
-Posso executar muitas ações administrativas nos seus grupos, basta adicionar-me como administrador e envie /administration para ajustar as configurações do seu grupo.
-Aqui estão alguns comandos administrativos e um breve comentário sobre o que eles fazem:
-
-• /pin <texto> - Envie uma mensagem formatada em Markdown que pode ser editada usando o mesmo comando com texto diferente, para evitar de ter que afixar novamente uma mensagem se não poder edita-la (o que acontece se a mensagem tiver mais de 48 horas)
-
-• /ban - Banir um utilizador respondendo a uma de suas mensagens ou especificando com o nome de utilizador/ID
-
-• /kick - Expulsar (banir e depois remover ban) um utilizador respondendo a uma de suas mensagens ou especificando com o nome de utilizador/ID
-
-• /unban - Remover ban a um utilizador respondendo a uma de suas mensagens ou especificando com o nome de utilizador/ID
-
-• /setrules <texto> - Defina o texto formatado como Markdown como as regras de grupo, que serão enviadas sempre que alguém usar /rules
- ]],
- ['10'] = [[
-• /setwelcome - Defina o texto formatado como Markdown como uma mensagem de boas-vindas que será enviada sempre que um utilizador se juntar ao seu grupo (A mensagem de boas-vindas pode ser desativada no menu de administração, acessível via /administration). Pode usar espaços reservados para personalizar automaticamente a mensagem de boas-vindas para cada utilizador. Use $user_id para inserir o ID numérico do utilizador, $chat_id para inserir o ID numérico do grupo, $name para inserir o nome do utilizador, $title para inserir o título do grupo e $username para inserir o nome de utilizador do utilizador (Se o utilizador não tiver um @utilizador, o seu nome será usado em vez disso, para evitar é melhor usar isso com $name)
-
-• /warn - Avisa um utilizador, e bane-o quando atingirem o número máximo de avisos
-
-• /mod - Promove um utilizador respondendo a, dando acesso a comandos administrativos como /ban, /kick, /warn etc. (isto é útil quando não quer que alguém tenha a capacidade de apagar mensagens!)
-
-• /demod - Despromove um utilizador respondendo a, removendo do seu estatuto de moderação e revogando sua capacidade de usar comandos administrativos
-
-• /staff - Mostrar o criador, administradores e moderadores do grupo numa lista bem formatada
- ]],
- ['11'] = [[
-• /report - Encaminha a mensagem de resposta para todos os administradores e os alerta da situação atual
-
-• /setlink <URL> - Define o endereço do grupo para o URL fornecido, que será enviado sempre que alguém usar /link
-
-• /links <texto> - Listas brancas todos os endereços Telegram encontrados no texto fornecido (inclui endereços de @utilizador)
- ]],
- ['12'] = 'Abaixo estão alguns links que pode achar úteis:',
- ['13'] = 'Desenvolvimento',
- ['14'] = 'Canal',
- ['15'] = 'Suporte',
- ['16'] = 'FAQ',
- ['17'] = 'Código Fonte',
- ['18'] = 'Doar',
- ['19'] = 'Rate',
- ['20'] = 'Registo de Administração',
- ['21'] = 'Definições de administrador',
- ['22'] = 'Plugins',
- ['23'] = [[
-<b>Olá %s! O meu nome é %s, é um prazer conhece-lo</b> %s
-
-Eu entendo muitos comandos, que você pode aprender mais sobre pressionando o botão "Comandos" usando o teclado acoplado.
-
-%s <b>Dica:</b> Use o botão "Definições" para alterar o modo como eu trabalho%s!
-
-%s <b>Find me useful, or just want to help?</b> Donations are very much appreciated, use /donate for more information!
- ]],
- ['24'] = 'em'
- },
- ['id'] = {
- ['1'] = 'Desculpe, mas eu não reconheço esse utilizador. Ensine-me quem ele é, encaminhando uma mensagem dele a mim ou faça com que ele me enviem uma mensagem.',
- ['2'] = 'Grupo consultado:',
- ['3'] = 'Este grupo:',
- ['4'] = 'Clique para enviar o resultado!'
- },
- ['imdb'] = {
- ['1'] = 'Anterior',
- ['2'] = 'Seguinte',
- ['3'] = 'Está na pagina %s de %s!'
- },
- ['import'] = {
- ['1'] = 'Eu não reconheço esse grupo!',
- ['2'] = 'Isso não é um super grupo, portanto não consigo importar nenhuma configuração dele!',
- ['3'] = 'Configurações administrativas importadas e plugins alternados com sucesso de %s para %s!'
- },
- ['info'] = {
- ['1'] = [[
-```
-Redis:
-%s Ficheiro de Configuração: %s
-%s Modo: %s
-%s Porta TCP: %s
-%s Versão: %s
-%s Tempo de atividade: %s days
-%s ID do Processo: %s
-%s Keys Expiradas: %s
-
-%s Contagem de Utilizadores: %s
-%s Contagem de Grupos: %s
-
-Sistema:
-%s OS: %s
-```
- ]]
- },
- ['instagram'] = {
- ['1'] = '@%s no Instagram'
- },
- ['ipsw'] = {
- ['1'] = '<b>%s</b> iOS %s\n\n<code>MD5 sum: %s\nSHA1 sum: %s\nTamanho do ficheiro: %s GB</code>\n\n<i>%s %s</i>',
- ['2'] = 'Este firmware não está mais sendo assinado!',
- ['3'] = 'Este firmware ainda está sendo assinado!',
- ['4'] = 'Selecione o seu modelo:',
- ['5'] = 'Selecione a versão do firmware:',
- ['6'] = 'Selecione seu tipo de dispositivo:',
- ['7'] = 'iPod Touch',
- ['8'] = 'iPhone',
- ['9'] = 'iPad',
- ['10'] = 'Apple TV'
- },
- ['ispwned'] = {
- ['1'] = 'Essa conta foi encontrada nos seguintes fugas de informação:'
- },
- ['itunes'] = {
- ['1'] = 'Nome:',
- ['2'] = 'Artista:',
- ['3'] = 'Álbum:',
- ['4'] = 'Faixa:',
- ['5'] = 'Disco:',
- ['6'] = 'A consulta original não pôde ser encontrada, provavelmente apagou a mensagem original.',
- ['7'] = 'A capa pode ser encontrada abaixo:',
- ['8'] = 'Introduza uma consulta de pesquisa (Ou seja, o que quer que eu procure no iTunes, Ex: "Green Day American Idiot" ira mostrar informações sobre o primeiro resultado para American Idiot dos Green Day).',
- ['9'] = 'Obter Capa do Álbum'
- },
- ['kick'] = {
- ['1'] = 'Qual utilizador gostaria que eu expulsasse? Pode especificar este utilizador por seu @utilizador ou ID numérico.',
- ['2'] = 'Eu não consigo expulsar esse utilizador porque ele é um moderador ou administrador neste grupo.',
- ['3'] = 'Eu não consigo expulsar esse utilizador porque ele já deixou este grupo.',
- ['4'] = 'Não consigo expulsar esse utilizador porque ele já foi expulso deste grupo.',
- ['5'] = 'Eu preciso ter permissões administrativas para expulsar esse utilizador. Corrija este problema e tente novamente.'
- },
- ['lastfm'] = {
- ['1'] = '%s\'s utilizador de last.fm foi definido para "%s".',
- ['2'] = 'O seu utilizador last.fm foi esquecido!',
- ['3'] = 'Não tem atualmente um utilizado do last.fm definido!',
- ['4'] = 'Especifique o utilizador do last.fm ou defina com /fmset.',
- ['5'] = 'Nenhum histórico foi encontrado para este utilizador.',
- ['6'] = '%s está atualmente a ouvir:\n',
- ['7'] = '%s ouviu ultimamente:\n',
- ['8'] = 'Desconhecido',
- ['9'] = 'Clique para enviar o resultado.'
- },
- ['location'] = {
- ['1'] = 'Não tem uma localização definida. O que nova localização gostaria que fosse?'
- },
- ['logchat'] = {
- ['1'] = 'Escreva o nome de utilizador ou ID numérico do grupo no qual deseja registar todas as ações administrativas.',
- ['2'] = 'A verificar se o grupo é válido...',
- ['3'] = 'Desculpe, parece que especificou um grupo inválido, ou especificou um grupo que eu ainda não adicionado. Corrija e tente novamente.',
- ['4'] = 'Não pode definir um utilizador como o seu grupo de registo!',
- ['5'] = 'Não parece ser administrador nesse grupo!',
- ['6'] = 'Parece que eu já estou registar ações administrativas nesse grupo! Use /logchat para especificar um novo.',
- ['7'] = 'Esse grupo é válido, vou tentar e enviar uma mensagem de teste para ele, apenas para garantir que tenho permissão para falar!',
- ['8'] = 'Olá mundo - esta é uma mensagem de teste para verificar minhas permissões de escrita - se estiver a ler isto, então tudo correu bem!',
- ['9'] = 'Tudo feito! De agora em diante, Quaisquer ações administrativas neste grupo serão registadas em %s - para mudar o grupo que quer que eu registe ações administrativas, basta enviar /logchat.'
- },
- ['lua'] = {
- ['1'] = 'Digite uma string de Lua para executar!'
- },
- ['lyrics'] = {
- ['1'] = 'Spotify',
- ['2'] = 'Mostrar letra',
- ['3'] = 'Introduza uma consulta de pesquisa (isto é, que musica/artista/letra quer que eu obtenha letras, Ex: "Green Day Basket Case" irá mostrar a letra para Basket Case dos Green Day).'
- },
- ['minecraft'] = {
- ['1'] = '<b>%s mudou o seu utilizador %s vez</b>',
- ['2'] = '<b>%s mudou o seu utilizador %s vezes</b>',
- ['3'] = 'Anterior',
- ['4'] = 'Seguinte',
- ['5'] = 'Voltar',
- ['6'] = 'UUID',
- ['7'] = 'Avatar',
- ['8'] = 'Histórico de Utilizador',
- ['9'] = 'Selecione uma opção:',
- ['10'] = 'Escreva o nome de utilizador do jogador do Minecraft que gostaria de ver informações (Ex: enviando "Notch" irá ver as informações sobre o jogador Notch).',
- ['11'] = 'Os nomes de utilizadores do Minecraft têm entre 3 e 16 caracteres.'
- },
- ['mute'] = {
- ['1'] = 'Que utilizador gostaria que ficasse silenciar? Pode especificar este utilizador pelo seu @utilizador ou ID numérico.',
- ['2'] = 'Não consigo silenciar este utilizador porque já estão silenciados neste grupo.',
- ['3'] = 'Não consigo silenciar este utilizador porque ele é um moderador ou administrador neste grupo.',
- ['4'] = 'Não consigo silenciar este utilizador porque ele já deixou (ou foi expulso) deste grupo.',
- ['5'] = 'Eu preciso ter permissões administrativas para silenciar este utilizador. Corrija este problema e tente novamente.'
- },
- ['myspotify'] = {
- ['1'] = 'Perfil',
- ['2'] = 'Seguindo',
- ['3'] = 'Recently Played',
- ['4'] = 'Currently Playing',
- ['5'] = 'Top Tracks',
- ['6'] = 'Top Artistas',
- ['7'] = 'You don\'t appear to be following any artists!',
- ['8'] = 'Seus Top Artistas',
- ['9'] = 'You don\'t appear to have any tracks in your library!',
- ['10'] = 'Your Top Tracks',
- ['11'] = 'You don\'t appear to be following any artists!',
- ['12'] = 'Artists You Follow',
- ['13'] = 'You don\'t appear to have recently played any tracks!',
- ['14'] = '<b>Recently Played</b>\n%s %s\n%s %s\n%s Listened to at %s:%s on %s/%s/%s.',
- ['15'] = 'The request has been accepted for processing, but the processing has not been completed.',
- ['16'] = 'You don\'t appear to be listening to anything right now!',
- ['17'] = 'Currently Playing',
- ['18'] = 'An error occured whilst re-authorising your Spotify account!',
- ['19'] = 'Successfully re-authorised your Spotify account! Processing your original request...',
- ['20'] = 'Re-authorising your Spotify account, please wait...',
- ['21'] = 'You need to authorise mattata in order to connect your Spotify account. Click [here](https://accounts.spotify.com/en/authorize?client_id=%s&response_type=code&redirect_uri=%s&scope=user-library-read,playlist-read-private,playlist-read-collaborative,user-read-private,user-read-email,user-follow-read,user-top-read,user-read-playback-state,user-read-recently-played,user-read-currently-playing,user-modify-playback-state) and press the green "OKAY" button to link mattata to your Spotify account. After you\'ve done that, send the link you were redirected to (it should begin with "%s", followed by a unique code) in reply to this message.',
- ['22'] = 'Playlists',
- ['23'] = 'Use Inline Mode',
- ['24'] = 'Lyrics',
- ['25'] = 'No devices were found.',
- ['26'] = 'You don\'t appear to have any playlists.',
- ['27'] = 'Your Playlists',
- ['28'] = '%s %s [%s tracks]',
- ['29'] = '%s %s [%s]\nSpotify %s user\n\n<b>Devices:</b>\n%s',
- ['30'] = 'Playing previous track...',
- ['31'] = 'You are not a premium user!',
- ['32'] = 'I could not find any devices.',
- ['33'] = 'Playing next track...',
- ['34'] = 'Resuming track...',
- ['35'] = 'Your device is temporarily unavailable...',
- ['36'] = 'No devices were found!',
- ['37'] = 'Pausing track...',
- ['38'] = 'Now playing',
- ['39'] = 'Shuffling your music...',
- ['40'] = 'That\'s not a valid volume. Please specify a number between 0 and 100.',
- ['41'] = 'The volume has been set to %s%%!',
- ['42'] = 'This message is using an old version of this plugin, please request a new one by sending /myspotify!'
- },
- ['name'] = {
- ['1'] = 'O nome pelo qual respondo atualmente é "%s" - para alterar isso, use /name <texto> (onde <texto> é o nome pelo qual quer que eu responda).',
- ['2'] = 'Meu novo nome precisa ter entre 2 e 32 caracteres!',
- ['3'] = 'Meu nome só pode conter caracteres alfanuméricos!',
- ['4'] = 'Vou agora responder a "%s", em vez de "%s" - para alterar isso, use /name <texto> (onde <text> o nome a qual quer que eu responda).'
- },
- ['netflix'] = {
- ['1'] = 'Ver mais.'
- },
- ['news'] = {
- ['1'] = '"<code>%s</code>" não é um padrão Lua válido.',
- ['2'] = 'Eu não consegui obter uma lista de fontes.',
- ['3'] = '<b>Fontes de notícias encontradas correspondentes</b> "<code>%s</code>":\n\n%s',
- ['4'] = '<b>Aqui estão as fontes de notícias disponíveis que pode usar com</b> /news<b>. Use</b> /nsources &lt;pesquisa&gt; <b>para pesquisar a lista de fontes de notícias para um conjunto mais específico de resultados. As pesquisas são combinadas usando padrões Lua</b>\n\n%s',
- ['5'] = 'Não tem uma fonte de notícias preferida. Use /setnews <source> para definir uma. Veja a lista de fontes usando /nsources, ou restringir os resultados usando /nsources <pesquisa>.',
- ['6'] = 'A sua fonte de notícias preferida atual é %s. Use /setnews <source> para alterar isso. Veja a lista de fontes usando /nsources, ou restringir os resultados usando /nsources <pesquisa>.',
- ['7'] = 'A sua fonte preferida já está definida para %s! Use /news para ver a história principal atual.',
- ['8'] = 'Isso não é uma fonte de notícias válida. Exibir uma lista de fontes usando /nsources, ou restringir os resultados usando /nsources <pesquisa>.',
- ['9'] = 'A sua fonte de notícias preferida foi atualizada para %s! Use /news para ver a história principal atual.',
- ['10'] = 'Isso não é uma fonte válida, use /nsources para ver uma lista de fontes disponíveis. Se tem uma fonte preferida, use /setnews <fonte> Para receber automaticamente notícias daquela fonte enviada quando envie /news, sem quaisquer argumentos necessários.',
- ['11'] = 'Ver mais.'
- },
- ['nick'] = {
- ['1'] = 'O seu nick foi esquecido!',
- ['2'] = 'O seu nick foi definido como "%s"!'
- },
- ['optout'] = {
- ['1'] = 'Optou por enviar os seus dados! Use /optout para excluir.',
- ['2'] = 'Optou por não enviar os seus dados! Use /optin para enviar.'
- },
- ['paste'] = {
- ['1'] = 'Selecione um serviço para enviar copia:'
- },
- ['pin'] = {
- ['1'] = 'Não definiu ainda uma mensagem afixada. Use /pin <texto> para definir uma. A formatação Markdown é suportada.',
- ['2'] = 'Aqui está a última mensagem gerada usando /pin.',
- ['3'] = 'Eu encontrei uma mensagem afixada existente na base de dados, mas a mensagem que enviei parece ter sido apagada, e não consigo mais encontra-la. Pode definir uma nova usando /pin <texto>. A formatação Markdown é suportada.',
- ['4'] = 'Ocorreu um erro ao atualizar a mensagem afixada. Ou o texto inserido continha um sintaxe Markdown inválido, ou a mensagem afixada foi apagada. Eu estou agora tentar e enviar-lhe uma mensagem afixada nova, que será capaz de encontrar abaixo - se precisar modifica-lo, depois de garantir que a mensagem ainda existe, use /pin <texto>.',
- ['5'] = 'Eu não consegui enviar esse texto porque ele contém um sintaxe Markdown inválido.',
- ['6'] = 'Clique aqui para ver a mensagem afixada, atualizado para contendo o texto que me enviou.'
- },
- ['pokedex'] = {
- ['1'] = 'Nome: %s\nID: %s\nTipo: %s\nDescrição: %s'
- },
- ['promote'] = {
- ['1'] = 'Não consigo promover este utilizador porque é moderador ou administrador deste grupo.',
- ['2'] = 'Não consigo promover este utilizador porque já saiu deste grupo.',
- ['3'] = 'Não consigo promover esse utilizador porque ele já foi expulso deste grupo.'
- },
- ['quote'] = {
- ['1'] = 'Este utilizador desativou a funcionalidade de armazenamento de dados.',
- ['2'] = 'Não há citações guardadas para %s! Pode guardar um usando /save em resposta a uma mensagem que enviam.'
- },
- ['report'] = {
- ['1'] = 'Please reply to the message you would like to report to the group\'s administrators.',
- ['2'] = 'You can\'t report your own messages, are you just trying to be funny?',
- ['3'] = '<b>%s precisa de ajuda em %s!</b>',
- ['4'] = 'Click here to view the reported message.',
- ['5'] = 'I\'ve successfully reported that message to %s admin(s)!'
- },
- ['save'] = {
- ['1'] = 'Este utilizador desativou a funcionalidade de armazenamento de dados.',
- ['2'] = 'Esta mensagem foi gravada na minha base de dados, e adicionado à lista de possíveis respostas para quando /quote è usado em resposta a %s!'
- },
- ['sed'] = {
- ['1'] = '%s\n\n<i>%s não quis dizer isso!</i>',
- ['2'] = '%s\n\n<i>%s admitiu a sua derrota.</i>',
- ['3'] = '%s\n\n<i>%s não tem certeza se eles estavam errados...</i>',
- ['4'] = 'Vai-te lixar, <i>quando é que eu estou errado?</i>',
- ['5'] = '"<code>%s</code>" não é um modelo Lua válido.',
- ['6'] = 'Hey %s, %s seems to think you meant:\n<i>%s</i>',
- ['7'] = 'Sim',
- ['8'] = 'Não',
- ['9'] = 'Não tenho certeza',
- ['10'] = 'Just edit your message, idiot.'
- },
- ['setgrouplang'] = {
- ['1'] = 'O idioma deste grupo foi alterado para %s!',
- ['2'] = 'This group\'s language is currently %s.\nPlease note that some strings may not be translated as of yet. If you\'d like to change your language, select one using the keyboard below:',
- ['3'] = 'The option to force users to use the same language in this group is currently disabled. This setting should be toggled from /administration but, to make things easier for you, I\'ve included a button below.',
- ['4'] = 'Habilitar',
- ['5'] = 'Desabilitar'
- },
- ['setlang'] = {
- ['1'] = 'O seu idioma foi definido para %s!',
- ['2'] = 'O seu idioma é atualmente %s.\nTome nota que algumas sequencias de caracteres podem não estar traduzidas. Se quiser alterar seu idioma, selecione um usando o teclado abaixo:'
- },
- ['setlink'] = {
- ['1'] = 'Não é um URL valido.',
- ['2'] = 'Endereço definido com sucesso!'
- },
- ['setrules'] = {
- ['1'] = 'Formato Markdown invalido.',
- ['2'] = 'Regras definidas com sucesso!'
- },
- ['setwelcome'] = {
- ['1'] = 'O que mensagem gostaria de boas-vindas que fosse? O texto que especificar será formato em Markdown e enviado toda vez que um utilizador se juntar ao grupo (A mensagem de boas-vindas pode ser desativada no menu de administração, acessível via /administration). Pode usar espaços reservados para personalizar automaticamente a mensagem de boas-vindas para cada utilizador. Use $user_id para inserir o ID numérico do utilizador, $chat_id para inserir o ID numérico do grupo, $name para inserir o nome do utilizador, $title para inserir o título do grupo e $username para inserir o nome de utilizador do utilizador (Se o utilizador não tiver um @utilizador, o seu nome será usado em vez disso, para evitar é melhor usar isso com $name).',
- ['2'] = 'Ocorreu um erro ao formatar a mensagem, verifique a sintaxe de Markdown e tente novamente.',
- ['3'] = 'A mensagem de boas-vindas para %s foi atualizada com sucesso!'
- },
- ['share'] = {
- ['1'] = 'Partilhar'
- },
- ['shorten'] = {
- ['1'] = 'Selecione um URL shortener usando os botões abaixo:'
- },
- ['shsh'] = {
- ['1'] = 'Eu não consegui obter qualquer blobs SHSH para esse ECID, assegure-se de que é válido e os guardou usando https://tsssaver.1conan.com.',
- ['2'] = 'Os blobs SHSH para esse dispositivo estão disponíveis para as seguintes versões do iOS:\n',
- ['3'] = 'Transferir .zip'
- },
- ['statistics'] = {
- ['1'] = 'No messages have been sent in this chat!',
- ['2'] = '<b>Statistics for:</b> %s\n\n%s\n<b>Total messages sent:</b> %s',
- ['3'] = 'The statistics for this chat have been reset!',
- ['4'] = 'I could not reset the statistics for this chat. Perhaps they have already been reset?'
- },
- ['steam'] = {
- ['1'] = 'O seu nome de utilizador do Steam foi definido para "%s".',
- ['2'] = '"%s" não é um nome de utilizador Steam valido.',
- ['3'] = '%s é utilizador do Steam desde %s, em %s. Desligou a ultima vez %s, em %s. Clique <a href="%s">aqui</a> para ver o perfil no Steam.',
- ['4'] = '%s, AKA "%s",'
- },
- ['trust'] = {
- ['1'] = 'I cannot trust this user because they are a moderator or an administrator of this chat.',
- ['2'] = 'I cannot trust this user because they have already left this chat.',
- ['3'] = 'I cannot trust this user because they have already been kicked from this chat.'
- },
- ['unmute'] = {
- ['1'] = 'Que utilizador gostaria que removesse silenciar? Pode especificar este utilizador pelo seu @utilizador ou ID numérico.',
- ['2'] = 'Não consigo remover silenciar a este utilizador porque não está atualmente silenciado neste grupo.',
- ['3'] = 'Não consigo remover silenciar a este utilizador porque ele é um moderador ou administrador neste grupo.',
- ['4'] = 'Não consigo remover silenciar a este utilizador porque ele já deixou (ou foi expulso) deste grupo.',
- },
- ['untrust'] = {
- ['1'] = 'Which user would you like me to untrust? You can specify this user by their @username or numerical ID.',
- ['2'] = 'I cannot untrust this user because they are a moderator or an administrator in this chat.',
- ['3'] = 'I cannot untrust this user because they have already left this chat.',
- ['4'] = 'I cannot untrust this user because they have already been kicked from this chat.'
- },
- ['upload'] = {
- ['1'] = 'Responda a mensagem do ficheiro que pretende transferir para o servidor. Deve ser <= 20 MB.',
- ['2'] = 'Ficheiro é demasiado grande. Deve ser <= 20 MB.',
- ['3'] = 'Não consegui obter esse ficheiro, é provavelmente muito antigo.',
- ['4'] = 'Ocorreu um erro ao recuperar esse ficheiro.',
- ['5'] = 'Ficheiro transferido para o servidor com sucesso - pode ser encontrado em <code>%s</code>!'
- },
- ['voteban'] = {
- ['1'] = 'Qual utilizador gostaria de abrir uma votação para banir? Pode especificar este utilizador pelo seu @utilizador ou ID numérico.',
- ['2'] = 'Não consigo criar uma votação para este utilizador porque ele é um moderador ou administrador neste grupo.',
- ['3'] = 'Não consigo criar uma votação para este utilizador porque ele já deixaram (ou foi expulso) deste grupo.',
- ['4'] = '%s [%s] deve ser banido por %s? %s voto a favor para banir imediatamente, e %s votos contra para fechar esta votação.',
- ['5'] = 'Sim [%s]',
- ['6'] = 'Não [%s]',
- ['7'] = 'O povo falou. E baniu %s [%s] por %s porque %s pessoas votaram a favor.',
- ['8'] = 'O montante de votos a favor necessários foi atingido, no entanto, não foi pode banir %s - talvez deixou o grupo ou foi promovido desde que abrimos a votação para banir? É isso ou não tenho mais os privilégios administrativos necessários para executar esta ação!',
- ['9'] = 'O povo falou. E não foi banido %s [%s] por %s porque %s pessoa decidiram votar contra.',
- ['10'] = 'Votou a favor na decisão de banir %s [%s]!',
- ['11'] = 'O seu voto atual foi retirado, use os botões novamente para reenviar o seu voto.',
- ['12'] = 'Votou contra na decisão de banir %s [%s]!',
- ['13'] = 'A vote-ban has already been opened for this user!'
- },
- ['weather'] = {
- ['1'] = 'Ainda não tem uma localização definida. Use /setloc <localização> para definir uma.',
- ['2'] = 'Está atualmente %s (parece %s) em %s. %s'
- },
- ['welcome'] = {
- ['1'] = 'Regras do Grupo'
- },
- ['allowlist'] = {
- ['1'] = 'Qual utilizador gostaria de adicionar à white-list? Pode especificar este utilizador pelo seu @utilizador ou ID numérico.',
- ['2'] = 'Não consigo adicionar à white-list esse utilizador porque ele é um moderador ou administrador neste grupo.',
- ['3'] = 'Não consigo adicionar à white-list esse utilizador porque ele já deixou este grupo.',
- ['4'] = 'Não consigo adicionar à white-list esse utilizador porque ele já foi banido neste grupo.'
- },
- ['wikipedia'] = {
- ['1'] = 'Ver mais.'
- },
- ['youtube'] = {
- ['1'] = 'Anterior',
- ['2'] = 'Seguinte',
- ['3'] = 'Está na pagina %s de %s!'
- }
-}
\ No newline at end of file
diff --git a/languages/pt_pt.lua b/languages/pt_pt.lua
deleted file mode 100644
index 2229e7a..0000000
--- a/languages/pt_pt.lua
+++ /dev/null
@@ -1,735 +0,0 @@
--- This is a language file for mattata
--- Language: pt-pt
--- Author: American_Jesus
-
--- DO NOT CHANGE ANYTHING THAT BEGINS OR ENDS WITH A %
--- THESE ARE PLACEHOLDERS!
-
--- DO NOT CHANGE ANY MARKDOWN/HTML FORMATTING!
--- IF YOU ARE UNSURE, ASK ON TELEGRAM (t.me/mattataDev)
-
-return {
- ['errors'] = {
- ['connection'] = 'Erro de ligação.',
- ['results'] = 'Eu não consegui encontrar nenhum resultado para isso.',
- ['supergroup'] = 'Este comando só pode ser usado em super grupos.',
- ['admin'] = 'Precisa ser moderador ou administrador neste grupo para usar este comando.',
- ['unknown'] = 'Eu não reconheço esse(s) utilizador(es). Se gostaria de me ensinar quem ele(s) são, encaminhe-me uma mensagem dele(s) para qualquer conversa que eu estou.',
- ['generic'] = 'Ocorreu um erro!',
- ['use'] = 'You are not allowed to use this!',
- ['private'] = 'You can only use this command in private chat!'
- },
- ['addcommand'] = {
- ['1'] = 'Please specify the command in the format <code>/command - description</code>',
- ['2'] = 'I couldn\'t retrieve my commands!',
- ['3'] = 'The command description can\'t be longer than 256 characters!',
- ['4'] = 'An unknown error occurred! I couldn\'t add your command!',
- ['5'] = 'Success! Command added.'
- },
- ['addrule'] = {
- ['1'] = 'Please specify the rule you would like to add!',
- ['2'] = 'You don\'t have any rules to add to! Please set group rules using /setrules!',
- ['3'] = 'I couldn\'t add that rule, as it would make the length of the rules longer than Telegram\'s 4096 character limit!',
- ['4'] = 'I couldn\'t add that rule, it appears it contains invalid Markdown formatting!',
- ['5'] = 'Successfully updated the rules!'
- },
- ['addslap'] = {
- ['1'] = 'You can only use this command in groups!',
- ['2'] = 'The slap cannot contain curly braces apart from placeholders!',
- ['3'] = 'The slap cannot be any longer than 256 characters in length!',
- ['4'] = 'I\'ve successfully added that slap as a possibility for /slap in this group!',
- ['5'] = 'You must include placeholders in your slap. Use {ME} for the person executing and {THEM} for the victim.'
- },
- ['administration'] = {
- ['1'] = 'Enable Administration',
- ['2'] = 'Disable Administration',
- ['3'] = 'Anti-Spam Settings',
- ['4'] = 'Warning Settings',
- ['5'] = 'Vote-Ban Settings',
- ['6'] = 'Welcome New Users?',
- ['7'] = 'Send Rules On Join?',
- ['8'] = 'Send Rules In Group?',
- ['9'] = 'Back',
- ['10'] = 'Next',
- ['11'] = 'Word Filter',
- ['12'] = 'Anti-Bot',
- ['13'] = 'Anti-Link',
- ['14'] = 'Log Actions?',
- ['15'] = 'Anti-RTL',
- ['16'] = 'Anti-Spam Action',
- ['17'] = 'Ban',
- ['18'] = 'Kick',
- ['19'] = 'Delete Commands?',
- ['20'] = 'Force Group Language?',
- ['21'] = 'Send Settings In Group?',
- ['22'] = 'Delete Reply On Action?',
- ['23'] = 'Require Captcha?',
- ['24'] = 'Use Inline Captcha?',
- ['25'] = 'Ban SpamWatch-flagged users?',
- ['26'] = 'Number of warnings until %s:',
- ['27'] = 'Upvotes needed to ban:',
- ['28'] = 'Downvotes needed to dismiss:',
- ['29'] = 'Deleted %s, and its matching link from the database!',
- ['30'] = 'There were no entries found in the database matching "%s"!',
- ['31'] = 'You\'re not an administrator in that chat!',
- ['32'] = 'The minimum number of upvotes required for a vote-ban is %s.',
- ['33'] = 'The maximum number of upvotes required for a vote-ban is %s.',
- ['34'] = 'The minimum number of downvotes required for a vote-ban is %s.',
- ['35'] = 'The maximum number of downvotes required for a vote-ban is %s.',
- ['36'] = 'The maximum number of warnings is %s.',
- ['37'] = 'The minimum number of warnings is %s.',
- ['38'] = 'You can add one or more words to the word filter by using /filter <word(s)>',
- ['39'] = 'You will no longer be reminded that the administration plugin is disabled. To enable it, use /administration.',
- ['40'] = 'That\'s not a valid chat!',
- ['41'] = 'You don\'t appear to be an administrator in that chat!',
- ['42'] = 'My administrative functionality can only be used in groups/channels! If you\'re looking for help with using my administrative functionality, check out the "Administration" section of /help! Alternatively, if you wish to manage the settings for a group you administrate, you can do so here by using the syntax /administration <chat>.',
- ['43'] = 'Use the keyboard below to adjust the administration settings for <b>%s</b>:',
- ['44'] = 'Please send me a [private message](https://t.me/%s), so that I can send you this information.',
- ['45'] = 'I have sent you the information you requested via private chat.',
- ['46'] = 'Remove Channel Pins?',
- ['47'] = 'Remove Other Pins?',
- ['48'] = 'Remove Pasted Code?',
- ['49'] = 'Prevent Inline Bots?',
- ['50'] = 'Kick Media On Join?',
- ['51'] = 'Enable Plugins For Admins?',
- ['52'] = 'Kick URLs On Join?'
- },
- ['afk'] = {
- ['1'] = 'Desculpe, receio que este elemento esteja disponível somente para utilizadores com um @utilizador público!',
- ['2'] = '%s voltou depois de estar AFK por %s!',
- ['3'] = 'Nota',
- ['4'] = '%s está agora AFK.%s'
- },
- ['antispam'] = {
- ['1'] = 'Disable',
- ['2'] = 'Enable',
- ['3'] = 'Disable limit',
- ['4'] = 'Enable limits on %s',
- ['5'] = 'All Administration Settings',
- ['6'] = '%s [%s] has kicked %s [%s] from %s [%s] for hitting the configured anti-spam limit for [%s] media.',
- ['7'] = 'Kicked %s for hitting the configured antispam limit for [%s] media.',
- ['8'] = 'The maximum limit is 100.',
- ['9'] = 'The minimum limit is 1.',
- ['10'] = 'Modify the anti-spam settings for %s below:',
- ['11'] = 'Hey %s, if you\'re going to send code that is longer than %s characters in length, please do so using /paste in <a href="https://t.me/%s">private chat with me</a>!',
- ['12'] = '%s <code>[%s]</code> has %s %s <code>[%s]</code> from %s <code>[%s]</code> for sending Telegram invite link(s).\n#chat%s #user%s',
- ['13'] = '%s %s for sending Telegram invite link(s).',
- ['14'] = 'Hey, I noticed you\'ve got anti-link enabled and you\'re currently not allowing your users to mention a chat you\'ve just mentioned, if you\'d like to allowlist it, use /allowlink <links>.',
- ['15'] = 'Kicked %s <code>[%s]</code> from %s <code>[%s]</code> for sending media within their first few messages.\n#chat%s #user%s',
- ['16'] = 'Kicked %s <code>[%s]</code> from %s <code>[%s]</code> for sending a URL within their first few messages.\n#chat%s #user%s',
- ['17'] = 'Action',
- ['18'] = 'Kick',
- ['19'] = 'Ban',
- ['20'] = 'Mute'
- },
- ['appstore'] = {
- ['1'] = 'Ver no iTunes',
- ['2'] = 'rating',
- ['3'] = 'ratings'
- },
- ['authspotify'] = {
- ['1'] = 'You are already authorised using that account.',
- ['2'] = 'Authorising, please wait...',
- ['3'] = 'A connection error occured. Are you sure you replied with the correct link? It should look like',
- ['4'] = 'Successfully authorised your Spotify account!'
- },
- ['avatar'] = {
- ['1'] = 'Não consegui obter fotos de perfil para esse utilizador, verifique se especificou um nome de utilizador ou ID numérico válido.',
- ['2'] = 'Esse utilizador não tem fotos de perfil.',
- ['3'] = 'Esse utilizador não tem assim tantas de perfil!',
- ['4'] = 'That user has opted-out of data-collecting functionality, therefore I am not able to show you any of their profile photos.',
- ['5'] = 'User: %s\nPhoto: %s/%s\nSend /avatar %s [offset] to @%s to view a specific photo of this user',
- ['6'] = 'User: %s\nPhoto: %s/%s\nUse /avatar %s [offset] to view a specific photo of this user'
- },
- ['ban'] = {
- ['1'] = 'Qual utilizador gostaria que eu bane? Pode especificar esse utilizador pelo seu @username ou ID numérico.',
- ['2'] = 'Não consigo banir esse utilizador porque ele é um moderador ou um administrador neste grupo.',
- ['3'] = 'Não consigo banir este utilizador porque ele saiu deste grupo.',
- ['4'] = 'Não consigo banir este utilizador porque ele já foi banido deste grupo.',
- ['5'] = 'Eu preciso ter permissões administrativas para banir esse utilizador. Corrija este problema e tente novamente.',
- ['6'] = '%s <code>[%s]</code> has banned %s <code>[%s]</code> from %s <code>[%s]</code>%s.\n%s %s',
- ['7'] = '%s has banned %s%s.'
- },
- ['bash'] = {
- ['1'] = 'Especifique um comando para executar!',
- ['2'] = 'Sucesso!'
- },
- ['blocklist'] = {
- ['1'] = 'Qual utilizador gostaria de adicionar a lista negra? Pode especificar este utilizador pelo seu @username ou ID numérico.',
- ['2'] = 'Não consigo adicionar a lista negra esse utilizador porque ele é um moderador ou um administrador neste grupo.',
- ['3'] = 'Não consigo adicionar a lista negra esse utilizador porque ele já deixou este grupo.',
- ['4'] = 'Não consigo adicionar a lista negra esse utilizador porque ele já foi banido neste grupo.',
- ['5'] = '%s <code>[%s]</code> has blocklisted %s <code>[%s]</code> from using %s <code>[%s]</code> in %s <code>[%s]</code>%s.\n%s %s',
- ['6'] = '%s has blocklisted %s from using %s%s.'
- },
- ['blocklistchat'] = {
- ['1'] = '%s foi adicionado a lista negra, e vou deixar lá quem eu adicionar!',
- ['2'] = '%s é um utilizador, este comando é apenas para lista negras em conversas como grupos e canais!',
- ['3'] = '%s não parece ser uma conversa valida!'
- },
- ['bugreport'] = {
- ['1'] = 'Sucesso! Seu relatório de bug foi enviado. O ID deste relatório é #%s.',
- ['2'] = 'Ocorreu um problema enquanto relatava esse bug! Ah, a ironia!'
- },
- ['calc'] = {
- ['1'] = 'Clique para enviar o resultado.',
- ['2'] = '"%s" was an unexpected word!',
- ['3'] = 'You cannot have a unit before a number!'
- },
- ['captionbotai'] = {
- ['1'] = 'Eu realmente não posso descrever essa imagem!'
- },
- ['cats'] = {
- ['1'] = 'Meow!'
- },
- ['channel'] = {
- ['1'] = 'Não tem permissão para usar isso!',
- ['2'] = 'Parece já não ser um administrador nesse grupo!',
- ['3'] = 'Não consegui enviar a sua mensagem, tem certeza de que ainda tenho permissão para enviar mensagens nesse grupo?',
- ['4'] = 'A sua mensagem foi enviada!',
- ['5'] = 'Não consegui recuperar uma lista de administradores para desse grupo!',
- ['6'] = 'Não parece ser um administrador desse grupo!',
- ['7'] = 'Especifique a mensagem a enviar, utilizando a sintaxe /channel <canal> <mensagem>.',
- ['8'] = 'Tem certeza de que deseja enviar esta mensagem? É assim que vai aparecer:',
- ['9'] = 'Sim, Tenho a certeza!',
- ['10'] = 'Essa mensagem contém formatação Markdown inválido! Corrija a sintaxe e tente novamente.'
- },
- ['chatroulette'] = {
- ['1'] = 'Hey! Please don\'t send messages longer than %s characters. We don\'t want to annoy the other user!',
- ['2'] = '*Anonymous said:*\n```\n%s\n```\nTo end your session, send /endchat.',
- ['3'] = 'I\'m afraid I lost connection from the other user! To begin a new chat, please send /chatroulette!',
- ['4'] = 'The other person you were chatting with has ended the session. To start a new one, send /chatroulette.',
- ['5'] = 'Successfully ended your session. To start a new one, send /chatroulette.',
- ['6'] = 'I have successfully removed you from the list of available users.',
- ['7'] = 'You don\'t have a session set up at the moment. To start one, send /chatroulette.',
- ['8'] = 'Finding you a session, please wait...',
- ['9'] = 'I\'m afraid there aren\'t any available users right now, but I have added you to the list of available users! To stop this completely, please send /endchat.',
- ['10'] = 'I have successfully paired you with another user to chat to! Please remember to be kind to them! To end the chat, send /endchat.',
- ['11'] = 'I\'m afraid the user who I tried to pair you with has since blocked me. Please try and send /chatroulette again to try and connect to me!',
- ['12'] = 'I have successfully paired you with another user to chat to! Please remember to be kind to them! To end the chat, send /endchat.'
- },
- ['commandstats'] = {
- ['1'] = 'No commands have been sent in this chat!',
- ['2'] = '<b>Command statistics for:</b> %s\n\n%s\n<b>Total commands sent:</b> %s',
- ['3'] = 'The command statistics for this chat have been reset!',
- ['4'] = 'I could not reset the command statistics for this chat. Perhaps they have already been reset?'
- },
- ['control'] = {
- ['1'] = 'Pfft, querias!',
- ['2'] = '%s está a recarregar...'
- },
- ['copypasta'] = {
- ['1'] = 'O texto respondido não deverá exceder %s caracteres!'
- },
- ['coronavirus'] = {
- ['1'] = [[*COVID-19 Statistics for:* %s
-
-*New confirmed cases:* %s
-*Total confirmed cases:* %s
-*New deaths:* %s
-*Total deaths:* %s
-*New recovered cases:* %s
-*Total recovered cases:* %s]]
- },
- ['counter'] = {
- ['1'] = 'Eu não pude adicionar um contador a essa mensagem!'
- },
- ['custom'] = {
- ['1'] = 'Sucesso! Essa mensagem será enviada toda vez que alguém usar %s!',
- ['2'] = 'O trigger "%s" não existe!',
- ['3'] = 'O trigger "%s" foi apagado!',
- ['4'] = 'Ainda não tem triggers personalizado definidos!',
- ['5'] = 'Comandos personalizados para %s:\n',
- ['6'] = 'Para criar um novo comando personalizado, use a seguinte sintaxe:\n/custom new #trigger <valor>. Para listar todos os triggers atuais, use /custom list. Para apagar um trigger, use /custom del #trigger.'
- },
- ['delete'] = {
- ['1'] = 'Não consegui apagar essa mensagem. Talvez a mensagem seja muito antiga ou inexistente?'
- },
- ['demote'] = {
- ['1'] = 'Qual utilizador gostaria que eu despromovesse? Pode especificar este utilizador pelo seu @username ou ID numérico.',
- ['2'] = 'Eu não posso despromover esse utilizador porque ele não é um moderador ou um administrador neste grupo.',
- ['3'] = 'Eu não posso despromover esse utilizador porque ele já deixou este grupo.',
- ['4'] = 'Não consigo despromover esse utilizador porque ele já foi expulso deste grupo.'
- },
- ['doge'] = {
- ['1'] = 'Por favor, escreva o texto que deseja para Doge-ify. Cada sentença deve ser separada usando barras (/) ou novas linhas.'
- },
- ['donate'] = {
- ['1'] = '<b>Hello, %s!</b>\n\nIf you\'re feeling generous, you can contribute to the mattata project by making a monetary donation of any amount. This will go towards server costs and any time and resources used to develop mattata. This is an optional act, however it is greatly appreciated and your name will also be listed publically on mattata\'s GitHub page.\n\nIf you\'re still interested, you can donate <a href="https://paypal.me/wrxck">here</a>. Thank you for your continued support!'
- },
- ['exec'] = {
- ['1'] = 'Selecione a linguagem em que gostaria de executar o seu código:',
- ['2'] = 'Ocurreu um erro! Tempo de ligação expirou. Está a tentar fazer-me lag?',
- ['3'] = 'Selecionou "%s" – tem a certeza?',
- ['4'] = 'Voltar',
- ['5'] = 'Tenho a certeza',
- ['6'] = 'Introduza um fragmento de código que pretende executar. Não precisa especificar a linguagem, faremos isso depois!',
- ['7'] = 'Selecione a linguagem em que gostaria de executar o seu código:'
- },
- ['facebook'] = {
- ['1'] = 'Ocorreu um erro!',
- ['2'] = 'Escreva o nome de utilizador do Facebook do qual gostaria de obter a foto do perfil.',
- ['3'] = 'Visitas @%s no Facebook'
- },
- ['fact'] = {
- ['1'] = 'Gerar Outro'
- },
- ['fban'] = {
- ['1'] = 'Which user would you like me to Fed-ban? You can specify this user by their @username or numerical ID.',
- ['2'] = 'I cannot Fed-ban this user because they are a moderator or an administrator in this chat.'
- },
- ['flickr'] = {
- ['1'] = 'Pesquisou por:',
- ['2'] = 'Introduza uma consulta de pesquisa (Ou seja, o que quer que eu procure no Flickr, i.e. "Big Ben" mostrara uma fotografia do Big Ben em Londres).',
- ['3'] = 'Mais Resultados'
- },
- ['game'] = {
- ['1'] = 'Total de vitórias: %s\nTotal de derrotas: %s\nBalanço: %s mattacoins',
- ['2'] = 'Entrar no Jogo',
- ['3'] = 'Este jogo já acabou!',
- ['4'] = 'Não é a sua vez!',
- ['5'] = 'Não faz parte deste jogo!',
- ['6'] = 'Não pode ser ai!',
- ['7'] = 'Já faz parte deste jogo!',
- ['8'] = 'Este jogo já começou!',
- ['9'] = '%s [%s] está a jogar contra %s [%s]\nE é a vez de %s\'s a jogar!',
- ['10'] = '%s ganhou o jogo contra %s!',
- ['11'] = '%s criou um jogo contra %s!',
- ['12'] = 'A espera pelo oponente...',
- ['13'] = 'Jogo do Galo',
- ['14'] = 'Clique para enviar o jogo para o seu grupo!',
- ['15'] = 'Estatísticas %s:\n',
- ['16'] = 'Jogar ao Jogo do Galo!'
- },
- ['gblocklist'] = {
- ['1'] = 'Responda ao utilizador que deseja incluir na lista negra global ou especifique-o por nome de utilizador/ID.',
- ['2'] = 'Não conseguir obter informações sobre "%s", verifique se é um nome de utilizador/ID válido e tente novamente.',
- ['3'] = 'Isso é um %s, não um utilizador!'
- },
- ['gif'] = {
- ['1'] = 'Introduza uma consulta de pesquisa (Que é, o que quer que eu procure no GIPHY, ex: "cat" irá mostrar um GIF de um gato).'
- },
- ['gallowlist'] = {
- ['1'] = 'Responda ao utilizador que deseja incluir na lista branca global ou especifique-o por nome de utilizador/ID.',
- ['2'] = 'Não conseguir obter informações sobre "%s", verifique se é um nome de utilizador/ID válido e tente novamente.',
- ['3'] = 'Isso é um %s, não um utilizador!'
- },
- ['hackernews'] = {
- ['1'] = 'Histórias principais de Hacker News:'
- },
- ['help'] = {
- ['1'] = 'Nenhum resultado encontrado!',
- ['2'] = 'Não foram encontrados elementos que correspondam a "%s", Por favor, tente ser mais específico!',
- ['3'] = '\n\nArgumentos: <requer> [opcional]\n\nProcurar um elemento ou obter ajuda com um comando usando minha funcionalidade de pesquisa inline - apenas me mencione em qualquer grupo usando a sintaxe @%s <texto de procura>.',
- ['4'] = 'Anterior',
- ['5'] = 'Seguinte',
- ['6'] = 'Voltar',
- ['7'] = 'Procurar',
- ['8'] = 'Está na pagina %s de %s!',
- ['9'] = [[
-Posso executar muitas ações administrativas nos seus grupos, basta adicionar-me como administrador e envie /administration para ajustar as configurações do seu grupo.
-Aqui estão alguns comandos administrativos e um breve comentário sobre o que eles fazem:
-
-• /pin <texto> - Envie uma mensagem formatada em Markdown que pode ser editada usando o mesmo comando com texto diferente, para evitar de ter que afixar novamente uma mensagem se não poder edita-la (o que acontece se a mensagem tiver mais de 48 horas)
-
-• /ban - Banir um utilizador respondendo a uma de suas mensagens ou especificando com o nome de utilizador/ID
-
-• /kick - Expulsar (banir e depois remover ban) um utilizador respondendo a uma de suas mensagens ou especificando com o nome de utilizador/ID
-
-• /unban - Remover ban a um utilizador respondendo a uma de suas mensagens ou especificando com o nome de utilizador/ID
-
-• /setrules <texto> - Defina o texto formatado como Markdown como as regras de grupo, que serão enviadas sempre que alguém usar /rules
- ]],
- ['10'] = [[
-• /setwelcome - Defina o texto formatado como Markdown como uma mensagem de boas-vindas que será enviada sempre que um utilizador se juntar ao seu grupo (A mensagem de boas-vindas pode ser desativada no menu de administração, acessível via /administration). Pode usar espaços reservados para personalizar automaticamente a mensagem de boas-vindas para cada utilizador. Use $user_id para inserir o ID numérico do utilizador, $chat_id para inserir o ID numérico do grupo, $name para inserir o nome do utilizador, $title para inserir o título do grupo e $username para inserir o nome de utilizador do utilizador (Se o utilizador não tiver um @utilizador, o seu nome será usado em vez disso, para evitar é melhor usar isso com $name)
-
-• /warn - Avisa um utilizador, e bane-o quando atingirem o número máximo de avisos
-
-• /mod - Promove um utilizador respondendo a, dando acesso a comandos administrativos como /ban, /kick, /warn etc. (isto é útil quando não quer que alguém tenha a capacidade de apagar mensagens!)
-
-• /demod - Despromove um utilizador respondendo a, removendo do seu estatuto de moderação e revogando sua capacidade de usar comandos administrativos
-
-• /staff - Mostrar o criador, administradores e moderadores do grupo numa lista bem formatada
- ]],
- ['11'] = [[
-• /report - Encaminha a mensagem de resposta para todos os administradores e os alerta da situação atual
-
-• /setlink <URL> - Define o endereço do grupo para o URL fornecido, que será enviado sempre que alguém usar /link
-
-• /links <texto> - Listas brancas todos os endereços Telegram encontrados no texto fornecido (inclui endereços de @utilizador)
- ]],
- ['12'] = 'Abaixo estão alguns links que pode achar úteis:',
- ['13'] = 'Desenvolvimento',
- ['14'] = 'Canal',
- ['15'] = 'Suporte',
- ['16'] = 'FAQ',
- ['17'] = 'Código Fonte',
- ['18'] = 'Doar',
- ['19'] = 'Rate',
- ['20'] = 'Registo de Administração',
- ['21'] = 'Definições de administrador',
- ['22'] = 'Plugins',
- ['23'] = [[
-<b>Olá %s! O meu nome é %s, é um prazer conhece-lo</b> %s
-
-Eu entendo muitos comandos, que você pode aprender mais sobre pressionando o botão "Comandos" usando o teclado acoplado.
-
-%s <b>Dica:</b> Use o botão "Definições" para alterar o modo como eu trabalho%s!
-
-%s <b>Find me useful, or just want to help?</b> Donations are very much appreciated, use /donate for more information!
- ]],
- ['24'] = 'em'
- },
- ['id'] = {
- ['1'] = 'Desculpe, mas eu não reconheço esse utilizador. Ensine-me quem ele é, encaminhando uma mensagem dele a mim ou faça com que ele me enviem uma mensagem.',
- ['2'] = 'Grupo consultado:',
- ['3'] = 'Este grupo:',
- ['4'] = 'Clique para enviar o resultado!'
- },
- ['imdb'] = {
- ['1'] = 'Anterior',
- ['2'] = 'Seguinte',
- ['3'] = 'Está na pagina %s de %s!'
- },
- ['import'] = {
- ['1'] = 'Eu não reconheço esse grupo!',
- ['2'] = 'Isso não é um super grupo, portanto não consigo importar nenhuma configuração dele!',
- ['3'] = 'Configurações administrativas importadas e plugins alternados com sucesso de %s para %s!'
- },
- ['info'] = {
- ['1'] = [[
-```
-Redis:
-%s Ficheiro de Configuração: %s
-%s Modo: %s
-%s Porta TCP: %s
-%s Versão: %s
-%s Tempo de atividade: %s days
-%s ID do Processo: %s
-%s Keys Expiradas: %s
-
-%s Contagem de Utilizadores: %s
-%s Contagem de Grupos: %s
-
-Sistema:
-%s OS: %s
-```
- ]]
- },
- ['instagram'] = {
- ['1'] = '@%s no Instagram'
- },
- ['ipsw'] = {
- ['1'] = '<b>%s</b> iOS %s\n\n<code>MD5 sum: %s\nSHA1 sum: %s\nTamanho do ficheiro: %s GB</code>\n\n<i>%s %s</i>',
- ['2'] = 'Este firmware não está mais sendo assinado!',
- ['3'] = 'Este firmware ainda está sendo assinado!',
- ['4'] = 'Selecione o seu modelo:',
- ['5'] = 'Selecione a versão do firmware:',
- ['6'] = 'Selecione seu tipo de dispositivo:',
- ['7'] = 'iPod Touch',
- ['8'] = 'iPhone',
- ['9'] = 'iPad',
- ['10'] = 'Apple TV'
- },
- ['ispwned'] = {
- ['1'] = 'Essa conta foi encontrada nos seguintes fugas de informação:'
- },
- ['itunes'] = {
- ['1'] = 'Nome:',
- ['2'] = 'Artista:',
- ['3'] = 'Álbum:',
- ['4'] = 'Faixa:',
- ['5'] = 'Disco:',
- ['6'] = 'A consulta original não pôde ser encontrada, provavelmente apagou a mensagem original.',
- ['7'] = 'A capa pode ser encontrada abaixo:',
- ['8'] = 'Introduza uma consulta de pesquisa (Ou seja, o que quer que eu procure no iTunes, Ex: "Green Day American Idiot" ira mostrar informações sobre o primeiro resultado para American Idiot dos Green Day).',
- ['9'] = 'Obter Capa do Álbum'
- },
- ['kick'] = {
- ['1'] = 'Qual utilizador gostaria que eu expulsasse? Pode especificar este utilizador por seu @utilizador ou ID numérico.',
- ['2'] = 'Eu não consigo expulsar esse utilizador porque ele é um moderador ou administrador neste grupo.',
- ['3'] = 'Eu não consigo expulsar esse utilizador porque ele já deixou este grupo.',
- ['4'] = 'Não consigo expulsar esse utilizador porque ele já foi expulso deste grupo.',
- ['5'] = 'Eu preciso ter permissões administrativas para expulsar esse utilizador. Corrija este problema e tente novamente.'
- },
- ['lastfm'] = {
- ['1'] = '%s\'s utilizador de last.fm foi definido para "%s".',
- ['2'] = 'O seu utilizador last.fm foi esquecido!',
- ['3'] = 'Não tem atualmente um utilizado do last.fm definido!',
- ['4'] = 'Especifique o utilizador do last.fm ou defina com /fmset.',
- ['5'] = 'Nenhum histórico foi encontrado para este utilizador.',
- ['6'] = '%s está atualmente a ouvir:\n',
- ['7'] = '%s ouviu ultimamente:\n',
- ['8'] = 'Desconhecido',
- ['9'] = 'Clique para enviar o resultado.'
- },
- ['location'] = {
- ['1'] = 'Não tem uma localização definida. O que nova localização gostaria que fosse?'
- },
- ['logchat'] = {
- ['1'] = 'Escreva o nome de utilizador ou ID numérico do grupo no qual deseja registar todas as ações administrativas.',
- ['2'] = 'A verificar se o grupo é válido...',
- ['3'] = 'Desculpe, parece que especificou um grupo inválido, ou especificou um grupo que eu ainda não adicionado. Corrija e tente novamente.',
- ['4'] = 'Não pode definir um utilizador como o seu grupo de registo!',
- ['5'] = 'Não parece ser administrador nesse grupo!',
- ['6'] = 'Parece que eu já estou registar ações administrativas nesse grupo! Use /logchat para especificar um novo.',
- ['7'] = 'Esse grupo é válido, vou tentar e enviar uma mensagem de teste para ele, apenas para garantir que tenho permissão para falar!',
- ['8'] = 'Olá mundo - esta é uma mensagem de teste para verificar minhas permissões de escrita - se estiver a ler isto, então tudo correu bem!',
- ['9'] = 'Tudo feito! De agora em diante, Quaisquer ações administrativas neste grupo serão registadas em %s - para mudar o grupo que quer que eu registe ações administrativas, basta enviar /logchat.'
- },
- ['lua'] = {
- ['1'] = 'Digite uma string de Lua para executar!'
- },
- ['lyrics'] = {
- ['1'] = 'Spotify',
- ['2'] = 'Mostrar letra',
- ['3'] = 'Introduza uma consulta de pesquisa (isto é, que musica/artista/letra quer que eu obtenha letras, Ex: "Green Day Basket Case" irá mostrar a letra para Basket Case dos Green Day).'
- },
- ['minecraft'] = {
- ['1'] = '<b>%s mudou o seu utilizador %s vez</b>',
- ['2'] = '<b>%s mudou o seu utilizador %s vezes</b>',
- ['3'] = 'Anterior',
- ['4'] = 'Seguinte',
- ['5'] = 'Voltar',
- ['6'] = 'UUID',
- ['7'] = 'Avatar',
- ['8'] = 'Histórico de Utilizador',
- ['9'] = 'Selecione uma opção:',
- ['10'] = 'Escreva o nome de utilizador do jogador do Minecraft que gostaria de ver informações (Ex: enviando "Notch" irá ver as informações sobre o jogador Notch).',
- ['11'] = 'Os nomes de utilizadores do Minecraft têm entre 3 e 16 caracteres.'
- },
- ['mute'] = {
- ['1'] = 'Que utilizador gostaria que ficasse silenciar? Pode especificar este utilizador pelo seu @utilizador ou ID numérico.',
- ['2'] = 'Não consigo silenciar este utilizador porque já estão silenciados neste grupo.',
- ['3'] = 'Não consigo silenciar este utilizador porque ele é um moderador ou administrador neste grupo.',
- ['4'] = 'Não consigo silenciar este utilizador porque ele já deixou (ou foi expulso) deste grupo.',
- ['5'] = 'Eu preciso ter permissões administrativas para silenciar este utilizador. Corrija este problema e tente novamente.'
- },
- ['myspotify'] = {
- ['1'] = 'Profile',
- ['2'] = 'Following',
- ['3'] = 'Recently Played',
- ['4'] = 'Currently Playing',
- ['5'] = 'Top Tracks',
- ['6'] = 'Top Artists',
- ['7'] = 'You don\'t appear to be following any artists!',
- ['8'] = 'Your Top Artists',
- ['9'] = 'You don\'t appear to have any tracks in your library!',
- ['10'] = 'Your Top Tracks',
- ['11'] = 'You don\'t appear to be following any artists!',
- ['12'] = 'Artists You Follow',
- ['13'] = 'You don\'t appear to have recently played any tracks!',
- ['14'] = '<b>Recently Played</b>\n%s %s\n%s %s\n%s Listened to at %s:%s on %s/%s/%s.',
- ['15'] = 'The request has been accepted for processing, but the processing has not been completed.',
- ['16'] = 'You don\'t appear to be listening to anything right now!',
- ['17'] = 'Currently Playing',
- ['18'] = 'An error occured whilst re-authorising your Spotify account!',
- ['19'] = 'Successfully re-authorised your Spotify account! Processing your original request...',
- ['20'] = 'Re-authorising your Spotify account, please wait...',
- ['21'] = 'You need to authorise mattata in order to connect your Spotify account. Click [here](https://accounts.spotify.com/en/authorize?client_id=%s&response_type=code&redirect_uri=%s&scope=user-library-read,playlist-read-private,playlist-read-collaborative,user-read-private,user-read-email,user-follow-read,user-top-read,user-read-playback-state,user-read-recently-played,user-read-currently-playing,user-modify-playback-state) and press the green "OKAY" button to link mattata to your Spotify account. After you\'ve done that, send the link you were redirected to (it should begin with "%s", followed by a unique code) in reply to this message.',
- ['22'] = 'Playlists',
- ['23'] = 'Use Inline Mode',
- ['24'] = 'Lyrics',
- ['25'] = 'No devices were found.',
- ['26'] = 'You don\'t appear to have any playlists.',
- ['27'] = 'Your Playlists',
- ['28'] = '%s %s [%s tracks]',
- ['29'] = '%s %s [%s]\nSpotify %s user\n\n<b>Devices:</b>\n%s',
- ['30'] = 'Playing previous track...',
- ['31'] = 'You are not a premium user!',
- ['32'] = 'I could not find any devices.',
- ['33'] = 'Playing next track...',
- ['34'] = 'Resuming track...',
- ['35'] = 'Your device is temporarily unavailable...',
- ['36'] = 'No devices were found!',
- ['37'] = 'Pausing track...',
- ['38'] = 'Now playing',
- ['39'] = 'Shuffling your music...',
- ['40'] = 'That\'s not a valid volume. Please specify a number between 0 and 100.',
- ['41'] = 'The volume has been set to %s%%!',
- ['42'] = 'This message is using an old version of this plugin, please request a new one by sending /myspotify!'
- },
- ['name'] = {
- ['1'] = 'O nome a qual respondo atualmente é "%s" - para alterar isso, use /name <texto> (onde <texto> o nome a qual quer que eu responda).',
- ['2'] = 'Meu novo nome precisa ter entre 2 e 32 caracteres!',
- ['3'] = 'Meu nome só pode conter caracteres alfanuméricos!',
- ['4'] = 'Vou agora responder a "%s", em vez de "%s" - para alterar isso, use /name <texto> (onde <text> o nome a qual quer que eu responda).'
- },
- ['netflix'] = {
- ['1'] = 'Ver mais.'
- },
- ['news'] = {
- ['1'] = '"<code>%s</code>" não é um padrão Lua válido.',
- ['2'] = 'Eu não consegui obter uma lista de fontes.',
- ['3'] = '<b>Fontes de notícias encontradas correspondentes</b> "<code>%s</code>":\n\n%s',
- ['4'] = '<b>Aqui estão as fontes de notícias disponíveis que pode usar com</b> /news<b>. Use</b> /nsources &lt;pesquisa&gt; <b>para pesquisar a lista de fontes de notícias para um conjunto mais específico de resultados. As pesquisas são combinadas usando padrões Lua</b>\n\n%s',
- ['5'] = 'Não tem uma fonte de notícias preferida. Use /setnews <source> para definir uma. Veja a lista de fontes usando /nsources, ou restringir os resultados usando /nsources <pesquisa>.',
- ['6'] = 'A sua fonte de notícias preferida atual é %s. Use /setnews <source> para alterar isso. Veja a lista de fontes usando /nsources, ou restringir os resultados usando /nsources <pesquisa>.',
- ['7'] = 'A sua fonte preferida já está definida para %s! Use /news para ver a história principal atual.',
- ['8'] = 'Isso não é uma fonte de notícias válida. Exibir uma lista de fontes usando /nsources, ou restringir os resultados usando /nsources <pesquisa>.',
- ['9'] = 'A sua fonte de notícias preferida foi atualizada para %s! Use /news para ver a história principal atual.',
- ['10'] = 'Isso não é uma fonte válida, use /nsources para ver uma lista de fontes disponíveis. Se tem uma fonte preferida, use /setnews <fonte> Para receber automaticamente notícias daquela fonte enviada quando envie /news, sem quaisquer argumentos necessários.',
- ['11'] = 'Ver mais.'
- },
- ['nick'] = {
- ['1'] = 'O seu nick foi esquecido!',
- ['2'] = 'O seu nick foi definido como "%s"!'
- },
- ['optout'] = {
- ['1'] = 'Optou por enviar os seus dados! Use /optout para excluir.',
- ['2'] = 'Optou por não enviar os seus dados! Use /optin para enviar.'
- },
- ['paste'] = {
- ['1'] = 'Selecione um serviço para enviar copia:'
- },
- ['pin'] = {
- ['1'] = 'Não definiu ainda uma mensagem afixada. Use /pin <texto> para definir uma. A formatação Markdown é suportada.',
- ['2'] = 'Aqui está a última mensagem gerada usando /pin.',
- ['3'] = 'Eu encontrei uma mensagem afixada existente na base de dados, mas a mensagem que enviei parece ter sido apagada, e não consigo mais encontra-la. Pode definir uma nova usando /pin <texto>. A formatação Markdown é suportada.',
- ['4'] = 'Ocorreu um erro ao atualizar a mensagem afixada. Ou o texto inserido continha um sintaxe Markdown inválido, ou a mensagem afixada foi apagada. Eu estou agora tentar e enviar-lhe uma mensagem afixada nova, que será capaz de encontrar abaixo - se precisar modifica-lo, depois de garantir que a mensagem ainda existe, use /pin <texto>.',
- ['5'] = 'Eu não consegui enviar esse texto porque ele contém um sintaxe Markdown inválido.',
- ['6'] = 'Clique aqui para ver a mensagem afixada, atualizado para contendo o texto que me enviou.'
- },
- ['pokedex'] = {
- ['1'] = 'Nome: %s\nID: %s\nTipo: %s\nDescrição: %s'
- },
- ['promote'] = {
- ['1'] = 'Não consigo promover este utilizador porque é moderador ou administrador deste grupo.',
- ['2'] = 'Não consigo promover este utilizador porque já saiu deste grupo.',
- ['3'] = 'Não consigo promover esse utilizador porque ele já foi expulso deste grupo.'
- },
- ['quote'] = {
- ['1'] = 'Este utilizador desativou a funcionalidade de armazenamento de dados.',
- ['2'] = 'Não há citações guardadas para %s! Pode guardar um usando /save em resposta a uma mensagem que enviam.'
- },
- ['report'] = {
- ['1'] = 'Please reply to the message you would like to report to the group\'s administrators.',
- ['2'] = 'You can\'t report your own messages, are you just trying to be funny?',
- ['3'] = '<b>%s needs help in %s!</b>',
- ['4'] = 'Click here to view the reported message.',
- ['5'] = 'I\'ve successfully reported that message to %s admin(s)!'
- },
- ['save'] = {
- ['1'] = 'Este utilizador desativou a funcionalidade de armazenamento de dados.',
- ['2'] = 'Esta mensagem foi gravada na minha base de dados, e adicionado à lista de possíveis respostas para quando /quote è usado em resposta a %s!'
- },
- ['sed'] = {
- ['1'] = '%s\n\n<i>%s não quis dizer isso!</i>',
- ['2'] = '%s\n\n<i>%s admitiu a sua derrota.</i>',
- ['3'] = '%s\n\n<i>%s não tem certeza se eles estavam errados...</i>',
- ['4'] = 'Vai-te lixar, <i>quando é que eu estou errado?</i>',
- ['5'] = '"<code>%s</code>" não é um modelo Lua válido.',
- ['6'] = 'Hey %s, %s seems to think you meant:\n<i>%s</i>',
- ['7'] = 'Sim',
- ['8'] = 'Não',
- ['9'] = 'Não tenho certeza',
- ['10'] = 'Just edit your message, idiot.'
- },
- ['setgrouplang'] = {
- ['1'] = 'This group\'s language has been set to %s!',
- ['2'] = 'This group\'s language is currently %s.\nPlease note that some strings may not be translated as of yet. If you\'d like to change your language, select one using the keyboard below:',
- ['3'] = 'The option to force users to use the same language in this group is currently disabled. This setting should be toggled from /administration but, to make things easier for you, I\'ve included a button below.',
- ['4'] = 'Enable',
- ['5'] = 'Disable'
- },
- ['setlang'] = {
- ['1'] = 'O seu idioma foi definido para %s!',
- ['2'] = 'O seu idioma é atualmente %s.\nTome nota que algumas sequencias de caracteres podem não estar traduzidas. Se quiser alterar seu idioma, selecione um usando o teclado abaixo:'
- },
- ['setlink'] = {
- ['1'] = 'Não é um URL valido.',
- ['2'] = 'Endereço definido com sucesso!'
- },
- ['setrules'] = {
- ['1'] = 'Formato Markdown invalido.',
- ['2'] = 'Regras definidas com sucesso!'
- },
- ['setwelcome'] = {
- ['1'] = 'O que mensagem gostaria de boas-vindas que fosse? O texto que especificar será formato em Markdown e enviado toda vez que um utilizador se juntar ao grupo (A mensagem de boas-vindas pode ser desativada no menu de administração, acessível via /administration). Pode usar espaços reservados para personalizar automaticamente a mensagem de boas-vindas para cada utilizador. Use $user_id para inserir o ID numérico do utilizador, $chat_id para inserir o ID numérico do grupo, $name para inserir o nome do utilizador, $title para inserir o título do grupo e $username para inserir o nome de utilizador do utilizador (Se o utilizador não tiver um @utilizador, o seu nome será usado em vez disso, para evitar é melhor usar isso com $name).',
- ['2'] = 'Ocorreu um erro ao formatar a mensagem, verifique a sintaxe de Markdown e tente novamente.',
- ['3'] = 'A mensagem de boas-vindas para %s foi atualizada com sucesso!'
- },
- ['share'] = {
- ['1'] = 'Partilhar'
- },
- ['shorten'] = {
- ['1'] = 'Selecione um URL shortener usando os botões abaixo:'
- },
- ['shsh'] = {
- ['1'] = 'Eu não consegui obter qualquer blobs SHSH para esse ECID, assegure-se de que é válido e os guardou usando https://tsssaver.1conan.com.',
- ['2'] = 'Os blobs SHSH para esse dispositivo estão disponíveis para as seguintes versões do iOS:\n',
- ['3'] = 'Transferir .zip'
- },
- ['statistics'] = {
- ['1'] = 'No messages have been sent in this chat!',
- ['2'] = '<b>Statistics for:</b> %s\n\n%s\n<b>Total messages sent:</b> %s',
- ['3'] = 'The statistics for this chat have been reset!',
- ['4'] = 'I could not reset the statistics for this chat. Perhaps they have already been reset?'
- },
- ['steam'] = {
- ['1'] = 'O seu nome de utilizador do Steam foi definido para "%s".',
- ['2'] = '"%s" não é um nome de utilizador Steam valido.',
- ['3'] = '%s é utilizador do Steam desde %s, em %s. Desligou a ultima vez %s, em %s. Clique <a href="%s">aqui</a> para ver o perfil no Steam.',
- ['4'] = '%s, AKA "%s",'
- },
- ['trust'] = {
- ['1'] = 'I cannot trust this user because they are a moderator or an administrator of this chat.',
- ['2'] = 'I cannot trust this user because they have already left this chat.',
- ['3'] = 'I cannot trust this user because they have already been kicked from this chat.'
- },
- ['unmute'] = {
- ['1'] = 'Que utilizador gostaria que removesse silenciar? Pode especificar este utilizador pelo seu @utilizador ou ID numérico.',
- ['2'] = 'Não consigo remover silenciar a este utilizador porque não está atualmente silenciado neste grupo.',
- ['3'] = 'Não consigo remover silenciar a este utilizador porque ele é um moderador ou administrador neste grupo.',
- ['4'] = 'Não consigo remover silenciar a este utilizador porque ele já deixou (ou foi expulso) deste grupo.',
- },
- ['untrust'] = {
- ['1'] = 'Which user would you like me to untrust? You can specify this user by their @username or numerical ID.',
- ['2'] = 'I cannot untrust this user because they are a moderator or an administrator in this chat.',
- ['3'] = 'I cannot untrust this user because they have already left this chat.',
- ['4'] = 'I cannot untrust this user because they have already been kicked from this chat.'
- },
- ['upload'] = {
- ['1'] = 'Responda a mensagem do ficheiro que pretende transferir para o servidor. Deve ser <= 20 MB.',
- ['2'] = 'Ficheiro é demasiado grande. Deve ser <= 20 MB.',
- ['3'] = 'Não consegui obter esse ficheiro, é provavelmente muito antigo.',
- ['4'] = 'Ocorreu um erro ao recuperar esse ficheiro.',
- ['5'] = 'Ficheiro transferido para o servidor com sucesso - pode ser encontrado em <code>%s</code>!'
- },
- ['voteban'] = {
- ['1'] = 'Qual utilizador gostaria de abrir uma votação para banir? Pode especificar este utilizador pelo seu @utilizador ou ID numérico.',
- ['2'] = 'Não consigo criar uma votação para este utilizador porque ele é um moderador ou administrador neste grupo.',
- ['3'] = 'Não consigo criar uma votação para este utilizador porque ele já deixaram (ou foi expulso) deste grupo.',
- ['4'] = '%s [%s] deve ser banido por %s? %s voto a favor para banir imediatamente, e %s votos contra para fechar esta votação.',
- ['5'] = 'Sim [%s]',
- ['6'] = 'Não [%s]',
- ['7'] = 'O povo falou. E baniu %s [%s] por %s porque %s pessoas votaram a favor.',
- ['8'] = 'O montante de votos a favor necessários foi atingido, no entanto, não foi pode banir %s - talvez deixou o grupo ou foi promovido desde que abrimos a votação para banir? É isso ou não tenho mais os privilégios administrativos necessários para executar esta ação!',
- ['9'] = 'O povo falou. E não foi banido %s [%s] por %s porque %s pessoa decidiram votar contra.',
- ['10'] = 'Votou a favor na decisão de banir %s [%s]!',
- ['11'] = 'O seu voto atual foi retirado, use os botões novamente para reenviar o seu voto.',
- ['12'] = 'Votou contra na decisão de banir %s [%s]!',
- ['13'] = 'A vote-ban has already been opened for this user!'
- },
- ['weather'] = {
- ['1'] = 'Ainda não tem uma localização definida. Use /setloc <localização> para definir uma.',
- ['2'] = 'Está atualmente %s (parece %s) em %s. %s'
- },
- ['welcome'] = {
- ['1'] = 'Group Rules'
- },
- ['allowlist'] = {
- ['1'] = 'Qual utilizador gostaria de adicionar a lista branca? Pode especificar este utilizador pelo seu @utilizador ou ID numérico.',
- ['2'] = 'Não consigo adicionar a lista branca esse utilizador porque ele é um moderador ou administrador neste grupo.',
- ['3'] = 'Não consigo adicionar a lista branca esse utilizador porque ele já deixou este grupo.',
- ['4'] = 'Não consigo adicionar a lista branca esse utilizador porque ele já foi banido neste grupo.'
- },
- ['wikipedia'] = {
- ['1'] = 'Ver mais.'
- },
- ['youtube'] = {
- ['1'] = 'Anterior',
- ['2'] = 'Seguinte',
- ['3'] = 'Está na pagina %s de %s!'
- }
-}
\ No newline at end of file
diff --git a/languages/scottish.lua b/languages/scottish.lua
deleted file mode 100644
index 34e7f2f..0000000
--- a/languages/scottish.lua
+++ /dev/null
@@ -1,735 +0,0 @@
--- This is a language file for mattata
--- Language: scottish
--- Author: LKD70
-
--- DO NOT CHANGE ANYTHING THAT BEGINS OR ENDS WITH A %
--- THESE ARE PLACEHOLDERS!
-
--- DO NOT CHANGE ANY MARKDOWN/HTML FORMATTING!
--- IF YOU ARE UNSURE, ASK ON TELEGRAM (t.me/mattataDev)
-
-return {
- ['errors'] = {
- ['connection'] = 'Connection mistak.',
- ['results'] = 'A coudna airt oot ony results for that.',
- ['supergroup'] = 'This commaund can anely be used in supergruips.',
- ['admin'] = 'Ye need tae be a moderator ore an administrator in thes tauk in maun tae use thes commaund.',
- ['unknown'] = 'A daena recognise that usar. If ye wud like tae lear me who thei be, forrit a message from them tae any tauk that Am in.',
- ['generic'] = 'A mistak occured!',
- ['use'] = 'You are not allowed to use this!',
- ['private'] = 'You can only use this command in private chat!'
- },
- ['addcommand'] = {
- ['1'] = 'Please specify the command in the format <code>/command - description</code>',
- ['2'] = 'I couldn\'t retrieve my commands!',
- ['3'] = 'The command description can\'t be longer than 256 characters!',
- ['4'] = 'An unknown error occurred! I couldn\'t add your command!',
- ['5'] = 'Success! Command added.'
- },
- ['addrule'] = {
- ['1'] = 'Please specify the rule you would like to add!',
- ['2'] = 'You don\'t have any rules to add to! Please set group rules using /setrules!',
- ['3'] = 'I couldn\'t add that rule, as it would make the length of the rules longer than Telegram\'s 4096 character limit!',
- ['4'] = 'I couldn\'t add that rule, it appears it contains invalid Markdown formatting!',
- ['5'] = 'Successfully updated the rules!'
- },
- ['addslap'] = {
- ['1'] = 'You can only use this command in groups!',
- ['2'] = 'The slap cannot contain curly braces apart from placeholders!',
- ['3'] = 'The slap cannot be any longer than 256 characters in length!',
- ['4'] = 'I\'ve successfully added that slap as a possibility for /slap in this group!',
- ['5'] = 'You must include placeholders in your slap. Use {ME} for the person executing and {THEM} for the victim.'
- },
- ['administration'] = {
- ['1'] = 'Enable Administration',
- ['2'] = 'Disable Administration',
- ['3'] = 'Anti-Spam Settings',
- ['4'] = 'Warning Settings',
- ['5'] = 'Vote-Ban Settings',
- ['6'] = 'Welcome New Users?',
- ['7'] = 'Send Rules On Join?',
- ['8'] = 'Send Rules In Group?',
- ['9'] = 'Back',
- ['10'] = 'Next',
- ['11'] = 'Word Filter',
- ['12'] = 'Anti-Bot',
- ['13'] = 'Anti-Link',
- ['14'] = 'Log Actions?',
- ['15'] = 'Anti-RTL',
- ['16'] = 'Anti-Spam Action',
- ['17'] = 'Ban',
- ['18'] = 'Kick',
- ['19'] = 'Delete Commands?',
- ['20'] = 'Force Group Language?',
- ['21'] = 'Send Settings In Group?',
- ['22'] = 'Delete Reply On Action?',
- ['23'] = 'Require Captcha?',
- ['24'] = 'Use Inline Captcha?',
- ['25'] = 'Ban SpamWatch-flagged users?',
- ['26'] = 'Number of warnings until %s:',
- ['27'] = 'Upvotes needed to ban:',
- ['28'] = 'Downvotes needed to dismiss:',
- ['29'] = 'Deleted %s, and its matching link from the database!',
- ['30'] = 'There were no entries found in the database matching "%s"!',
- ['31'] = 'You\'re not an administrator in that chat!',
- ['32'] = 'The minimum number of upvotes required for a vote-ban is %s.',
- ['33'] = 'The maximum number of upvotes required for a vote-ban is %s.',
- ['34'] = 'The minimum number of downvotes required for a vote-ban is %s.',
- ['35'] = 'The maximum number of downvotes required for a vote-ban is %s.',
- ['36'] = 'The maximum number of warnings is %s.',
- ['37'] = 'The minimum number of warnings is %s.',
- ['38'] = 'You can add one or more words to the word filter by using /filter <word(s)>',
- ['39'] = 'You will no longer be reminded that the administration plugin is disabled. To enable it, use /administration.',
- ['40'] = 'That\'s not a valid chat!',
- ['41'] = 'You don\'t appear to be an administrator in that chat!',
- ['42'] = 'My administrative functionality can only be used in groups/channels! If you\'re looking for help with using my administrative functionality, check out the "Administration" section of /help! Alternatively, if you wish to manage the settings for a group you administrate, you can do so here by using the syntax /administration <chat>.',
- ['43'] = 'Use the keyboard below to adjust the administration settings for <b>%s</b>:',
- ['44'] = 'Please send me a [private message](https://t.me/%s), so that I can send you this information.',
- ['45'] = 'I have sent you the information you requested via private chat.',
- ['46'] = 'Remove Channel Pins?',
- ['47'] = 'Remove Other Pins?',
- ['48'] = 'Remove Pasted Code?',
- ['49'] = 'Prevent Inline Bots?',
- ['50'] = 'Kick Media On Join?',
- ['51'] = 'Enable Plugins For Admins?',
- ['52'] = 'Kick URLs On Join?'
- },
- ['afk'] = {
- ['1'] = 'Sorry, Am afraid thes feature is anely available tae usars with a public @usarname!',
- ['2'] = '%s has returned after being awa for %s!',
- ['3'] = 'Jot',
- ['4'] = '%s is now awa.%s'
- },
- ['antispam'] = {
- ['1'] = 'Disable',
- ['2'] = 'Enable',
- ['3'] = 'Disable limit',
- ['4'] = 'Enable limits on %s',
- ['5'] = 'All Administration Settings',
- ['6'] = '%s [%s] has kicked %s [%s] from %s [%s] for hitting the configured anti-spam limit for [%s] media.',
- ['7'] = 'Kicked %s for hitting the configured antispam limit for [%s] media.',
- ['8'] = 'The maximum limit is 100.',
- ['9'] = 'The minimum limit is 1.',
- ['10'] = 'Modify the anti-spam settings for %s below:',
- ['11'] = 'Hey %s, if you\'re going to send code that is longer than %s characters in length, please do so using /paste in <a href="https://t.me/%s">private chat with me</a>!',
- ['12'] = '%s <code>[%s]</code> has %s %s <code>[%s]</code> from %s <code>[%s]</code> for sending Telegram invite link(s).\n#chat%s #user%s',
- ['13'] = '%s %s for sending Telegram invite link(s).',
- ['14'] = 'Hey, I noticed you\'ve got anti-link enabled and you\'re currently not allowing your users to mention a chat you\'ve just mentioned, if you\'d like to allowlist it, use /allowlink <links>.',
- ['15'] = 'Kicked %s <code>[%s]</code> from %s <code>[%s]</code> for sending media within their first few messages.\n#chat%s #user%s',
- ['16'] = 'Kicked %s <code>[%s]</code> from %s <code>[%s]</code> for sending a URL within their first few messages.\n#chat%s #user%s',
- ['17'] = 'Action',
- ['18'] = 'Kick',
- ['19'] = 'Ban',
- ['20'] = 'Mute'
- },
- ['appstore'] = {
- ['1'] = 'veu on iTunes',
- ['2'] = 'rating',
- ['3'] = 'ratings'
- },
- ['authspotify'] = {
- ['1'] = 'You are already authorised using that account.',
- ['2'] = 'Authorising, please wait...',
- ['3'] = 'A connection error occured. Are you sure you replied with the correct link? It should look like',
- ['4'] = 'Successfully authorised your Spotify account!'
- },
- ['avatar'] = {
- ['1'] = 'A coudna get the profile photaes for that usar, pleese mak siccar ye specified a valid usarname ore numerical ID.',
- ['2'] = 'That usar daesna have any profile photos.',
- ['3'] = 'That usar daesna have that many profile photaes!',
- ['4'] = 'That user has opted-out of data-collecting functionality, therefore I am not able to show you any of their profile photos.',
- ['5'] = 'User: %s\nPhoto: %s/%s\nSend /avatar %s [offset] to @%s to view a specific photo of this user',
- ['6'] = 'User: %s\nPhoto: %s/%s\nUse /avatar %s [offset] to view a specific photo of this user'
- },
- ['ban'] = {
- ['1'] = 'Which usar wud ye like me tae ban? Ye can specify thes usar by thair @usarname ore numerical ID.',
- ['2'] = 'A cannae ban thes usar becawis thei be a moderator ore an administrator in thes tauk.',
- ['3'] = 'A cannae ban thes usar becawis thei have alrady left thes tauk.',
- ['4'] = 'A cannae ban thes usar becawis thei have alrady been banned from thes tauk.',
- ['5'] = 'A need tae have administrative permissions in maun tae ban thes usar. Pleese mend thes issue, and pree again.',
- ['6'] = '%s <code>[%s]</code> has banned %s <code>[%s]</code> from %s <code>[%s]</code>%s.\n%s %s',
- ['7'] = '%s has banned %s%s.'
- },
- ['bash'] = {
- ['1'] = 'Pleese specify a commaund tae run!',
- ['2'] = 'Success!'
- },
- ['blocklist'] = {
- ['1'] = 'Which usar wud ye like me tae blocklist? Ye can specify thes usar by thair @usarname ore numerical ID.',
- ['2'] = 'A cannae blocklist thes usar becawis thei be a moderator ore an administrator in thes tauk.',
- ['3'] = 'A cannae blocklist thes usar becawis thei have alrady left thes tauk.',
- ['4'] = 'A cannae blocklist thes usar becawis thei have alrady been banned from thes tauk.',
- ['5'] = '%s <code>[%s]</code> has blocklisted %s <code>[%s]</code> from using %s <code>[%s]</code> in %s <code>[%s]</code>%s.\n%s %s',
- ['6'] = '%s has blocklisted %s from using %s%s.'
- },
- ['blocklistchat'] = {
- ['1'] = '%s has now been blocklisted, and A will leave whenever A am added there!',
- ['2'] = '%s is a usar, thes commaund is anely for blocklisting tauks such as gruips and channels!',
- ['3'] = '%s daesna appeir tae be a valid tauk!'
- },
- ['bugreport'] = {
- ['1'] = 'Success! Your bug report has been sent. The ID of thes report is #%s.',
- ['2'] = 'There was a problem whilst reporting that bug! Ha, the irony!'
- },
- ['calc'] = {
- ['1'] = 'Click tae send the result.',
- ['2'] = '"%s" was an unexpected word!',
- ['3'] = 'You cannot have a unit before a number!'
- },
- ['captionbotai'] = {
- ['1'] = 'A really cannae describe that picture!'
- },
- ['cats'] = {
- ['1'] = 'Meow!'
- },
- ['channel'] = {
- ['1'] = 'Ye be not allowed tae use thes!',
- ['2'] = 'Ye daena appeir tae be an administrator in that tauk anymore!',
- ['3'] = 'A coudna send yer message, be ye sure A still have permission tae send messages in that tauk?',
- ['4'] = 'Your message has been sent!',
- ['5'] = 'A was unable tae retrieve a list of administrators for that tauk!',
- ['6'] = 'Ye daena appeir tae be an administrator in that tauk!',
- ['7'] = 'Pleese specify the message tae send, using the syntax /channel <channel> <message>.',
- ['8'] = 'Are ye sure ye want tae send thes message? This is how it will look:',
- ['9'] = 'Yes, Am sure!',
- ['10'] = 'That message contains invalid Markdoun formatting! Pleese correct yer syntax and pree again.'
- },
- ['chatroulette'] = {
- ['1'] = 'Hey! Please don\'t send messages longer than %s characters. We don\'t want to annoy the other user!',
- ['2'] = '*Anonymous said:*\n```\n%s\n```\nTo end your session, send /endchat.',
- ['3'] = 'I\'m afraid I lost connection from the other user! To begin a new chat, please send /chatroulette!',
- ['4'] = 'The other person you were chatting with has ended the session. To start a new one, send /chatroulette.',
- ['5'] = 'Successfully ended your session. To start a new one, send /chatroulette.',
- ['6'] = 'I have successfully removed you from the list of available users.',
- ['7'] = 'You don\'t have a session set up at the moment. To start one, send /chatroulette.',
- ['8'] = 'Finding you a session, please wait...',
- ['9'] = 'I\'m afraid there aren\'t any available users right now, but I have added you to the list of available users! To stop this completely, please send /endchat.',
- ['10'] = 'I have successfully paired you with another user to chat to! Please remember to be kind to them! To end the chat, send /endchat.',
- ['11'] = 'I\'m afraid the user who I tried to pair you with has since blocked me. Please try and send /chatroulette again to try and connect to me!',
- ['12'] = 'I have successfully paired you with another user to chat to! Please remember to be kind to them! To end the chat, send /endchat.'
- },
- ['commandstats'] = {
- ['1'] = 'No commands have been sent in this chat!',
- ['2'] = '<b>Command statistics for:</b> %s\n\n%s\n<b>Total commands sent:</b> %s',
- ['3'] = 'The command statistics for this chat have been reset!',
- ['4'] = 'I could not reset the command statistics for this chat. Perhaps they have already been reset?'
- },
- ['control'] = {
- ['1'] = 'Pfft, ye wish!',
- ['2'] = '%s is reloading...'
- },
- ['copypasta'] = {
- ['1'] = 'The replied-to text musn\'t be any longer than %s characters!'
- },
- ['coronavirus'] = {
- ['1'] = [[*COVID-19 Statistics for:* %s
-
-*New confirmed cases:* %s
-*Total confirmed cases:* %s
-*New deaths:* %s
-*Total deaths:* %s
-*New recovered cases:* %s
-*Total recovered cases:* %s]]
- },
- ['counter'] = {
- ['1'] = 'A coudna add a cownter tae that message!'
- },
- ['custom'] = {
- ['1'] = 'Success! That message will now be sent every time somebody uses %s!',
- ['2'] = 'The trigger "%s" does not exist!',
- ['3'] = 'The trigger "%s" has been deleted!',
- ['4'] = 'Ye daena have any custom triggers set!',
- ['5'] = 'Custom commands for %s:\n',
- ['6'] = 'To create a new, custom commaund, use the following syntax:\n/custom new #trigger <value>. tae list all current triggers, use /custom list. tae delete a trigger, use /custom del #trigger.'
- },
- ['delete'] = {
- ['1'] = 'I could not delete that message. Perhaps the message is too old or non-existent?'
- },
- ['demote'] = {
- ['1'] = 'Which usar wud ye like me tae demote? Ye can specify thes usar by thair @usarname ore numerical ID.',
- ['2'] = 'A cannae demote thes usar becawis thei be not a moderator ore an administrator in thes tauk.',
- ['3'] = 'A cannae demote thes usar becawis thei have alrady left thes tauk.',
- ['4'] = 'A cannae demote thes usar becawis thei have alrady been kicked from thes tauk.'
- },
- ['doge'] = {
- ['1'] = 'Pleese enter the text ye want tae Doge-ify. Each sentence should be separated using slashes ore new lines.'
- },
- ['donate'] = {
- ['1'] = '<b>Hello, %s!</b>\n\nIf you\'re feeling generous, you can contribute to the mattata project by making a monetary donation of any amount. This will go towards server costs and any time and resources used to develop mattata. This is an optional act, however it is greatly appreciated and your name will also be listed publically on mattata\'s GitHub page.\n\nIf you\'re still interested, you can donate <a href="https://paypal.me/wrxck">here</a>. Thank you for your continued support!'
- },
- ['exec'] = {
- ['1'] = 'Pleese select the language ye wud like tae execute yer code in:',
- ['2'] = 'A mistak occured! The connection timed-out. Were ye preeing tae make me lag?',
- ['3'] = 'Ye have selected "%s" – be ye sure?',
- ['4'] = 'Back',
- ['5'] = 'Am sure',
- ['6'] = 'Pleese enter a snippet of code that ye wud like tae run. Ye daena need tae specify the language, we will do that afterwards!',
- ['7'] = 'Pleese select the language ye wud like tae execute yer code in:'
- },
- ['facebook'] = {
- ['1'] = 'A mistak occured!',
- ['2'] = 'Pleese enter the name of the Facebook usar ye wud like tae get the profile picture of.',
- ['3'] = 'veu @%s on Facebook'
- },
- ['fact'] = {
- ['1'] = 'Generate Another'
- },
- ['fban'] = {
- ['1'] = 'Which user would you like me to Fed-ban? You can specify this user by their @username or numerical ID.',
- ['2'] = 'I cannot Fed-ban this user because they are a moderator or an administrator in this chat.'
- },
- ['flickr'] = {
- ['1'] = 'Ye serched for:',
- ['2'] = 'Pleese enter a serch query (that is, what ye want me tae serch Flickr for, i.e. "Big Ben" will return a photograph of Big Ben in London).',
- ['3'] = 'More Results'
- },
- ['game'] = {
- ['1'] = 'Total wyns: %s\nTotal losses: %s\nBalance: %s mattacoins',
- ['2'] = 'Join Gemm',
- ['3'] = 'This gemm has alrady ended!',
- ['4'] = 'It\'s not yer turn!',
- ['5'] = 'Ye be not part of thes gemm!',
- ['6'] = 'Ye cannae go here!',
- ['7'] = 'Ye be alrady part of thes gemm!',
- ['8'] = 'This gemm has alrady started!',
- ['9'] = '%s [%s] is playing against %s [%s]\nIt is currently %s\'s turn!',
- ['10'] = '%s won the gemm against %s!',
- ['11'] = '%s drew the gemm against %s!',
- ['12'] = 'Waiting for opponent...',
- ['13'] = 'Tic-Tac-Toe',
- ['14'] = 'Click tae send the gemm tae yer tauk!',
- ['15'] = 'Statistics for %s:\n',
- ['16'] = 'Play Tic-Tac-Toe!'
- },
- ['gblocklist'] = {
- ['1'] = 'Pleese reply-to the usar ye\'d like tae globally blocklist, ore specify them by usarname/ID.',
- ['2'] = 'A coudna get information about "%s", pleese check it\'s a valid usarname/ID and pree again.',
- ['3'] = 'That\'s a %s, not a usar!'
- },
- ['gif'] = {
- ['1'] = 'Pleese enter a serch query (that is, what ye want me tae serch GIPHY for, i.e. "cat" will return a GIF of a cat).'
- },
- ['gallowlist'] = {
- ['1'] = 'Pleese reply-to the usar ye\'d like tae globally allowlist, ore specify them by usarname/ID.',
- ['2'] = 'A coudna get information about "%s", pleese check it\'s a valid usarname/ID and pree again.',
- ['3'] = 'That\'s a %s, not a usar!'
- },
- ['hackernews'] = {
- ['1'] = 'Top Stories from Hacker News:'
- },
- ['help'] = {
- ['1'] = 'No results found!',
- ['2'] = 'There were no features found matching "%s", pleese pree and be more specific!',
- ['3'] = '\n\nArguments: <required> [optional]\n\nSerch for a feature ore get help with a commaund by using my inline serch functionality - just mention me in any tauk using the syntax @%s <serch query>.',
- ['4'] = 'Previous',
- ['5'] = 'Next',
- ['6'] = 'Back',
- ['7'] = 'Serch',
- ['8'] = 'Ye be on page %s of %s!',
- ['9'] = [[
-A can perform many administrative actions in yer gruips, just add me as an administrator and send /administration tae adjust the settings for yer gruip.
-Here be some administrative commands and a brief comment regarding what thei do:
-
-• /pin <text> - Send a Markdoun-formatted message which can be edited by using the same commaund with different text, tae save ye from having tae re-pin a message if ye can't edit it (which happens if the message is older than 48 hours)
-
-• /ban - Ban a usar by replying tae one of thair messages, ore by specifying them by usarname/ID
-
-• /kick - Kick (ban and then unban) a usar by replying tae one of thair messages, ore by specifying them by usarname/ID
-
-• /unban - Unban a usar by replying tae one of thair messages, ore by specifying them by usarname/ID
-
-• /setrules <text> - Set the given Markdoun-formatted text as the gruip rules, which will be sent whenever somebody uses /rules
- ]],
- ['10'] = [[
-• /setwelcome - Set the given Markdoun-formatted text as a welcome message that will be sent every time a usar joins yer gruip (the welcome message can be disabled in the administration menu, accessible via /administration). Ye can use placeholders tae automatically customise the welcome message for each usar. Use $usar\_id tae insert the usar's numerical ID, $chat\_id tae insert the tauk's numerical ID, $name tae insert the usar's name, $title tae insert the tauk title and $usarname tae insert the usar's usarname (if the usar doesn't have an @usarname, thair name will be used instead, so it is best tae avoid using thes with $name)
-
-• /warn - Warn a usar, and ban them when thei hit the maximum number of warnings
-
-• /mod - Promote the replied-to usar, giving them access tae administrative commands such as /ban, /kick, /warn etc. (this is useful when ye don't want somebody tae have the ability tae delete messages!)
-
-• /demod - Demote the replied-to usar, stripping them from thair moderation status and revoking thair ability tae use administrative commands
-
-• /staff - veu the gruip's creator, administrators, and moderators in a neatly-formatted list
- ]],
- ['11'] = [[
-• /report - Forwards the replied-to message tae all administrators and alerts them of the current situation
-
-• /setlink <URL> - Set the gruip's link tae the given URL, which will be sent whenever somebody uses /link
-
-• /links <text> - Allowlists all of the Telegram links found in the given text (includes @usarname links)
- ]],
- ['12'] = 'Below be some links ye might find useful:',
- ['13'] = 'Development',
- ['14'] = 'Channel',
- ['15'] = 'Support',
- ['16'] = 'FAQ',
- ['17'] = 'Source',
- ['18'] = 'Donate',
- ['19'] = 'Rate',
- ['20'] = 'Administration Log',
- ['21'] = 'Admin Settings',
- ['22'] = 'Plugins',
- ['23'] = [[
-<b>Hi %s! My name's %s, it's a pleasure tae meet ye</b> %s
-
-A understand many commands, which ye can learn more about by pressing the "Commands" button using the attached keyboard.
-
-%s <b>Tip:</b> Use the "Settings" button tae change how A work%s!
-
-%s <b>Find me useful, or just want to help?</b> Donations are very much appreciated, use /donate for more information!
- ]],
- ['24'] = 'in'
- },
- ['id'] = {
- ['1'] = 'Am sorry, but A daena recognise that usar. tae lear me who thei be, forrit a message from them tae me ore get them tae send me a message.',
- ['2'] = 'Queried Chat:',
- ['3'] = 'This Chat:',
- ['4'] = 'Click tae send the result!'
- },
- ['imdb'] = {
- ['1'] = 'Previous',
- ['2'] = 'Next',
- ['3'] = 'Ye be on page %s of %s!'
- },
- ['import'] = {
- ['1'] = 'A daena recognise that tauk!',
- ['2'] = 'That\'s not a supergruip, therefore A cannae import any settings from it!',
- ['3'] = 'Successfully imported administrative settings & toggled plugins from %s tae %s!'
- },
- ['info'] = {
- ['1'] = [[
-```
-Redis:
-%s Config File: %s
-%s Mode: %s
-%s TCP Port: %s
-%s Version: %s
-%s Uptime: %s days
-%s Process ID: %s
-%s Expired Keys: %s
-
-%s Usar Cownt: %s
-%s Gruip Cownt: %s
-
-System:
-%s OS: %s
-```
- ]]
- },
- ['instagram'] = {
- ['1'] = '@%s on Instagram'
- },
- ['ipsw'] = {
- ['1'] = '<b>%s</b> iOS %s\n\n<code>MD5 sum: %s\nSHA1 sum: %s\nFile size: %s GB</code>\n\n<i>%s %s</i>',
- ['2'] = 'This firmwhere is no longer being signed!',
- ['3'] = 'This firmwhere is still being signed!',
- ['4'] = 'Pleese select yer model:',
- ['5'] = 'Pleese select yer firmwhere version:',
- ['6'] = 'Pleese select yer device type:',
- ['7'] = 'iPod Touch',
- ['8'] = 'iPhone',
- ['9'] = 'iPad',
- ['10'] = 'Apple TV'
- },
- ['ispwned'] = {
- ['1'] = 'That account was found in the following leaks:'
- },
- ['itunes'] = {
- ['1'] = 'Name:',
- ['2'] = 'Artist:',
- ['3'] = 'Album:',
- ['4'] = 'Track:',
- ['5'] = 'Disc:',
- ['6'] = 'The original query could not be found, ye\'ve probably deleted the original message.',
- ['7'] = 'The artwork can be found below:',
- ['8'] = 'Pleese enter a serch query (that is, what ye want me tae serch iTunes for, i.e. "Green Day American Idiot" will return information about the first result for American Idiot by Green Day).',
- ['9'] = 'Get Album Artwork'
- },
- ['kick'] = {
- ['1'] = 'Which usar wud ye like me tae keek? Ye can specify thes usar by thair @usarname ore numerical ID.',
- ['2'] = 'A cannae keek thes usar becawis thei be a moderator ore an administrator in thes tauk.',
- ['3'] = 'A cannae keek thes usar becawis thei have alrady left thes tauk.',
- ['4'] = 'A cannae keek thes usar becawis thei have alrady been keeked from thes tauk.',
- ['5'] = 'A need tae have administrative permissions in maun tae keek thes usar. Pleese amend thes issue, and pree again.'
- },
- ['lastfm'] = {
- ['1'] = '%s\'s last.fm usarname has been set tae "%s".',
- ['2'] = 'Your last.fm usarname has been forgotten!',
- ['3'] = 'Ye daena currently have a last.fm usarname set!',
- ['4'] = 'Pleese specify yer last.fm usarname ore set it with /fmset.',
- ['5'] = 'No history was found for thes usar.',
- ['6'] = '%s is currently listening to:\n',
- ['7'] = '%s last listened to:\n',
- ['8'] = 'Unknown',
- ['9'] = 'Click tae send the result.'
- },
- ['location'] = {
- ['1'] = 'Ye daena have a location set. What wud ye like yer new location tae be?'
- },
- ['logchat'] = {
- ['1'] = 'Pleese enter the usarname ore numerical ID of the tauk ye wish tae log all administrative actions into.',
- ['2'] = 'Checking tae see whether that tauk is valid...',
- ['3'] = 'Am sorry, it appeirs ye\'ve either specified an invalid tauk, ore ye\'ve specified a tauk A haven\'t been added tae yet. Pleese rectify thes and pree again.',
- ['4'] = 'Ye can\'t set a usar as yer log tauk!',
- ['5'] = 'Ye daena appeir tae be an administrator in that tauk!',
- ['6'] = 'It seems Am alrady logging administrative actions into that tauk! Use /logchat tae specify a new one.',
- ['7'] = 'That tauk is valid, Am now going tae pree and send a test message tae it, just tae ensure A have permission tae post!',
- ['8'] = 'Hello, World - thes is a test message tae check my posting permissions - if ye\'re reading thes, then everything went OK!',
- ['9'] = 'All done! From now on, any administrative actions in thes tauk will be logged into %s - tae change the tauk ye want me tae log administrative actions into, just send /logchat.'
- },
- ['lua'] = {
- ['1'] = 'Pleese enter a string of Lua tae execute!'
- },
- ['lyrics'] = {
- ['1'] = 'Spotify',
- ['2'] = 'Show Lyrics',
- ['3'] = 'Pleese enter a serch query (that is, what song/artist/lyrics ye want me tae get lyrics for, i.e. "Green Day Basket Case" will return the lyrics for the song Basket Case by Green Day).'
- },
- ['minecraft'] = {
- ['1'] = '<b>%s has changed his/her usarname %s time</b>',
- ['2'] = '<b>%s has changed his/her usarname %s times</b>',
- ['3'] = 'Previous',
- ['4'] = 'Next',
- ['5'] = 'Back',
- ['6'] = 'UUID',
- ['7'] = 'Avatar',
- ['8'] = 'Usarname History',
- ['9'] = 'Pleese select an option:',
- ['10'] = 'Pleese enter the usarname of the Minecraft player ye wud like tae view information about (i.e. sending "Notch" will view information about the player Notch).',
- ['11'] = 'Minecraft usarnames be between 3 and 16 characters long.'
- },
- ['mute'] = {
- ['1'] = 'Which user would you like me to mute? You can specify this user by their @username or numerical ID.',
- ['2'] = 'I cannot mute this user because they are already muted in this chat.',
- ['3'] = 'I cannot mute this user because they are a moderator or an administrator in this chat.',
- ['4'] = 'I cannot mute this user because they have already left (or been kicked from) this chat.',
- ['5'] = 'I need to have administrative permissions in order to mute this user. Please amend this issue, and try again.'
- },
- ['myspotify'] = {
- ['1'] = 'Profile',
- ['2'] = 'Following',
- ['3'] = 'Recently Played',
- ['4'] = 'Currently Playing',
- ['5'] = 'Top Tracks',
- ['6'] = 'Top Artists',
- ['7'] = 'You don\'t appear to be following any artists!',
- ['8'] = 'Your Top Artists',
- ['9'] = 'You don\'t appear to have any tracks in your library!',
- ['10'] = 'Your Top Tracks',
- ['11'] = 'You don\'t appear to be following any artists!',
- ['12'] = 'Artists You Follow',
- ['13'] = 'You don\'t appear to have recently played any tracks!',
- ['14'] = '<b>Recently Played</b>\n%s %s\n%s %s\n%s Listened to at %s:%s on %s/%s/%s.',
- ['15'] = 'The request has been accepted for processing, but the processing has not been completed.',
- ['16'] = 'You don\'t appear to be listening to anything right now!',
- ['17'] = 'Currently Playing',
- ['18'] = 'An error occured whilst re-authorising your Spotify account!',
- ['19'] = 'Successfully re-authorised your Spotify account! Processing your original request...',
- ['20'] = 'Re-authorising your Spotify account, please wait...',
- ['21'] = 'You need to authorise mattata in order to connect your Spotify account. Click [here](https://accounts.spotify.com/en/authorize?client_id=%s&response_type=code&redirect_uri=%s&scope=user-library-read,playlist-read-private,playlist-read-collaborative,user-read-private,user-read-email,user-follow-read,user-top-read,user-read-playback-state,user-read-recently-played,user-read-currently-playing,user-modify-playback-state) and press the green "OKAY" button to link mattata to your Spotify account. After you\'ve done that, send the link you were redirected to (it should begin with "%s", followed by a unique code) in reply to this message.',
- ['22'] = 'Playlists',
- ['23'] = 'Use Inline Mode',
- ['24'] = 'Lyrics',
- ['25'] = 'No devices were found.',
- ['26'] = 'You don\'t appear to have any playlists.',
- ['27'] = 'Your Playlists',
- ['28'] = '%s %s [%s tracks]',
- ['29'] = '%s %s [%s]\nSpotify %s user\n\n<b>Devices:</b>\n%s',
- ['30'] = 'Playing previous track...',
- ['31'] = 'You are not a premium user!',
- ['32'] = 'I could not find any devices.',
- ['33'] = 'Playing next track...',
- ['34'] = 'Resuming track...',
- ['35'] = 'Your device is temporarily unavailable...',
- ['36'] = 'No devices were found!',
- ['37'] = 'Pausing track...',
- ['38'] = 'Now playing',
- ['39'] = 'Shuffling your music...',
- ['40'] = 'That\'s not a valid volume. Please specify a number between 0 and 100.',
- ['41'] = 'The volume has been set to %s%%!',
- ['42'] = 'This message is using an old version of this plugin, please request a new one by sending /myspotify!'
- },
- ['name'] = {
- ['1'] = 'The name A currently respond tae is "%s" - tae change thes, use /name <text> (where <text> is what ye want me tae respond to).',
- ['2'] = 'My new name needs tae be between 2 and 32 characters long!',
- ['3'] = 'My name may anely contain alphanumeric characters!',
- ['4'] = 'A will now respond tae "%s", instead of "%s" - tae change thes, use /name <text> (where <text> is what ye want me tae respond to).'
- },
- ['netflix'] = {
- ['1'] = 'Read more.'
- },
- ['news'] = {
- ['1'] = '"<code>%s</code>" isn\'t a valid Lua pattern.',
- ['2'] = 'A coudna retrieve a list of sources.',
- ['3'] = '<b>News sources found matching</b> "<code>%s</code>":\n\n%s',
- ['4'] = '<b>Here be the current available news sources ye can use with</b> /news<b>. Use</b> /nsources &lt;query&gt; <b>to serch the list of news sources for a more specific set of results. Serches be matched using Lua patterns</b>\n\n%s',
- ['5'] = 'Ye daena have a preferred news source. Use /setnews <source> tae set one. veu a list of sources using /nsources, ore narrow doun the results by using /nsources <query>.',
- ['6'] = 'Your current preferred news source is %s. Use /setnews <source> tae change it. veu a list of sources using /nsources, ore narrow doun the results by using /nsources <query>.',
- ['7'] = 'Your preferred source is alrady set tae %s! Use /news tae view the current top story.',
- ['8'] = 'That\'s not a valid news source. veu a list of sources using /nsources, ore narrow doun the results by using /nsources <query>.',
- ['9'] = 'Your preferred news source has been updated tae %s! Use /news tae view the current top story.',
- ['10'] = 'That\'s not a valid source, use /nsources tae view a list of available sources. If ye have a preferred source, use /setnews <source> tae automatically have news from that source sent when ye send /news, without any arguments needed.',
- ['11'] = 'Read more.'
- },
- ['nick'] = {
- ['1'] = 'Your nickname has now been forgotten!',
- ['2'] = 'Your nickname has been set tae "%s"!'
- },
- ['optout'] = {
- ['1'] = 'Ye have opted-in tae having data ye send collected! Use /optout tae opt-out.',
- ['2'] = 'Ye have opted-out of having data ye send collected! Use /optin tae opt-in.'
- },
- ['paste'] = {
- ['1'] = 'Pleese select a service tae upload yer paste to:'
- },
- ['pin'] = {
- ['1'] = 'You haven\'t set a pin before. Use /pin <text> to set one. Markdown formatting is supported.',
- ['2'] = 'Here is the last message generated using /pin.',
- ['3'] = 'I found an existing pin in the database, but the message I sent it in seems to have been deleted, and I can\'t find it anymore. You can set a new one with /pin <text>. Markdown formatting is supported.',
- ['4'] = 'There was an error whilst updating your pin. Either the text you entered contained invalid Markdown syntax, or the pin has been deleted. I\'m now going to try and send you a new pin, which you\'ll be able to find below - if you need to modify it then, after ensuring the message still exists, use /pin <text>.',
- ['5'] = 'I couldn\'t send that text because it contains invalid Markdown syntax.',
- ['6'] = 'Click here to see the pin, updated to contain the text you gave me.'
- },
- ['pokedex'] = {
- ['1'] = 'Name: %s\nID: %s\nType: %s\nDescription: %s'
- },
- ['promote'] = {
- ['1'] = 'A cannae promote thes usar becawis thei be a moderator ore an administrator of thes tauk.',
- ['2'] = 'A cannae promote thes usar becawis thei have alrady left thes tauk.',
- ['3'] = 'A cannae promote thes usar becawis thei have alrady been kicked from thes tauk.'
- },
- ['quote'] = {
- ['1'] = 'This usar has opted out of data-storing functionality.',
- ['2'] = 'There be no saved quotes for %s! Ye can save one by using /save in reply tae a message thei send.'
- },
- ['report'] = {
- ['1'] = 'Please reply to the message you would like to report to the group\'s administrators.',
- ['2'] = 'You can\'t report your own messages, are you just trying to be funny?',
- ['3'] = '<b>%s needs help in %s!</b>',
- ['4'] = 'Click here to view the reported message.',
- ['5'] = 'I\'ve successfully reported that message to %s admin(s)!'
- },
- ['save'] = {
- ['1'] = 'This usar has opted out of data-storing functionality.',
- ['2'] = 'That message has been saved in my database, and added tae the list of possible responses for when /quote is used in reply tae %s!'
- },
- ['sed'] = {
- ['1'] = '%s\n\n<i>%s didn\'t mean tae say thes!</i>',
- ['2'] = '%s\n\n<i>%s has admitted defeat.</i>',
- ['3'] = '%s\n\n<i>%s isn\'t sure if thei were mistaken...</i>',
- ['4'] = 'Screw ye, <i>when am A ever wrong?</i>',
- ['5'] = '"<code>%s</code>" isn\'t a valid Lua pattern.',
- ['6'] = 'Hey %s, %s seems to think you meant:\n<i>%s</i>',
- ['7'] = 'Yes',
- ['8'] = 'No',
- ['9'] = 'Not sure',
- ['10'] = 'Just edit your message, idiot.'
- },
- ['setgrouplang'] = {
- ['1'] = 'This group\'s language has been set to %s!',
- ['2'] = 'This group\'s language is currently %s.\nPlease note that some strings may not be translated as of yet. If you\'d like to change your language, select one using the keyboard below:',
- ['3'] = 'The option to force users to use the same language in this group is currently disabled. This setting should be toggled from /administration but, to make things easier for you, I\'ve included a button below.',
- ['4'] = 'Enable',
- ['5'] = 'Disable'
- },
- ['setlang'] = {
- ['1'] = 'Your language has been set tae %s!',
- ['2'] = 'Your language is currently %s.\nPleese note that some strings may not be translated as of yet. If ye\'d like tae change yer language, select one using the keyboard below:'
- },
- ['setlink'] = {
- ['1'] = 'That\'s not a valid URL.',
- ['2'] = 'Link set successfully!'
- },
- ['setrules'] = {
- ['1'] = 'Invalid Markdown formatting.',
- ['2'] = 'Successfully set the new rules!'
- },
- ['setwelcome'] = {
- ['1'] = 'What wud ye like the welcome message tae be? The text ye specify will be Markdoun-formatted and sent every time a usar joins the tauk (the welcome message can be disabled in the administration menu, accessible via /administration). Ye can use placeholders tae automatically customise the welcome message for each usar. Use $usar_id tae insert the usar\'s numerical ID, $chat_id tae insert the tauk\'s numerical ID, $name tae insert the usar\'s name, $title tae insert the tauk\'s title and $usarname tae insert the usar\'s usarname (if the usar daesna have an @usarname, thair name will be used instead, so it is best tae avoid using thes in conjunction with $name).',
- ['2'] = 'There was a mistak formatting yer message, pleese check yer Markdoun syntax and pree again.',
- ['3'] = 'The welcome message for %s has successfully been updated!'
- },
- ['share'] = {
- ['1'] = 'Shbe'
- },
- ['shorten'] = {
- ['1'] = 'Pleese select a URL shortener using the buttons below:'
- },
- ['shsh'] = {
- ['1'] = 'A coudna fetch any SHSH blobs for that ECID, pleese ensure it\'s valid and ye have saved them using https://tsssaver.1conan.com.',
- ['2'] = 'SHSH blobs for that device be available for the following versions of iOS:\n',
- ['3'] = 'Dounload .zip'
- },
- ['statistics'] = {
- ['1'] = 'No messages have been sent in this chat!',
- ['2'] = '<b>Statistics for:</b> %s\n\n%s\n<b>Total messages sent:</b> %s',
- ['3'] = 'The statistics for this chat have been reset!',
- ['4'] = 'I could not reset the statistics for this chat. Perhaps they have already been reset?'
- },
- ['steam'] = {
- ['1'] = 'Your Steam usarname has been set tae "%s".',
- ['2'] = '"%s" isn\'t a valid Steam usarname.',
- ['3'] = '%s has been a usar on Steam since %s, on %s. They last logged off at %s, on %s. Click <a href="%s">here</a> tae view thair Steam profile.',
- ['4'] = '%s, AKA "%s",'
- },
- ['trust'] = {
- ['1'] = 'I cannot trust this user because they are a moderator or an administrator of this chat.',
- ['2'] = 'I cannot trust this user because they have already left this chat.',
- ['3'] = 'I cannot trust this user because they have already been kicked from this chat.'
- },
- ['unmute'] = {
- ['1'] = 'Which user would you like me to unmute? You can specify this user by their @username or numerical ID.',
- ['2'] = 'I cannot unmute this user because they are not currently muted in this chat.',
- ['3'] = 'I cannot unmute this user because they are a moderator or an administrator in this chat.',
- ['4'] = 'I cannot unmute this user because they have already left (or been kicked from) this chat.'
- },
- ['untrust'] = {
- ['1'] = 'Which user would you like me to untrust? You can specify this user by their @username or numerical ID.',
- ['2'] = 'I cannot untrust this user because they are a moderator or an administrator in this chat.',
- ['3'] = 'I cannot untrust this user because they have already left this chat.',
- ['4'] = 'I cannot untrust this user because they have already been kicked from this chat.'
- },
- ['upload'] = {
- ['1'] = 'Pleese reply tae the file ye\'d like tae dounload tae the server. It must be <= 20 MB.',
- ['2'] = 'That file is too large. It must be <= 20 MB.',
- ['3'] = 'A coudna get thes file, it\'s probably too old.',
- ['4'] = 'There was a mistak whilst retrieving thes file.',
- ['5'] = 'Successfully dounloaded the file tae the server - it can be found at <code>%s</code>!'
- },
- ['voteban'] = {
- ['1'] = 'Which user would you like to open up a vote-ban for? You can specify this user by their @username or numerical ID.',
- ['2'] = 'I cannot setup a vote-ban for this user because they are a moderator or an administrator in this chat.',
- ['3'] = 'I cannot setup a vote-ban for this user because they have already left (or been kicked from) this chat.',
- ['4'] = 'Should %s [%s] be banned from %s? %s upvotes are required for an immediate ban, and %s downvotes are required for this vote to be closed.',
- ['5'] = 'Yes [%s]',
- ['6'] = 'No [%s]',
- ['7'] = 'The people have spoken. I have banned %s [%s] from %s because %s people voted for me to do so.',
- ['8'] = 'The required upvote amount was reached, however, I was unable to ban %s - perhaps they\'ve left the group or been promoted since we opened the vote to ban them? It\'s either that, or I no longer have the administrative privileges required in order to perform this action!',
- ['9'] = 'The people have spoken. I haven\'t banned %s [%s] from %s because the required %s people downvoted the decision to ban them.',
- ['10'] = 'You upvoted the decision to ban %s [%s]!',
- ['11'] = 'Your current vote has been retracted, use the buttons again to re-submit your vote.',
- ['12'] = 'You downvoted the decision to ban %s [%s]!',
- ['13'] = 'A vote-ban has already been opened for this user!'
- },
- ['weather'] = {
- ['1'] = 'Ye daena have a location set. Use /setloc <location> tae set one.',
- ['2'] = 'It\'s currently %s (feels like %s) in %s. %s'
- },
- ['welcome'] = {
- ['1'] = 'Group Rules'
- },
- ['allowlist'] = {
- ['1'] = 'Which user would you like me to allowlist? You can specify this user by their @username or numerical ID.',
- ['2'] = 'I cannot allowlist this user because they are a moderator or an administrator in this chat.',
- ['3'] = 'I cannot allowlist this user because they have already left this chat.',
- ['4'] = 'I cannot allowlist this user because they have already been banned from this chat.'
- },
- ['wikipedia'] = {
- ['1'] = 'Read more.'
- },
- ['youtube'] = {
- ['1'] = 'Previous',
- ['2'] = 'Next',
- ['3'] = 'Ye be on page %s of %s!'
- }
-}
\ No newline at end of file
diff --git a/languages/tr_tr.lua b/languages/tr_tr.lua
deleted file mode 100644
index 94e787b..0000000
--- a/languages/tr_tr.lua
+++ /dev/null
@@ -1,735 +0,0 @@
--- This is a language file for mattata
--- Language: tr-tr
--- Author: By_Azade
-
--- DO NOT CHANGE ANYTHING THAT BEGINS OR ENDS WITH A %
--- THESE ARE PLACEHOLDERS!
-
--- DO NOT CHANGE ANY MARKDOWN/HTML FORMATTING!
--- IF YOU ARE UNSURE, ASK ON TELEGRAM (t.me/mattataDev)
-
-return {
- ['errors'] = {
- ['connection'] = 'Bağlantı Hatası',
- ['results'] = 'Bunun için herhangi bir sonuç bulamadım.',
- ['supergroup'] = 'Bu komut sadece grupta kullanılır.',
- ['admin'] = 'Bu komutu kullanabilmeniz için grupta admin veya moderatör olmalısınız.',
- ['unknown'] = 'Bu kullanıcıyı tanımıyorum. Eğer onu bana tanıtmak isterseniz, mesajını bana yönlendirin.',
- ['generic'] = 'Hata oluştu!',
- ['use'] = 'Bunu kullanmanıza izi yok!',
- ['private'] = 'You can only use this command in private chat!'
- },
- ['addcommand'] = {
- ['1'] = 'Please specify the command in the format <code>/command - description</code>',
- ['2'] = 'I couldn\'t retrieve my commands!',
- ['3'] = 'The command description can\'t be longer than 256 characters!',
- ['4'] = 'An unknown error occurred! I couldn\'t add your command!',
- ['5'] = 'Success! Command added.'
- },
- ['addrule'] = {
- ['1'] = 'Please specify the rule you would like to add!',
- ['2'] = 'You don\'t have any rules to add to! Please set group rules using /setrules!',
- ['3'] = 'I couldn\'t add that rule, as it would make the length of the rules longer than Telegram\'s 4096 character limit!',
- ['4'] = 'I couldn\'t add that rule, it appears it contains invalid Markdown formatting!',
- ['5'] = 'Successfully updated the rules!'
- },
- ['addslap'] = {
- ['1'] = 'You can only use this command in groups!',
- ['2'] = 'The slap cannot contain curly braces apart from placeholders!',
- ['3'] = 'The slap cannot be any longer than 256 characters in length!',
- ['4'] = 'I\'ve successfully added that slap as a possibility for /slap in this group!',
- ['5'] = 'You must include placeholders in your slap. Use {ME} for the person executing and {THEM} for the victim.'
- },
- ['administration'] = {
- ['1'] = 'Enable Administration',
- ['2'] = 'Disable Administration',
- ['3'] = 'Anti-Spam Settings',
- ['4'] = 'Warning Settings',
- ['5'] = 'Vote-Ban Settings',
- ['6'] = 'Welcome New Users?',
- ['7'] = 'Send Rules On Join?',
- ['8'] = 'Send Rules In Group?',
- ['9'] = 'Back',
- ['10'] = 'Next',
- ['11'] = 'Word Filter',
- ['12'] = 'Anti-Bot',
- ['13'] = 'Anti-Link',
- ['14'] = 'Log Actions?',
- ['15'] = 'Anti-RTL',
- ['16'] = 'Anti-Spam Action',
- ['17'] = 'Ban',
- ['18'] = 'Kick',
- ['19'] = 'Delete Commands?',
- ['20'] = 'Force Group Language?',
- ['21'] = 'Send Settings In Group?',
- ['22'] = 'Delete Reply On Action?',
- ['23'] = 'Require Captcha?',
- ['24'] = 'Use Inline Captcha?',
- ['25'] = 'Ban SpamWatch-flagged users?',
- ['26'] = 'Number of warnings until %s:',
- ['27'] = 'Upvotes needed to ban:',
- ['28'] = 'Downvotes needed to dismiss:',
- ['29'] = 'Deleted %s, and its matching link from the database!',
- ['30'] = 'There were no entries found in the database matching "%s"!',
- ['31'] = 'You\'re not an administrator in that chat!',
- ['32'] = 'The minimum number of upvotes required for a vote-ban is %s.',
- ['33'] = 'The maximum number of upvotes required for a vote-ban is %s.',
- ['34'] = 'The minimum number of downvotes required for a vote-ban is %s.',
- ['35'] = 'The maximum number of downvotes required for a vote-ban is %s.',
- ['36'] = 'The maximum number of warnings is %s.',
- ['37'] = 'The minimum number of warnings is %s.',
- ['38'] = 'You can add one or more words to the word filter by using /filter <word(s)>',
- ['39'] = 'You will no longer be reminded that the administration plugin is disabled. To enable it, use /administration.',
- ['40'] = 'That\'s not a valid chat!',
- ['41'] = 'You don\'t appear to be an administrator in that chat!',
- ['42'] = 'My administrative functionality can only be used in groups/channels! If you\'re looking for help with using my administrative functionality, check out the "Administration" section of /help! Alternatively, if you wish to manage the settings for a group you administrate, you can do so here by using the syntax /administration <chat>.',
- ['43'] = 'Use the keyboard below to adjust the administration settings for <b>%s</b>:',
- ['44'] = 'Please send me a [private message](https://t.me/%s), so that I can send you this information.',
- ['45'] = 'I have sent you the information you requested via private chat.',
- ['46'] = 'Remove Channel Pins?',
- ['47'] = 'Remove Other Pins?',
- ['48'] = 'Remove Pasted Code?',
- ['49'] = 'Prevent Inline Bots?',
- ['50'] = 'Kick Media On Join?',
- ['51'] = 'Enable Plugins For Admins?',
- ['52'] = 'Kick URLs On Join?'
- },
- ['afk'] = {
- ['1'] = 'Üzgünüm, Bu özellik sadece aktif kullanıcılar için @kullanıcıadı şeklinde kullanılır!',
- ['2'] = '%s klavyeden uzaklaşarak tekrar geri döndü %s!',
- ['3'] = 'Not',
- ['4'] = '%s şuan klavyeden uzaklaştı.%s'
- },
- ['antispam'] = {
- ['1'] = 'Kapalı',
- ['2'] = 'Açık',
- ['3'] = 'Sınırı devre dışı bırak',
- ['4'] = 'Sınırları etkinleştir %s',
- ['5'] = 'Tüm Yönetim Ayarları',
- ['6'] = '%s [%s] Anti-spam medya limitine ulaşıldığı %s [%s] için %s [%s] gruptan atıldı [%s] .',
- ['7'] = 'Atıldı %s anti-spam medya limitini aştığı için [%s] .',
- ['8'] = 'Maksimum sınır 100.',
- ['9'] = 'Minimum sınır is 1.',
- ['10'] = 'Aşağıdan %s anti-spam ayarlarını değiştirin:',
- ['11'] = 'Hey %s, if you\'re going to send code that is longer than %s characters in length, please do so using /paste in <a href="https://t.me/%s">private chat with me</a>!',
- ['12'] = '%s <code>[%s]</code> has %s %s <code>[%s]</code> from %s <code>[%s]</code> for sending Telegram invite link(s).\n#chat%s #user%s',
- ['13'] = '%s %s for sending Telegram invite link(s).',
- ['14'] = 'Hey, I noticed you\'ve got anti-link enabled and you\'re currently not allowing your users to mention a chat you\'ve just mentioned, if you\'d like to allowlist it, use /allowlink <links>.',
- ['15'] = 'Kicked %s <code>[%s]</code> from %s <code>[%s]</code> for sending media within their first few messages.\n#chat%s #user%s',
- ['16'] = 'Kicked %s <code>[%s]</code> from %s <code>[%s]</code> for sending a URL within their first few messages.\n#chat%s #user%s',
- ['17'] = 'Action',
- ['18'] = 'Kick',
- ['19'] = 'Ban',
- ['20'] = 'Mute'
- },
- ['appstore'] = {
- ['1'] = 'iTunes de görüntüle',
- ['2'] = 'rating',
- ['3'] = 'ratings'
- },
- ['authspotify'] = {
- ['1'] = 'You are already authorised using that account.',
- ['2'] = 'Authorising, please wait...',
- ['3'] = 'A connection error occured. Are you sure you replied with the correct link? It should look like',
- ['4'] = 'Successfully authorised your Spotify account!'
- },
- ['avatar'] = {
- ['1'] = 'Bu kullanıcı için profil fotoğraflarını alamadım, lütfen geçerli bir kullanıcı adı veya sayısal kimlik belirttiğinizden emin olun.',
- ['2'] = 'Bu kullanıcının profil fotoğrafı yok..',
- ['3'] = 'Bu kullanıcının pek çok profil fotoğrafı yok!',
- ['4'] = 'Bu kullanıcı, veri toplama işlevini devre dışı bıraktı, bu nedenle profil fotoğraflarından hiçbirini size gösteremiyorum.',
- ['5'] = 'User: %s\nPhoto: %s/%s\nSend /avatar %s [offset] to @%s to view a specific photo of this user',
- ['6'] = 'User: %s\nPhoto: %s/%s\nUse /avatar %s [offset] to view a specific photo of this user'
- },
- ['ban'] = {
- ['1'] = 'Hangi kullanıcı banlamamı istersiniz? Bu kullanıcıyı @kulanıcıadı şeklinde veya kullanıcı IDsi ile belirtebilirsin.',
- ['2'] = 'Bu kullanıcıyı, bu sohbette bir moderatör veya yönetici oldukları için banlayamam.',
- ['3'] = 'Bu sohbetten ayrıldığı için bu kullanıcıyı banyalamam.',
- ['4'] = 'Bu sohbetten zaten banlandıkları için bu kullanıcıyı banlayamam.',
- ['5'] = 'Bu kullanıcıyı banlamam için admin izinlerine sahip olmam gerekiyor. Lütfen bu sorunu düzeltip tekrar deneyin.',
- ['6'] = '%s <code>[%s]</code> has banned %s <code>[%s]</code> from %s <code>[%s]</code>%s.\n%s %s',
- ['7'] = '%s has banned %s%s.'
- },
- ['bash'] = {
- ['1'] = 'Lütfen çalıştırılacak bir komut belirtin!',
- ['2'] = 'Başarılı!'
- },
- ['blocklist'] = {
- ['1'] = 'Hangi kullanıcıyı kara listeye almamı istersiniz?? Bu kullanıcıyı @kulanıcıadı şeklinde veya kullanıcı IDsi ile belirtebilirsin.',
- ['2'] = 'Bu kullanıcıyı, bu sohbette bir moderatör veya yönetici oldukları için kara listeye alamam.',
- ['3'] = 'Bu sohbetten ayrıldığı için bu kullanıcıyı kara listeye alamam.',
- ['4'] = 'Bu sohbetten banlandığı için bu kullanıcıyı kara listeye alamam.',
- ['5'] = '%s <code>[%s]</code> has blocklisted %s <code>[%s]</code> from using %s <code>[%s]</code> in %s <code>[%s]</code>%s.\n%s %s',
- ['6'] = '%s has blocklisted %s from using %s%s.'
- },
- ['blocklistchat'] = {
- ['1'] = '%s şimdi kara listeye alındı!',
- ['2'] = '%s bir kullanıcıysa, bu komut sadece gruplar ve kanallar gibi sohbetleri kara listeye almak için kullanılır!',
- ['3'] = '%s Geçerli bir sohbet gibi gözükmüyor!'
- },
- ['bugreport'] = {
- ['1'] = 'Başarılı! Hata raporunuz gönderilmiştir. Bu raporun kimliği #%s.',
- ['2'] = 'Bu hatayı bildirirken bir sorun oluştu! Ha, ironi!'
- },
- ['calc'] = {
- ['1'] = 'Sonuç göndermek için tıklayın.',
- ['2'] = '"%s" was an unexpected word!',
- ['3'] = 'You cannot have a unit before a number!'
- },
- ['captionbotai'] = {
- ['1'] = 'Bu resmi gerçekten tarif edemiyorum!'
- },
- ['cats'] = {
- ['1'] = 'Miyavvv!'
- },
- ['channel'] = {
- ['1'] = 'Bunu kullanmanıza izin verilmiyor!',
- ['2'] = 'Bu sohbette artık yönetici gibi görünmüyorsunuz!',
- ['3'] = 'Mesajınızı gönderemedim, hala sohbet mesajı gönderme iznim var mı?',
- ['4'] = 'Mesajınız gönderildi!',
- ['5'] = 'Sohbet yöneticilerinin listesini alamadım!',
- ['6'] = 'Sohbette bir yönetici gibi görünmüyorsun!',
- ['7'] = 'Lütfen, gönderilecek mesajı /channel <kanal> <mesaj> sözdizimini kullanarak belirtin.',
- ['8'] = 'Bu mesajı göndermek istediğinizden emin misiniz? Nasıl görüneceği ise şöyledir:',
- ['9'] = 'Evet eminim!',
- ['10'] = 'Bu mesaj geçersiz Markdown biçimlendirme içeriyor! Lütfen sözdiziminizi düzeltin ve tekrar deneyin.'
- },
- ['chatroulette'] = {
- ['1'] = 'Hey! Please don\'t send messages longer than %s characters. We don\'t want to annoy the other user!',
- ['2'] = '*Anonymous said:*\n```\n%s\n```\nTo end your session, send /endchat.',
- ['3'] = 'I\'m afraid I lost connection from the other user! To begin a new chat, please send /chatroulette!',
- ['4'] = 'The other person you were chatting with has ended the session. To start a new one, send /chatroulette.',
- ['5'] = 'Successfully ended your session. To start a new one, send /chatroulette.',
- ['6'] = 'I have successfully removed you from the list of available users.',
- ['7'] = 'You don\'t have a session set up at the moment. To start one, send /chatroulette.',
- ['8'] = 'Finding you a session, please wait...',
- ['9'] = 'I\'m afraid there aren\'t any available users right now, but I have added you to the list of available users! To stop this completely, please send /endchat.',
- ['10'] = 'I have successfully paired you with another user to chat to! Please remember to be kind to them! To end the chat, send /endchat.',
- ['11'] = 'I\'m afraid the user who I tried to pair you with has since blocked me. Please try and send /chatroulette again to try and connect to me!',
- ['12'] = 'I have successfully paired you with another user to chat to! Please remember to be kind to them! To end the chat, send /endchat.'
- },
- ['commandstats'] = {
- ['1'] = 'Bu sohbette hiçbir komut gönderilmedi!',
- ['2'] = '<b>Komut için istatistikler:</b> %s\n\n%s\n<b>Toplam göderilen komutlar:</b> %s',
- ['3'] = 'Bu sohbetin komut istatistikleri sıfırlandı!',
- ['4'] = 'Bu sohbetin komut istatistiklerini sıfırlayamadım. Belki de daha önce sıfırlanmışlardır?'
- },
- ['control'] = {
- ['1'] = 'Pfft, dilersen!',
- ['2'] = '%s Yeniden yükleniyor...'
- },
- ['copypasta'] = {
- ['1'] = 'Yanıtlanan metin, %s karakterlerden uzun olmamalıdır.!'
- },
- ['coronavirus'] = {
- ['1'] = [[*COVID-19 Statistics for:* %s
-
-*New confirmed cases:* %s
-*Total confirmed cases:* %s
-*New deaths:* %s
-*Total deaths:* %s
-*New recovered cases:* %s
-*Total recovered cases:* %s]]
- },
- ['counter'] = {
- ['1'] = 'Bu mesaja sayaç ekleyemedim!'
- },
- ['custom'] = {
- ['1'] = 'Başarılı! Bu mesaj şimdi birileri her kullandığı zaman gönderilecek %s!',
- ['2'] = 'Tetikleyici "%s" yok!',
- ['3'] = 'Tetikleyici "%s" silindi!',
- ['4'] = 'Herhangi bir özel tetikleyici ayarlamadın!',
- ['5'] = 'Özel komutlar %s:\n',
- ['6'] = 'Yeni ve özel bir komut oluşturmak için şu sözdizimini kullanın:\n/custom new #tetikleyici <değer>.Tüm tetikleyiciler listesi için, /custom list komutunu kullanın. Tetikleyiciyi silmek için ise, /custom del #trigger komutunu kullanın.'
- },
- ['delete'] = {
- ['1'] = 'Bu mesajı silemedim. Belki de mesaj çok eskidir veya mevcut değildir?'
- },
- ['demote'] = {
- ['1'] = 'Hangi kullanıcının yetkisini almamı istersin ? Bu kullanıcıyı @kulanıcıadı şeklinde veya kullanıcı IDsi ile belirtebilirsin.',
- ['2'] = 'Bu kullanıcıyı, bu sohbette bir moderatör veya yönetici olmadığı için yetkisini almam mümkün değil.',
- ['3'] = 'Bu sohbetten zaten ayrıldıı, bu kullanıcının yetkisini alamam.',
- ['4'] = 'Bu kullanıcı daha önce bu sohbetten atılmış ulduğu için yetkisini almam mümkün değil.'
- },
- ['doge'] = {
- ['1'] = 'Lütfen Dogeify istediğiniz metni girin. Her cümle eğik çizgi veya yeni satırlar kullanılarak ayrılmalıdır.'
- },
- ['donate'] = {
- ['1'] = '<b>Hello, %s!</b>\n\nIf you\'re feeling generous, you can contribute to the mattata project by making a monetary donation of any amount. This will go towards server costs and any time and resources used to develop mattata. This is an optional act, however it is greatly appreciated and your name will also be listed publically on mattata\'s GitHub page.\n\nIf you\'re still interested, you can donate <a href="https://paypal.me/wrxck">here</a>. Thank you for your continued support!'
- },
- ['exec'] = {
- ['1'] = 'Lütfen kodunuzu yürütmek istediğiniz dili seçin:',
- ['2'] = 'Bir hata oluştu! Bağlantı zaman aşımına uğradı. Beni geride bırakmaya mı çalışıyordun?',
- ['3'] = 'Seçtiniz "%s" – emin misin?',
- ['4'] = 'Geri',
- ['5'] = 'Eminim',
- ['6'] = 'Çalıştırmak istediğiniz kod parçacığını yazınız.Dili belirtmeniz gerekmiyor, bunu daha sonra yapacağız!',
- ['7'] = 'Lütfen kodunuzu yürütmek istediğiniz dili seçin:'
- },
- ['facebook'] = {
- ['1'] = 'Bir hata oluştu!',
- ['2'] = 'Lütfen profil resmini almak istediğiniz Facebook kullanıcısının adını girin.',
- ['3'] = 'Facebook da %s görüntüle'
- },
- ['fact'] = {
- ['1'] = 'Başka Bir Tane Oluştur'
- },
- ['fban'] = {
- ['1'] = 'Which user would you like me to Fed-ban? You can specify this user by their @username or numerical ID.',
- ['2'] = 'I cannot Fed-ban this user because they are a moderator or an administrator in this chat.'
- },
- ['flickr'] = {
- ['1'] = 'Aradığınız:',
- ['2'] = 'Lütfen bir arama sorgusu girin (Yani, Flickrı aramamı ne için istiyorsun, Örnek: "Kalem" kalem fotoğragları gösterilecek).',
- ['3'] = 'Daha fazla sonuç'
- },
- ['game'] = {
- ['1'] = 'Toplam kazanç: %s\nToplam kayıp: %s\nKalan: %s mattacoins',
- ['2'] = 'Oyuna Katıl',
- ['3'] = 'Bu oyun zaten bitti!',
- ['4'] = 'Senin sıran değil!',
- ['5'] = 'Bu oyunun bir parçası değilsin!',
- ['6'] = 'Bu oyuna giremezsiniz!',
- ['7'] = 'Zaten bu oyunun bir parçasısın!',
- ['8'] = 'Bu oyun zaten başladı!',
- ['9'] = '%s [%s] e karşı oynuyor %s [%s]\nŞuanda by %s\'s senin sıran!',
- ['10'] = '%s e karşı oyunu kazandı %s!',
- ['11'] = '%s e karşı oyundan çekildi %s!',
- ['12'] = 'Rakip bekleniyor...',
- ['13'] = 'Tic-Tac-Toe',
- ['14'] = 'Oyunu sohbete göndermek için tıklayın!',
- ['15'] = 'Oyun istatistiği %s:\n',
- ['16'] = 'Tic-Tac-Toe oyna!'
- },
- ['gblocklist'] = {
- ['1'] = 'Lütfen genel kara listeye eklemek istediğiniz kullanıcıyı yanıtlayın veya kullanıcı adı veya kimlik numarasına göre belirtin.',
- ['2'] = 'Hakkında bilgi alamadım "%s", lütfen geçerli bir kullanıcı adı veya kimliğini kontrol edin ve tekrar deneyin.',
- ['3'] = 'Bu bir %s kullanıcı değil'
- },
- ['gif'] = {
- ['1'] = 'Lütfen bir arama sorgusu girin (GIPHY de ne aramak istediğini belirt , örnek: "kedi" kedi ile ilgili olan GIF ler gösterilecek).'
- },
- ['gallowlist'] = {
- ['1'] = 'Lütfen genel olarak beyaz listeye eklemek isteyen kullanıcıyı yanıtlayın, kullanıcı adı veya kimlik numarasına göre belirtin.',
- ['2'] = 'Hakkında bilgi alamadım "%s", lütfen geçerli bir kullanıcı adı veya kimliğini kontrol edin ve tekrar deneyin.',
- ['3'] = 'Bu bir %s kullanıcı değil'
- },
- ['hackernews'] = {
- ['1'] = 'Hacker Haberlerinden En Çok Okunan Hikayeler:'
- },
- ['help'] = {
- ['1'] = 'Sonuç bulunamadı!',
- ['2'] = '"%s" ile eşleşen hiçbir özellik bulunamadı, lütfen daha spesifik olmaya çalışın ve deneyin.!',
- ['3'] = '\n\nDeğişken: <required> [opsiyonel]\n\nSatır içi arama işlevselliğini kullanarak bir özellik arayın veya bir komutla yardım alın - @%s <arama sorgusu> sözdizimini kullanarak herhangi bir sohbetten bahsedin.',
- ['4'] = 'Önceki',
- ['5'] = 'Sonraki',
- ['6'] = 'Geri',
- ['7'] = 'Ara',
- ['8'] = '%s sayfanın %s sayfasındasın',
- ['9'] = [[
-Gruplarınızda birçok idari işlem yapabilirim, Beni yönetici olarak eklemelisin ve grubunuzun ayarlarını yapmak için /administrator komutunu göndermelisin.
-İşte bazı idari komutlar ve yaptıklarıyla ilgili kısa bir açıklama:
-
-• /pin <yazı> - Aynı komutla farklı metni kullanarak düzenlenebilen Markdown formatlı bir mesaj gönderin, Bir mesajı düzenleyemiyorsanız bundan kurtulmak için yeniden sabitlemeniz gerekmez (Mesaj 48 saatten fazla sabit kalamaz)
-
-• /ban - Bir kullanıcıyı, mesajlarından birine yanıt vererek veya kullanıcı adı / kimlik numarasıyla belirterek banla
-
-• /kick - Bir kullanıcıyı mesajlarından birine yanıt vererek veya kullanıcı adı / kimlik numarasıyla belirterek bir kullanıcıyı banlayın (aynı şekilde unban komutu)
-
-• /unban - Bir kullanıcıyı mesajlarından birine yanıt vererek veya kullanıcı adı / kimlik numarasıyla belirterek bir kullanıcının banını kaldırın
-
-• /setrules <yazı> - Verilen Markdown formatlı metni, birisi kullandığı zaman gönderilecek olan grup kuralları olarak ayarlayın, /rules komutunu kullanarak
- ]],
- ['10'] = [[
-• /setwelcome - Kullanıcının gruba katıldığı her zaman gösterilecek olan bir hoş geldin mesajı belirtin. (hoş geldin mesajı admin menüsünden kapalı olabilir, /administration komutu ile kontrol edin). Her kullanıcı için hoş geldiniz mesajını otomatik olarak özelleştirmek için yer tutucularını kullanabilirsiniz. Kullanıcının sayısal kimliğini eklemek için $user_id kullanın,sohbetin sayısal kimliğini eklemek için $chat_id, kullanıcının adını eklemek için $name, grubun ismini eklemek için $title ve kullanıcının kullanıcı adını eklemek için $username (eğer kullanıcının kullanıcı adı (@kullanıcıadı) yoksa, bunun yerine isimleri kullanılacak, bu yüzden $name ile birlikte kullanılmamalıdır.)
-
-• /warn - Bir kullanıcıyı uyarmak ve maksimum uyarı sayısına ulaştığında onları banlamak için kullanılır
-
-• /mod - Yanıtlanan kullanıcıya moderatör yetkisi verir, /ban, /kick, /warn vb komutları kullanabilir.(Bu, birisinin mesajlarını silmeyi istemiyorsanız kullanışlıdır!)
-
-• /demod - Yanıtlanan kullanıcınn moderatör yetkisini alır, moderatör komutlarını kullanamaz.
-
-• /staff - Grubun kurucusunu, adminlerini, ve moderatörlerinin listesini gösterir.
- ]],
- ['11'] = [[
-• /report - Yanıtlanan mesajı direk olarak admine rapor edip yönderir.
-
-• /setlink <URL> - Grubun bağlantısını verilen URL'yi ayarlayın; /link bu komutu, biri kullanıldığında URL gönderilir.
-
-• /links <yazı> - Verilen metinde bulunan tüm Telegram bağlantılarını beyaz listeye ekler ( @kullanıcıadı şeklinde olanları da)
- ]],
- ['12'] = 'Aşağıda yararlı bulabileceğiniz bazı bağlantılar verilmiştir.:',
- ['13'] = 'Geliştirme',
- ['14'] = 'Kanal',
- ['15'] = 'Destek',
- ['16'] = 'SSS',
- ['17'] = 'Kaynak',
- ['18'] = 'Bağışta bulunmak',
- ['19'] = 'Oylamak',
- ['20'] = 'Yönetim Günlüğü',
- ['21'] = 'Admin Ayarları',
- ['22'] = 'Eklentiler',
- ['23'] = [[
-<b>Merhaba %s! Benim adım %s, sizinle tanışmak bir şeref idi</b> %s
-
-Bir çok komutu anlıyorum, hangi komutu öğrenmek istiyorsan satır içinde "Komutlar" butonunu seçin.
-
-%s <b>İpucu:</b> "Ayarlar" butonuna tıklayarak nasıl çalıştığımı öğrenin%s!
-
-%s <b>Beni kullanışlı mı buldun, yoksa yardıma ihtiyaç mı var ?</b>Bağışlar çok takdir edilmektedir, /donate komutunu kullanarak daha fazla bilgi elde et!
- ]],
- ['24'] = 'içinde'
- },
- ['id'] = {
- ['1'] = 'Üzgünüm ama o kullanıcıyı tanımıyorum. Bana kim olduğunu öğretmek istersen, onun bir measjını bana ilet.',
- ['2'] = 'Sorgulanan Sohbet:',
- ['3'] = 'Bu sohbet:',
- ['4'] = 'Sonuç göndermek için tıklayın!'
- },
- ['imdb'] = {
- ['1'] = 'Önceki',
- ['2'] = 'Sonraki',
- ['3'] = '%s sayfanın %s sayfasındasın!'
- },
- ['import'] = {
- ['1'] = 'Bu sohbeti tanımıyorum!',
- ['2'] = 'Bu bir supergroup değil, bu nedenle herhangi bir ayarları aktaramıyorum!',
- ['3'] = '%s dan %s adresinden yönetim ayarlarını ve geçiş yapmış eklentileri başarıyla içe aktardı.!'
- },
- ['info'] = {
- ['1'] = [[
-```
-Dağıtım:
-%s Yapılandırma Dosyası: %s
-%s Mod: %s
-%s TCP Port: %s
-%s Versyon: %s
-%s Çalışma süresi: %s days
-%s Çalışma kimliği: %s
-%s Süresi Dolmuş Anahtarlar: %s
-
-%s Kullanıcı Sayısı: %s
-%s Grup Sayısı: %s
-
-Sistem:
-%s İşletim sistemi: %s
-```
- ]]
- },
- ['instagram'] = {
- ['1'] = '@%s İnstagram'
- },
- ['ipsw'] = {
- ['1'] = '<b>%s</b> iOS %s\n\n<code>MD5 toplamı: %s\nSHA1 toplamı: %s\nDosya boyutu: %s GB</code>\n\n<i>%s %s</i>',
- ['2'] = 'Bu yazılım artık imzalanmıyor!',
- ['3'] = 'Bu yazılım hala imzalanıyor!',
- ['4'] = 'Lütfen modelinizi seçin:',
- ['5'] = 'Lütfen bellenim sürümünüzü seçin:',
- ['6'] = 'Lütfen aygıt türünü seçin:',
- ['7'] = 'iPod Touch',
- ['8'] = 'iPhone',
- ['9'] = 'iPad',
- ['10'] = 'Apple TV'
- },
- ['ispwned'] = {
- ['1'] = 'Bu hesap aşağıdaki sızıntılarda bulundu:'
- },
- ['itunes'] = {
- ['1'] = 'İsim:',
- ['2'] = 'Sanatçı:',
- ['3'] = 'Albüm:',
- ['4'] = 'Parça:',
- ['5'] = 'Disk:',
- ['6'] = 'Orijinal sorgu bulunamadı, muhtemelen orijinal iletiyi silindiniz.',
- ['7'] = 'Sanat aşağıda bulunabilir:',
- ['8'] = 'Lütfen bir arama sorgusu girin (iTunes de aramak istediğin sorguyu gir, örnek: "Aykut Kuşkaya-Kaldırımlar" Aykut Kuşkaya - Kaldırımlar parçası aranacak.).',
- ['9'] = 'Albüm Kapağını Getir'
- },
- ['kick'] = {
- ['1'] = 'Hangi kullanıcıyı gruptan atmak istersiniz? Bu kullanıcıyı @kulanıcıadı şeklinde veya kullanıcı IDsi ile belirtebilirsin.',
- ['2'] = 'Bu kullanıcıyı, bu sohbette bir moderatör veya yönetici olduğu için gruptan atamam.',
- ['3'] = 'Bu kullanıcıyı, bu sohbeden ayrıldığı için gruptan atamam.',
- ['4'] = 'Bu kullanıcıyı, bu sohbetten çoktan atıldıkları için gruptan atamam.',
- ['5'] = 'Bu kullanıcıyı gruptan atmak için admin izinlerine sahip olmam gerekiyor. Lütfen bu sorunu düzeltip tekrar deneyin.'
- },
- ['lastfm'] = {
- ['1'] = '%s\'s last.fm kullanıcı adı ayarlandı "%s".',
- ['2'] = 'last.fm kullanıcı adın unutuldu!',
- ['3'] = 'Şu anda bir last.fm kullanıcı adınız yok!',
- ['4'] = 'Lütfen last.fm kullanıcı adınızı belirtin veya /fmset ile ayarlayın.',
- ['5'] = 'Bu kullanıcı için geçmiş bulunamadı.',
- ['6'] = '%s Şu anda bunu dinliyorsun:\n',
- ['7'] = '%s en son dinlenilen:\n',
- ['8'] = 'Bilinmeyen',
- ['9'] = 'Sonuç göndermek için tıklayın.'
- },
- ['location'] = {
- ['1'] = 'Ayarlanmış konumunuz yok. Yeni konum ayarlamak ister misiniz?'
- },
- ['logchat'] = {
- ['1'] = 'Lütfen tüm idari işlemleri kaydetmek istediğiniz sohbetin kullanıcı adını veya sayısal kimliğini girin.',
- ['2'] = 'Bu sohbetin geçerli olup olmadığını kontrol et...',
- ['3'] = 'Maalesef geçersiz bir sohbet belirttiniz veya henüz eklenmediğim bir sohbet belirttiniz. Lütfen bunu düzeltin ve tekrar deneyin.',
- ['4'] = 'Bir kullanıcıyı günlük sohbetiniz olarak ayarlayamazsınız!',
- ['5'] = 'Sohbette bir yönetici gibi görünmüyorsun!',
- ['6'] = 'Görünen o ki sohbetime zaten idari işlemler yapıyorum! /logchat komutunu kullanarak bir tane oluştur.',
- ['7'] = 'Bu sohbet geçerlidir, şimdi göndermeye izinim olduğundan emin olmak için ona bir test mesajı göndermeye çalışacağım!',
- ['8'] = 'Merhaba, Dünya - bu,mesaj gönderme izinlerini kontrol etmek için bir test mesajıdır - Eğer bunu okursanız, her şey yolundadır.',
- ['9'] = 'Hepsi tamam! Şu andan itibaren, bu sohbetteki herhangi bir idari işlemler giriş yapabilir %s - Benim için yönetimsel işlemleri kaydetmek istediğim sohbeti değiştirmek için, /logchat komutunu kullanın.'
- },
- ['lua'] = {
- ['1'] = 'Lütfen yürütülecek bir Lua dizgesi girin!'
- },
- ['lyrics'] = {
- ['1'] = 'Spotify',
- ['2'] = 'Şarkı sözlerini göster',
- ['3'] = 'Lütfen bir arama sorgusu girin (aramak istediğin şarkı sözlerini belirt, örnek: "Ankaranın Bağları" Ankaranın bağları şarkı sözlerini getirecek.).'
- },
- ['minecraft'] = {
- ['1'] = '<b>%s kullanıcı adını değiştirdi %s time</b>',
- ['2'] = '<b>%s kullanıcı adını %s kere değiştirdi </b>',
- ['3'] = 'Önceki',
- ['4'] = 'Sonraki',
- ['5'] = 'Geri',
- ['6'] = 'UUID',
- ['7'] = 'Resim',
- ['8'] = 'Kullanıcı adı geçmişi',
- ['9'] = 'Lütfen özellik seçiniz:',
- ['10'] = 'Lütfen Minecraft oyuncusunun kullanıcı adını giriniz. (örnek: "By_Azade" By_Azade hakkında bilgi verecel).',
- ['11'] = 'Minecraft usernames are between 3 and 16 characters long.'
- },
- ['mute'] = {
- ['1'] = 'Hangi kullanıcıyı susturmak istersiniz? Bu kullanıcıyı @kulanıcıadı şeklinde veya kullanıcı IDsi ile belirtebilirsin.',
- ['2'] = 'Bu sohbette zaten sessiz oldukları için bu kullanıcıyı susturamıyorum',
- ['3'] = 'Bu sohbette bir moderatör ya da yönetici oldukları için bu kullanıcıyı susturamıyorum.',
- ['4'] = 'Bu kullanıcıyı zaten bu sohbetten ayrılmış (veya oradan atılmış) bu yüzden susturamıyorum.',
- ['5'] = 'Bu kullanıcıyı susturmak için admin izinlerine sahip olmam gerekiyor. Lütfen bu sorunu düzeltip tekrar deneyin.'
- },
- ['myspotify'] = {
- ['1'] = 'Profil',
- ['2'] = 'Takip Edilenler',
- ['3'] = 'Önceden Oynatılanlar',
- ['4'] = 'Şu Anda Oynatılıyor',
- ['5'] = 'En İyi Parçalarınız',
- ['6'] = 'En İyi Sanatçılarınız',
- ['7'] = 'Herhangi bir sanatçıyı takip ediyor gibi görünmüyorsun!',
- ['8'] = 'En İyi Sanatçılarınız',
- ['9'] = 'Kütüphanenizde herhangi bir parçanın bulunmadığı anlaşılıyor!',
- ['10'] = 'En İyi Parçalarınız',
- ['11'] = 'Herhangi bir sanatçıyı takip ediyor gibi görünmüyorsun!',
- ['12'] = 'Takip Edilen Sanatçılar',
- ['13'] = 'Yakın zamanda herhangi bir parça çalmış görünmüyorsun!',
- ['14'] = '<b>Son Oynatılan</b>\n%s %s\n%s %s\n%s Dinlendi %s:%s on %s/%s/%s.',
- ['15'] = 'İstek işleme için kabul edildi, ancak işlem tamamlanmadı.',
- ['16'] = 'Şu an bir şey dinliyor görünmüyorsun!',
- ['17'] = 'Şu Anda Oynatılıyor',
- ['18'] = 'Spotify hesabınızı yeniden yetkilendirirken bir hata oluştu.!',
- ['19'] = 'Spotify hesabınız başarılı bir şekilde yeniden yetkilendirildi! İsteğinizi işleme koyabilirsiniz....',
- ['20'] = 'Spotify hesabınızı yeniden yetkilendirilecek, lütfen bekleyin...',
- ['21'] = 'Spotify hesabınızı bağlamak için mattatayı yetkilendirmeniz gerekir. Tıklayın [buraya](https://accounts.spotify.com/en/authorize?client_id=%s&response_type=code&redirect_uri=%s&scope=user-library-read,playlist-read-private,playlist-read-collaborative,user-read-private,user-read-email,user-follow-read,user-top-read,user-read-playback-state,user-read-recently-played,user-read-currently-playing,user-modify-playback-state) Mattatayı Spotify hesabınıza bağlamak için yeşil "Tamam" düğmesine basın. Bunu yaptıktan sonra, yönlendirilen bağlantıyı şu adrese gönderin: ("%s" ile başlamalı ve onu benzersiz bir kod takip etmelidir).',
- ['22'] = 'Çalma listeleri',
- ['23'] = 'Satıriçi Modu Kullan',
- ['24'] = 'Şarkı sözleri',
- ['25'] = 'Hiç aygıt bulunamadı.',
- ['26'] = 'Hiçbir çalma listenizin yokmuş gibi görünüyor.',
- ['27'] = 'Senin Oynatma Listen',
- ['28'] = '%s %s [%s parçalar]',
- ['29'] = '%s %s [%s]\nSpotify %s kullanıcı\n\n<b>aygıtları:</b>\n%s',
- ['30'] = 'Önceki parçayı çalınıyor...',
- ['31'] = 'Premium kullanıcı değilsiniz!',
- ['32'] = 'Herhangi bir cihaz bulamadım.',
- ['33'] = 'Bir sonraki parçayı çalınıyor...',
- ['34'] = 'Parça yeniden başlatılıyor...',
- ['35'] = 'Cihazınız geçici olarak kullanılamıyor...',
- ['36'] = 'Hiç aygıt bulunamadı!',
- ['37'] = 'Parçayı durduruyor...',
- ['38'] = 'Şimdi oynuyor',
- ['39'] = 'Shuffling your music...',
- ['40'] = 'Bu geçerli bir ses değil. Lütfen 0 ile 100 arasında bir sayı belirtin.',
- ['41'] = 'Ses seviyesi ayarlandı %s%%!',
- ['42'] = 'Bu ileti bu eklentinin eski bir sürümünü kullanıyor, lütfen /myspotify komutunu kullanarak yeni bir tane isteyin.!'
- },
- ['name'] = {
- ['1'] = 'Şu anda yanıtladığım isim "%s" - bunu değiştirmek için, /name <yazı> komutunu kullanın (Buradaki <yazı> bemin cevap vermemi istediğiniz şeydir).',
- ['2'] = 'Yeni adım 2 ila 32 karakter uzunluğunda olmalıdır!',
- ['3'] = 'İsmim yalnızca alfasayısal karakterler içerebilir!',
- ['4'] = 'Şimdi "% s" yerine "% s" ye yanıt vereceğim - bunu değiştirmek için, /name <yazı> komutunu kullanın (Buradaki <yazı> benim cevap vermemi istediğiniz şeydir).'
- },
- ['netflix'] = {
- ['1'] = 'Daha Fazla Bilgi Edinin'
- },
- ['news'] = {
- ['1'] = '"<code>%s</code>" Geçerli bir Lua kalıbı değil.',
- ['2'] = 'Bir kaynak listesi alınamadı..',
- ['3'] = '<b>Eşleşen haber kaynakları bulundu</b> "<code>%s</code>":\n\n%s',
- ['4'] = '<b>Aşağıdakilerle birlikte kullanabileceğiniz mevcut haber kaynakları</b> /news komutunu kullanarak./nsources komutunu <b>kullanın.</b> &lt;kaynak&gt; <b>daha spesifik bir sonuç kümesi için haber kaynakları listesinde arama yapmalısın. Aramalar Lua kalıpları kullanılarak eşleştirilir</b>\n\n%s',
- ['5'] = 'Tercih ettiğiniz bir haber kaynağınız yok. /setnews <kaynak> komutunu kullanarak bir tane ayarla. Kaynakların listesini görmek için /nsources komutunu kullan, veya kaynakları daraltmak için /nsources <kaynak> komutunu kullanabilirsin.',
- ['6'] = 'Tercih ettiğiniz mevcut haber kaynağı %s. /setnews <kaynak> komutunu kullanarak değiştirebilirsin. /nsources komutunu kullanarak kaynakları görüntüleyebilirsin, veya kaynakları daraltmak için /nsources <kaynak> komutunu kullanabilirsin.',
- ['7'] = 'Tercih ettiğiniz kaynak zaten %s! Geçerli hikayeyi görüntülemek için /news komutunu kullanın.',
- ['8'] = 'Bu geçerli bir haber kaynağı değil./nsources komutunu kullanarak bir kaynak listesi görüntüle, veya sonuçları daraltmak için /nsources <sorgu> komutunu kullan.',
- ['9'] = 'Tercih ettiğiniz haber kaynağı güncellendi %s! Geçerli hikayeyi görüntülemek için /news komutunu kullanın.',
- ['10'] = 'Bu geçerli bir kaynak değil, /nsources komutunu kullanarak aktif kaynakları görüntüleyin.Tercih ettiğiniz bir kaynağınız varsa, /setnews <kaynak> /news komutunu kullanarak gönderdiğinizde o kaynaktan gönderilen haberler otomatik olarak alınır, Herhangi bir argüman gerekmeden.',
- ['11'] = 'Daha Fazla Bilgi Edinin'
- },
- ['nick'] = {
- ['1'] = 'Takma adınız şimdi unutuldu!',
- ['2'] = 'Takma adınız "%s"!'
- },
- ['optout'] = {
- ['1'] = 'Toplanan verileri göndermeyi için seçtiniz! /optout komutunu kullanın.',
- ['2'] = 'Toplanan verileri göndermekten vazgeçtiniz! Etkinleştirmek için /optin komutunu kullanın.'
- },
- ['paste'] = {
- ['1'] = 'Lütfen yapıştırma dosyanızı yüklemek için bir hizmet seçin:'
- },
- ['pin'] = {
- ['1'] = 'Daha önce bir mesaj sabitlemediniz. /pin <yazı> komutunu kullanarak bir tane oluşturun.Yazı tipi türlerini destekler.',
- ['2'] = 'İşte son mesajı kullanarak üretilen /pin.',
- ['3'] = 'Veritabanında varolan bir pin buldum, Ancak gönderdiğim mesaj silindi gibi görünüyor, ve artık onu bulamıyorum. /pin <yazı> komutunu kullanrak yeni bir tane oluşturabilirsin. Yazı tipi türlerini destekler.',
- ['4'] = 'Mesajı sabitlerken bir hata oluştu. Girdiğiniz metnin geçersiz yazı tipi türü içerdiği için sabitlenen mesaj silindi. Şimdi, size aşağıda bulabileceğiniz yeni bir pin göndermeye çalışacağım - Onu değiştirmeniz gerekiyorsa, mesaj hala mevcut olduğundan emin olduktan sonra, /pin <yazı> komutunu kullanın.',
- ['5'] = 'Geçersiz yazı tipi formatı içerdiğinden bu metni gönderemedim.',
- ['6'] = 'Sabitlenen mesajı görüntüle, güncellenen mesajı görüntülemek için tıklayın.'
- },
- ['pokedex'] = {
- ['1'] = 'İsim: %s\nKimlik: %s\nTip: %s\nAçıklama: %s'
- },
- ['promote'] = {
- ['1'] = 'Admini veya moderatörü yetkilendiremezsin.',
- ['2'] = 'Bu kullanıcıyı yetkilendiremiyorum çünkü bu sohbetten ayrılmış durumda.',
- ['3'] = 'Bu kullanıcıyı yetkilendiremiyorum çünkü bu sohbetten çoktan atılmış durumda.'
- },
- ['quote'] = {
- ['1'] = 'Bu kullanıcı, veri saklama işlevini devre dışı bıraktı.',
- ['2'] = 'Bunun için kayıtlı söz yok %s! Onların gönderdikleri bir mesajı /save komutunu kullanarak kaydedebilirsiniz.'
- },
- ['report'] = {
- ['1'] = 'Lütfen grubun yöneticilerine bildirmek istediğiniz iletiyi yanıtlayın.',
- ['2'] = 'Kendi mesajlarınızı bildiremezsiniz, sadece komik olmaya mı çalışıyorsunuz?',
- ['3'] = '<b>%s içinde yardıma ihtiyacı var %s!</b>',
- ['4'] = 'Bildirilen mesajı görüntülemek için burayı tıklayın.',
- ['5'] = 'Bu mesajı %s admin(ler) e başarıyla rapor ettim.!'
- },
- ['save'] = {
- ['1'] = 'Bu kullanıcı, veri saklama işlevini devre dışı bıraktı.',
- ['2'] = 'Bu mesaj benim veritabanıma kaydedildi ve /quote cevabında kullanıldığında olası yanıtların listesine eklendi. %s!'
- },
- ['sed'] = {
- ['1'] = '%s\n\n<i>%s Bunu söylemek istememiştim!</i>',
- ['2'] = '%s\n\n<i>%s Yenilgiyi kabul etti.</i>',
- ['3'] = '%s\n\n<i>%s Yanılıyor mu bilmiyorlar mı ...</i>',
- ['4'] = 'Kahretsin, <i>Ne zamandır yanılıyorum?</i>',
- ['5'] = '"<code>%s</code>" Geçerli bir Lua kalıbı değil.',
- ['6'] = 'Hey %s, %s seems to think you meant:\n<i>%s</i>',
- ['7'] = 'Evet',
- ['8'] = 'Hayır',
- ['9'] = 'Emin değilim',
- ['10'] = 'Just edit your message, idiot.'
- },
- ['setgrouplang'] = {
- ['1'] = 'Bu grubun dili şu şekilde ayarlandı: %s!',
- ['2'] = 'Bu grubun dili şu anda %s.\nLütfen bazı dizelerin henüz tercüme edilmediğine dikkat ediniz. Dilinizi değiştirmek isterseniz, aşağıdaki klavyeyi kullanarak birini seçin:',
- ['3'] = 'Kullanıcıları bu grupta aynı dili kullanmaya zorlama seçeneği şu anda devre dışı. Bu ayar /administrator den değiştirilmelidir, ancak işleri sizin için daha kolay hale getirmek için aşağıda bir düğme ekledim.',
- ['4'] = 'Etkin',
- ['5'] = 'Devre dışı'
- },
- ['setlang'] = {
- ['1'] = 'Diliniz ayarlandı %s!',
- ['2'] = 'Diliniz şuanda %s.\nLütfen bazı dizelerin henüz tercüme edilmediğine dikkat ediniz. Dilinizi değiştirmek isterseniz, aşağıdaki klavyeyi kullanarak birini seçin:'
- },
- ['setlink'] = {
- ['1'] = 'Doğru bir URL değil.',
- ['2'] = 'Link başarılı bir şekilde ayarlandı!'
- },
- ['setrules'] = {
- ['1'] = 'Bilinmeyen yazı tipi formatı.',
- ['2'] = 'Yeni kural başarılı bir şekilde kaydedildi!'
- },
- ['setwelcome'] = {
- ['1'] = 'Hoşgeldiniz mesajında ne yapmak istersiniz? Belirttiğiniz metin Markdown formatında olacak ve bir kullanıcı sohbete her katıldığında gönderilecektir (Hoş Geldiniz mesajı yönetim menüsünde devre dışı bırakılabilir, /administration üzerinden erişilebilir). Her kullanıcı için hoş geldiniz mesajını otomatik olarak özelleştirmek için yer tutucularını kullanabilirsiniz. Kullanıcının sayısal kimliğini eklemek için $user_id kullanın,sohbetin sayısal kimliğini eklemek için $chat_id, kullanıcının adını eklemek için $name, grubun ismini eklemek için $title ve kullanıcının kullanıcı adını eklemek için $username (eğer kullanıcının kullanıcı adı (@kullanıcıadı) yoksa, bunun yerine isimleri kullanılacak, bu yüzden $name ile birlikte kullanılmamalıdır.).',
- ['2'] = 'Mesajınızı biçimlendirirken bir hata oluştu, lütfen yazı türünü kontrol edin ve tekrar deneyin.',
- ['3'] = 'Hoş geldin mesajı %s başarılı bir şekilde güncellendi!'
- },
- ['share'] = {
- ['1'] = 'Paylaş'
- },
- ['shorten'] = {
- ['1'] = 'Lütfen aşağıdaki butonları kullanarak bir URL kısaltıcı seçin:'
- },
- ['shsh'] = {
- ['1'] = 'ECID için herhangi bir SHSH blobunu getiremedim, Lütfen geçerli olduğundan ve bunları kullanarak kaydettiğinizden emin olun https://tsssaver.1conan.com.',
- ['2'] = 'SHSH Bu cihazın blobları, iOSun aşağıdaki sürümleri için kullanılabilir:\n',
- ['3'] = 'İndir .zip'
- },
- ['statistics'] = {
- ['1'] = 'Bu sohbette hiç mesaj gönderilmedi!',
- ['2'] = '<b>Statistics for:</b> %s\n\n%s\n<b>Total messages sent:</b> %s',
- ['3'] = 'Bu sohbet istatistikleri sıfırlandı!',
- ['4'] = 'Bu sohbetin istatistiklerini sıfırlayamadım. Belki daha önce resetlendi?'
- },
- ['steam'] = {
- ['1'] = 'Steam kullanıcı adın ayarlandı "%s".',
- ['2'] = '"%s" Steam kullanıcı adı değil.',
- ['3'] = '%s Steam kullanıcısı %s, açık %s. En son kapattılanlar %s, açık %s. Tıkla <a href="%s">here</a> Steam profilini görüntüle.',
- ['4'] = '%s, AKA "%s",'
- },
- ['trust'] = {
- ['1'] = 'Admini ve moderatörü güvenli olarak işaretleyemem.',
- ['2'] = 'Bu kullanıcıyı güvenli olarak işaretleyemem,kullanıcı gruptan ayrılmış.',
- ['3'] = 'Bu kullanıcıyı güvenli olarak işaretleyemem, kullanıcı gruptan atılmış'
- },
- ['unmute'] = {
- ['1'] = 'Hangi kullanıcının sesini açmak istiyorsun? Bu kullanıcıyı @kulanıcıadı şeklinde veya kullanıcı IDsi ile belirtebilirsin.',
- ['2'] = 'Bu kullanıcının sesini açamam, kullanıcının sesi kapanmamış.',
- ['3'] = 'Adminin veya moderatörün sesini kapatamam.',
- ['4'] = 'Bu kullanıcının sesini açamam, kullanıcı gruptan ayrılmış.'
- },
- ['untrust'] = {
- ['1'] = 'Hangi kullanıcıyı güvenilmeyen yapmak istiyorsun ? Bu kullanıcıyı @kulanıcıadı şeklinde veya kullanıcı IDsi ile belirtebilirsin.',
- ['2'] = 'Admin ve moderatörü güvenilmeyenler olarak ekleyemem.',
- ['3'] = 'Bu kullanıcıyı güvenilmeyenler listesine ekleyemem, kullanıcı gruptan ayrılmış.',
- ['4'] = 'Bu kullanıcıyı güvenilmeyenler listesine ekleyemem, kullanıcı gruptan atılmış.'
- },
- ['upload'] = {
- ['1'] = 'Please reply to the file you\'d like to download to the server. It must be <= 20 MB.',
- ['2'] = 'Dosya çok büyük boyutta. 20MBdan küçük olmalı <= 20 MB.',
- ['3'] = 'Bu dosyayı alamıyorum, muhtemelen çok eski.',
- ['4'] = 'Bu dosyayı alınırken bir hata meydana geldi.',
- ['5'] = 'Dosyayı sunucudan başarılı bir şekilde indirdiniz - bulunabilir <code>%s</code>!'
- },
- ['voteban'] = {
- ['1'] = 'Hangi kullanıcı için oyla-banla özelliği kullanmak istiyorsun? Bu kullanıcıyı @kulanıcıadı şeklinde veya kullanıcı IDsi ile belirtebilirsin.',
- ['2'] = 'Admin için oyla-banla özelliği kullanılmaz',
- ['3'] = 'Oyla-banla özelliğini kullanamıyorum, kullanıcı gruptan ayılmış veya banlanmış.',
- ['4'] = '[%s] Buradan banlanması gerekir mi %s? %s hemen yasaklanması için oylama gerekir, ve %s bunun için en az oylama kapalı olmalıdır',
- ['5'] = 'Evet [%s]',
- ['6'] = 'Hayır [%s]',
- ['7'] = '[%s] Buradan %s %s banlandı %s çünkü %s insanlar bunun için oy kullandılar.',
- ['8'] = 'En yüksek oy miktarına ulaşıldı, ancak, banlayamam %s - belki onlar oylama yapılmadan önce gruptan ayrılmışlardır? Bu eylemi gerçekleştirmek için yetkiniz yok',
- ['9'] = 'Onları %s [%s] banlayamam %s çünkü %s insanlar banlamak için karar vermemişler.',
- ['10'] = 'Banlamak için oy kullandın %s [%s]!',
- ['11'] = 'Oyun geri çekildi, butonu kullanarak tekrar oy kullanabilirsin.',
- ['12'] = 'Banlama kararı alındı %s [%s]!',
- ['13'] = 'A vote-ban has already been opened for this user!'
- },
- ['weather'] = {
- ['1'] = 'Konum ayarlamadın. /setloc <konum> komutunu kullanarak bir tane ayarla.',
- ['2'] = 'Şu anda %s (hissedilen sıcaklık %s) %s. %s'
- },
- ['welcome'] = {
- ['1'] = 'Grup Kuralları'
- },
- ['allowlist'] = {
- ['1'] = 'Hangi kullanıcıyı beyaz listeye almak istiyorsun? Bir kullanıcıyı özel olarak @kullanıcıadı şeklinde veya kullanıcı kimliği ile belirtebilirsin.',
- ['2'] = 'Admini veya moderatörü beyaz listeye alamam.',
- ['3'] = 'Bu kullanıcıyı beyaz listeye alamam, kullanıcı sohbetten ayrılmış.',
- ['4'] = 'Bu kullanıcıyı beyaz listeye alamam kullanıcı sohbetten banlanmış'
- },
- ['wikipedia'] = {
- ['1'] = 'Daha fazla bilgi edinin.'
- },
- ['youtube'] = {
- ['1'] = 'Önceki',
- ['2'] = 'Sonraki',
- ['3'] = '%s sayfanın %s sayfasındasın!'
- }
-}
diff --git a/launch.sh b/launch.sh
deleted file mode 100755
index 4593bca..0000000
--- a/launch.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/sh
-if [ ! -f ./configuration.lua ]
-then
- echo "Please insert the required variables into configuration.example.lua. Then, you need to rename configuration.example.lua to configuration.lua!"
-else
- while true; do
- lua -e "require('mattata').run({}, require('configuration'))"
- echo "mattata has stopped!"
- sleep 3s
- done
-fi
diff --git a/libs/https.lua b/libs/https.lua
deleted file mode 100644
index 7359855..0000000
--- a/libs/https.lua
+++ /dev/null
@@ -1,126 +0,0 @@
---[[
-
- Customised version of https://github.com/brunoos/luasec/blob/master/src/https.lua to allow better timeouts.
-
- LuaSec 0.9 license
- Copyright (C) 2006-2019 Bruno Silvestre, UFG
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-]]
-
-local socket = require('socket')
-local ssl = require('ssl')
-local ltn12 = require('ltn12')
-local http = require('socket.http')
-local url = require('socket.url')
-
-local https = {
- ['try'] = socket.try,
- ['configuration'] = {
- ['protocol'] = 'any',
- ['options'] = {
- 'all',
- 'no_sslv2',
- 'no_sslv3'
- },
- ['verify'] = 'none'
- }
-}
-
-function https.build_url(request)
- local parsed = url.parse(request, { ['port'] = 443 })
- return url.build(parsed)
-end
-
-function https.build_table(request, body, result, method)
- request = {
- ['url'] = https.build_url(request),
- ['method'] = method or (body and 'POST' or 'GET'),
- ['sink'] = ltn12.sink.table(result)
- }
- if body then
- request.source = ltn12.source.string(body)
- request.headers = {
- ['Content-Length'] = #body,
- ['Content-Type'] = 'application/x-www-form-urlencoded'
- }
- end
- return request
-end
-
-function https.register(connection)
- for name, method in pairs(getmetatable(connection.socket).__index) do
- if type(method) == 'function' then
- connection[name] = function(self, ...)
- return method(self.socket, ...)
- end
- end
- end
-end
-
-function https.tcp(parameters, timeout)
- parameters = type(parameters) == 'table' and parameters or {}
- for k, v in pairs(https.configuration) do
- parameters[k] = parameters[k] or v
- end
- parameters.mode = 'client'
- return function()
- local connection = {}
- connection.socket = https.try(socket.tcp())
- https.settimeout = getmetatable(connection.socket).__index.settimeout
- function connection:settimeout(...)
- return https.settimeout(self.socket, ...)
- end
- function connection:connect(host, port)
- https.try(self.socket:connect(host, port))
- self.socket = https.try(ssl.wrap(self.socket, parameters))
- self.socket:sni(host)
- if timeout and tonumber(timeout) ~= nil then
- self.socket:settimeout(tonumber(timeout))
- end
- https.try(self.socket:dohandshake())
- https.register(self, getmetatable(self.socket))
- return 1
- end
- return connection
- end
-end
-
-function https.request(request, body, timeout)
- local result = {}
- request = type(request) == 'string' and https.build_table(request, body, result) or request
- timeout = https.timeout or request.timeout or timeout or nil
- if http.PROXY or request.proxy then
- return nil, 'Proxies are not supported!'
- elseif request.redirect then
- return nil, 'Redirects are not supported!'
- elseif request.create then
- return nil, 'The create function is not supported!'
- end
- request.create = https.tcp(request, timeout)
- local res, code, headers, status = http.request(request)
- if res and type(result) == 'table' then
- res = table.concat(result)
- end
- return res, code, headers, status
-end
-
-return https
\ No newline at end of file
diff --git a/libs/redis.lua b/libs/redis.lua
deleted file mode 100644
index 5cf6e7c..0000000
--- a/libs/redis.lua
+++ /dev/null
@@ -1,72 +0,0 @@
---[[
-
- _ _ _ _ _
- _ __ ___ __ _| |_| |_ __ _| |_ __ _ _ __ ___ __| (_)___
- | '_ ` _ \ / _` | __| __/ _` | __/ _` |_____| '__/ _ \/ _` | / __|
- | | | | | | (_| | |_| || (_| | || (_| |_____| | | __/ (_| | \__ \
- |_| |_| |_|\__,_|\__|\__\__,_|\__\__,_| |_| \___|\__,_|_|___/
-
- Copyright (c) 2017 Matthew Hesketh
- See LICENSE for details
-
- mattata-redis is a small Lua library to connect mattata to redis.
- Intended for use with the mattata library, a feature-packed Telegram bot.
-
-]]--
-
-local redis = require('redis')
-local configuration = require('configuration')
-
-redis.commands.hgetall = redis.command('hgetall', {
- ['response'] = function(response, command, ...)
- local request = {}
- for i = 1, #response, 2 do
- local n = response[i]
- request[n] = response[i + 1]
- end
- return request
- end
-})
-
-if not configuration.redis then
- print('The redis table could not be found in configuration.lua!')
- return false
-elseif not configuration.redis.host then
- print('Please specify the host address of your redis database in the redis table of configuration.lua. Unless you have changed it, this will be 127.0.0.1.')
- return false
-elseif not configuration.redis.port then
- print('Please specify the port of your redis database in the redis table of configuration.lua. Unless you have changed it, this will be 6379.')
- return false
-elseif tonumber(configuration.redis.port) == nil then
- print('The value of port in the redis table of configuration.lua must be numerical!')
- return false
-end
-
-local success = pcall(function()
- local params = {
- ['host'] = configuration.redis.host,
- ['port'] = configuration.redis.port
- }
- redis = redis.connect(params)
-end)
-
-if not success then
- print('An error has occured whilst connecting to redis!')
- return false
-end
-
-if configuration.redis.db and configuration.redis.db ~= '' then
- if tonumber(configuration.redis.db) == nil then
- print('The value of db in the redis table of configuration.lua must be numerical!')
- return false
- end
- redis:select(
- tonumber(configuration.redis.db)
- )
-end
-
-if configuration.redis.password and configuration.redis.password ~= '' and type(configuration.redis.password) == 'string' then
- redis:auth(configuration.redis.password)
-end
-
-return redis
\ No newline at end of file
diff --git a/libs/utils.lua b/libs/utils.lua
deleted file mode 100644
index fa1c948..0000000
--- a/libs/utils.lua
+++ /dev/null
@@ -1,477 +0,0 @@
-local utils = {}
-local redis = require('libs.redis')
-local configuration = require('configuration')
-
-local mattata = {}
-local api = {}
-local tools = {}
-
-function utils:init()
- mattata = self
- api = self.api
- tools = self.tools
- return utils
-end
-
-function utils.is_trusted_user(chat_id, user_id)
- if redis:sismember('administration:' .. chat_id .. ':trusted', user_id) then
- return true
- end
- return false
-end
-
-function utils.get_user_count()
- return #redis:keys('user:*:info')
-end
-
-function utils.get_group_count()
- return #redis:keys('chat:*:info')
-end
-
-function utils.get_user_language(user_id)
- return redis:hget('chat:' .. user_id .. ':settings', 'language') or 'en_gb'
-end
-
-function utils.get_log_chat(chat_id)
- local chat = redis:hget('chat:' .. chat_id .. ':settings', 'log chat')
- if chat ~= false and chat ~= nil then
- return chat
- end
- return configuration.log_channel or false
-end
-
-function utils.set_captcha(chat_id, user_id, text, id, timeout)
- local hash = string.format('chat:%s:captcha:%s', tostring(chat_id), tostring(user_id))
- redis:hset(hash, 'id', id)
- redis:hset(hash, 'text', text)
- redis:set('captcha:' .. chat_id .. ':' .. user_id, true)
- redis:expire('captcha:' .. chat_id .. ':' .. user_id, timeout)
- return true
-end
-
-function utils.get_captcha_id(chat_id, user_id)
- return redis:hget('chat:' .. chat_id .. ':captcha:' .. user_id, 'id') or false
-end
-
-function utils.get_captcha_text(chat_id, user_id)
- return redis:hget('chat:' .. chat_id .. ':captcha:' .. user_id, 'text') or false
-end
-
-function utils.delete_redis_hash(hash, field)
- return redis:hdel(hash, field)
-end
-
-function utils.wipe_redis_captcha(chat_id, user_id)
- local hash = string.format('chat:%s:captcha:%s', tostring(chat_id), tostring(user_id))
- redis:hdel(hash, 'id')
- redis:hdel(hash, 'text')
- return true
-end
-
-function utils.get_missing_languages(delimiter)
- local missing_languages = redis:smembers('mattata:missing_languages')
- if not missing_languages then
- return false
- end
- local output = {}
- for _, v in pairs(missing_languages) do
- table.insert(output, v)
- end
- delimiter = delimiter or ', '
- return table.concat(output, delimiter)
-end
-
-function utils.purge_user(user)
- if type(user) ~= 'table' then
- return false
- end
- user = user.from or user
- redis:hdel('user:' .. user.id .. ':info', 'id')
- if user.username or redis:hget('user:' .. user.id .. ':info', 'username') then
- redis:hdel('user:' .. user.id .. ':info', 'username')
- local all = redis:smembers('user:' .. user.id .. ':usernames')
- for _, v in pairs(all) do
- redis:srem('user:' .. user.id .. ':usernames', v)
- end
- redis:del('username:' .. user.id)
- end
- redis:hdel('user:' .. user.id .. ':info', 'first_name')
- if user.name or redis:hget('user:' .. user.id .. ':info', 'name') then
- redis:hdel('user:' .. user.id .. ':info', 'name')
- end
- if user.last_name or redis:hget('user:' .. user.id .. ':info', 'last_name') then
- redis:hdel('user:' .. user.id .. ':info', 'last_name')
- end
- if user.language_code or redis:hget('user:' .. user.id .. ':info', 'language_code') then
- redis:hdel('user:' .. user.id .. ':info', 'language_code')
- end
- return true
-end
-
-function utils.get_list(name)
- name = tostring(name)
- local length = redis:llen(name)
- return redis:lrange(name, 0, tonumber(length) - 1)
-end
-
-function utils.get_inline_help(input, offset)
- offset = offset and tonumber(offset) or 0
- local inline_help = {}
- local count = offset + 1
- local plugin_list = mattata.plugin_list
- for _, plugin in pairs(mattata.administrative_plugin_list) do
- if not tools.table_contains(plugin_list, plugin) then
- table.insert(plugin_list, plugin)
- end
- end
- table.sort(plugin_list)
- for k, v in pairs(plugin_list) do
- -- The bot API only accepts a maximum of 50 results, hence we need the offset.
- if k > offset and k < offset + 50 then
- v = v:gsub('\n', ' ')
- if v:match('^/.- %- .-$') and v:lower():match(input) then
- table.insert(inline_help,
- {
- ['type'] = 'article',
- ['id'] = tostring(count),
- ['title'] = v:match('^(/.-) %- .-$'),
- ['description'] = v:match('^/.- %- (.-)$'),
- ['input_message_content'] = {
- ['message_text'] = utf8.char(8226) .. ' ' .. v:match('^(/.-) %- .-$') .. ' - ' .. v:match('^/.- %- (.-)$')
- }
- })
- count = count + 1
- end
- end
- end
- return inline_help
-end
-
-function utils.string_to_time(str, is_temp_ban)
- if not str then
- return false
- end
- str = tostring(str):gsub('%s', '')
- local base_date = {
- ['year'] = 1970,
- ['month'] = 1,
- ['day'] = 1,
- ['hour'] = 0,
- ['min'] = 0,
- ['sec'] = 0
- }
- local units = {
- ['y'] = 'year',
- ['year'] = 'year',
- ['years'] = 'year',
- ['mo'] = 'month',
- ['month'] = 'month',
- ['months'] = 'month',
- ['w'] = '7day',
- ['week'] = '7day',
- ['weeks'] = '7day',
- ['d'] = 'day',
- ['day'] = 'day',
- ['days'] = 'day',
- ['h'] = 'hour',
- ['hour'] = 'hour',
- ['hours'] = 'hour',
- ['m'] = 'min',
- ['min'] = 'min',
- ['mins'] = 'min',
- ['minute'] = 'min',
- ['minutes'] = 'min',
- ['s'] = 'sec',
- ['sec'] = 'sec',
- ['secs'] = 'sec',
- ['second'] = 'sec',
- ['seconds'] = 'sec'
- }
- for number, unit in str:gmatch('(%d+)(%a+)') do
- local amount, field = units[unit]:match('^(%d*)(%a+)$')
- base_date[field] = base_date[field] + tonumber(number) * (tonumber(amount) or 1)
- end
- local final_length = os.time(base_date)
- if is_temp_ban and final_length <= 59 then
- return false
- end
- return final_length
-end
-
-function utils.get_user_setting(chat_id, user_id, setting)
- if not chat_id or not user_id or not setting then
- return false
- elseif not redis:hexists('user:' .. user_id .. ':' .. chat_id .. ':settings', tostring(setting)) then
- return false
- end
- return true
-end
-
-function utils.is_group(message)
- if not message or not message.chat or not message.chat.type or message.chat.type == 'private' then
- return false
- end
- return true
-end
-
-function utils.input(s)
- local mentioned_user = false
- if not s then
- return false
- elseif type(s) == 'table' then
- if s.entities and #s.entities >= 2 and s.entities[2].type == 'text_mention' then
- mentioned_user = tostring(s.entities[2].user.id)
- end
- s = s.text
- end
- if s:lower():match('^mattata search %a+ for .-$') then
- return s:lower():match('^mattata search %a+ for (.-)$')
- elseif not s:lower():match('^[%%/%%!%%$%%^%%?%%&%%%%]') then
- return s
- end
- local input = s:find(' ')
- if not input then
- return false
- end
- s = s:sub(input + 1)
- input = s:find(' ')
- if mentioned_user then
- s = input and mentioned_user .. ' ' .. s:sub(input + 1) or mentioned_user
- end
- return s
-end
-
-function utils.get_input(message, has_reason)
- local input = utils.input(message)
- if message.reply then
- if not message.reply.from or message.reply.forward_from then
- return false
- elseif has_reason and input then
- return message.reply.from.id, input
- end
- return message.reply.from.id
- elseif not input then
- return false
- elseif has_reason and input:find(' ') then
- return input:match('^(.-) '), input:match(' (.-)$')
- end
- return input
-end
-
-function utils.get_chat_id(chat)
- if not chat then
- return false
- end
- local success = api.get_chat(chat)
- if not success or not success.result then
- return false
- end
- return success.result.id
-end
-
-function utils.get_setting(chat_id, setting)
- if not chat_id or not setting then
- return false
- end
- return redis:hget('chat:' .. chat_id .. ':settings', tostring(setting))
-end
-
-function utils.get_value(chat_id, value)
- if not chat_id or not value then
- return false
- end
- return redis:hget('chat:' .. chat_id .. ':info', tostring(value))
-end
-
-function utils.set_value(chat_id, key, value)
- if not chat_id or not key or not value then
- return false
- end
- return redis:hset('chat:' .. chat_id .. ':info', tostring(key), tostring(value))
-end
-
-function utils.log_error(error_message)
- error_message = tostring(error_message):gsub('%%', '%%%%')
- local output = string.format('%s[31m[Error] %s%s[0m', string.char(27), error_message, string.char(27))
- print(output)
-end
-
-function utils.set_command_action(chat_id, message_id, command)
- local hash = string.format('action:%s:%s', chat_id, message_id)
- return redis:set(hash, command)
-end
-
-function utils.increase_administrative_action(chat_id, user_id, action, increase_by)
- if not increase_by or tonumber(increase_by) == nil then
- increase_by = 1
- end
- local hash = string.format('chat:%s:%s', chat_id, user_id)
- return redis:hincrby(hash, action, increase_by)
-end
-
-function utils.is_allowlisted_link(link, chat_id)
- if link == 'username' or link == 'isiswatch' or link == 'mattata' or link == 'telegram' then
- return true
- elseif chat_id and redis:get('allowlisted_links:' .. chat_id .. ':' .. link:lower()) then
- return true
- end
- return false
-end
-
-function utils.is_valid(message, offset) -- Performs basic checks on the message object to see if it's fit
--- for its purpose. If it's valid, this function will return `true` - otherwise it will return `false`.
- if not message then -- If the `message` object is nil, then we'll ignore it.
- return false, 'No `message` object exists!'
- elseif message.date < os.time() - (offset or 10) then -- We don't want to process old messages, so anything
- -- older than the current system time (giving it a leeway of 10 seconds, unless otherwise specified).
- return false, 'This `message` object is too old!'
- elseif not message.from then -- If the `message.from` object doesn't exist, this will likely
- -- break some more code further down the line!
- return false, 'No `message.from` object exists!'
- end
- return true
-end
-
-function utils.get_chat_members(chat_id)
- return redis:smembers('chat:' .. chat_id .. ':users')
-end
-
-function utils.is_privacy_enabled(user_id)
- return redis:exists('user:' .. user_id .. ':opt_out')
-end
-
-function utils.uses_administration(chat_id)
- return utils.get_setting(chat_id, 'use administration')
-end
-
-function utils.is_plugin_allowed(plugin, is_blocklisted)
- if not is_blocklisted then
- return true
- end
- for _, p in pairs(configuration.blocklist_plugin_exceptions) do
- if p == plugin then
- return true
- end
- end
- return false
-end
-
-function utils.command_action(chat_id, message_id)
- if not chat_id or not message_id then
- return false
- end
- return string.format('action:%s:%s', chat_id, message_id)
-end
-
-function utils.is_fed_admin(fed_id, user_id)
- if not fed_id or not user_id then
- return false
- end
- return redis:sismember('fedadmins:' .. fed_id, user_id)
-end
-
-function utils.is_fed_creator(fed_id, user_id)
- if not fed_id or not user_id then
- return false
- end
- local creator = redis:hget('fed:' .. fed_id, 'creator')
- return tonumber(user_id) == tonumber(creator) and true or false
-end
-
-function utils.is_user_fedbanned(chat_id, user_id)
- if not chat_id or not user_id then
- return false
- end
- local feds = redis:smembers('chat:' .. chat_id .. ':feds')
- if #feds == 0 then
- return false
- end
- for _, fed in pairs(feds) do
- if redis:sismember('fedbans:' .. fed, user_id) then
- return true
- end
- end
- return false
-end
-
-function utils.has_fed(user_id, fed_id)
- if not user_id then
- return false
- end
- local feds = redis:smembers('feds:' .. user_id)
- if #feds > 0 then
- if fed_id then
- for _, fed in pairs(feds) do
- if fed_id == fed then
- return true, fed
- end
- end
- return false
- end
- return true, feds[1], true
- end
- return false
-end
-
-function utils.fed_ban_chat_member(chat_id, user_id, fed_list)
- if not chat_id or not user_id then
- return false
- end
- fed_list = type(fed_list) == 'table' and fed_list or { fed_list }
- api.ban_chat_member(chat_id, user_id)
- local success
- for _, fed in pairs(fed_list) do
- success = redis:sadd('fedbans:' .. fed, user_id)
- end
- return success
-end
-
-function utils.fed_unban_chat_member(chat_id, user_id, fed_list)
- if not chat_id or not user_id then
- return false
- end
- fed_list = type(fed_list) == 'table' and fed_list or { fed_list }
- local success
- api.unban_chat_member(chat_id, user_id)
- for _, fed in pairs(fed_list) do
- success = redis:srem('fedbans:' .. fed, user_id)
- end
- return success
-end
-
-function utils.is_fed_banned(fed_id, user_id)
- if not fed_id or not user_id then
- return false
- end
- return redis:sismember('fedbans:' .. fed_id, user_id) and true or false
-end
-
-function utils.get_feds(chat_id)
- if not chat_id then
- return false
- end
- return redis:smembers('chat:' .. chat_id .. ':feds')
-end
-
-function utils.get_fed_bans(fed_id)
- if not fed_id then
- return false
- end
- return #redis:smembers('fedbans:' .. fed_id)
-end
-
-function utils.fed_allowlist(chat_id, user_id)
- if not chat_id or not user_id then
- return false
- end
- return redis:sadd('fedallowlist:' .. chat_id, user_id)
-end
-
-function utils.is_user_fed_allowlisted(chat_id, user_id)
- if not chat_id or not user_id then
- return false
- end
- return redis:sismember('fedallowlist:' .. chat_id, user_id) and true or false
-end
-
-return utils
\ No newline at end of file
diff --git a/mattata.lua b/mattata.lua
deleted file mode 100644
index c111c25..0000000
--- a/mattata.lua
+++ /dev/null
@@ -1,1425 +0,0 @@
---[[
- _ _ _
- _ __ ___ __ _| |_| |_ __ _| |_ __ _
- | '_ ` _ \ / _` | __| __/ _` | __/ _` |
- | | | | | | (_| | |_| || (_| | || (_| |
- |_| |_| |_|\__,_|\__|\__\__,_|\__\__,_|
-
- v1.5
-
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- See LICENSE for details
-
-]]
-
-local mattata = {}
-local https = require('ssl.https')
-local ltn12 = require('ltn12')
-local json = require('dkjson')
-local redis = dofile('libs/redis.lua')
-local configuration = require('configuration')
-local api = require('telegram-bot-lua.core').configure(configuration.bot_token)
-local tools = require('telegram-bot-lua.tools')
-local socket = require('socket')
-local utils = dofile('libs/utils.lua')
-local html = require('htmlEntities')
-
-local plugin_list = {}
-local administrative_plugin_list = {}
-local inline_plugin_list = {}
-
-function mattata:init()
- if mattata.is_reloading then
- configuration = require('configuration')
- mattata.is_reloading = false
- end
- self.info = api.info -- Set the bot's information to the object fetched from the Telegram bot API.
- mattata.info = api.info
- self.plugins = {} -- Make a table for the bot's plugins.
- self.api = api
- self.tools = tools
- self.configuration = configuration
- self.beta_plugins = {}
- self.chats = {}
- self.users = {}
- self.replies = {}
- for k, v in ipairs(configuration.plugins) do -- Iterate over all of the configured plugins.
- local true_path = v
- for _, p in pairs(configuration.administrative_plugins) do
- if v == p then
- true_path = 'administration.' .. v
- end
- end
- for _, p in pairs(configuration.beta_plugins) do
- if v == p then
- table.insert(self.beta_plugins, v)
- end
- end
- local plugin = require('plugins.' .. true_path) -- Load each plugin.
- if not plugin then
- error('Invalid plugin: ' .. true_path)
- elseif mattata.is_duplicate(configuration.plugins, v) then
- error('Duplicate plugin: ' .. v)
- end
- plugin.is_administrative = true_path:match('^administration%.') and true or false
- self.plugins[k] = plugin
- self.plugins[k].name = v
- if self.beta_plugins[v] then
- plugin.is_beta_plugin = true
- end
- if plugin.init then -- If the plugin has an `init` function, run it.
- plugin.init(self, configuration)
- end
- plugin.is_administrative = (self.plugins[k].name == 'administration' or true_path:match('^administration%.')) and true or false
- -- By default, a plugin doesn't have inline functionality; but, if it does, set it to `true` appropriately.
- plugin.is_inline = plugin.on_inline_query and true or false
- plugin.commands = plugin.commands or {} -- If the plugin hasn't got any commands configured, then set a blank
- -- table, so when it comes to iterating over the commands later on, the bot won't encounter any problems.
- if plugin.help and not plugin.is_beta_plugin then -- If the plugin has help documentation, then insert it into other tables (where necessary).
- if plugin.is_administrative then
- table.insert(administrative_plugin_list, plugin.help)
- else
- table.insert(plugin_list, plugin.help)
- if plugin.is_inline then -- If the plugin is inline and has documentation, then insert the documentation into
- -- the `inline_plugin_list` table.
- table.insert(inline_plugin_list, plugin.help)
- end
- end
- plugin.help = 'Usage:\n' .. plugin.help:gsub('%. (Alias)', '.\n%1') -- Make the plugin's documentation style all nicely unified, for consistency.
- end
- self.plugin_list = plugin_list
- self.inline_plugin_list = inline_plugin_list
- self.administrative_plugin_list = administrative_plugin_list
- end
- print(configuration.connected_message)
- local info_message = '\tUsername: @' .. self.info.username .. '\n\tName: ' .. self.info.name .. '\n\tID: ' .. self.info.id
- print('\n' .. info_message .. '\n')
- if redis:get('mattata:version') ~= configuration.version then
- local success = dofile('migrate.lua')
- print(success)
- end
- self.version = configuration.version
- -- Make necessary database changes if the version has changed.
- if not redis:get('mattata:version') or redis:get('mattata:version') ~= self.version then
- redis:set('mattata:version', self.version)
- end
- self.last_update = self.last_update or 0 -- If there is no last update known, make it 0 so the bot doesn't encounter any problems when it tries to add the necessary increment.
- self.last_backup = self.last_backup or os.date('%V')
- self.last_cron = self.last_cron or os.date('%M')
- self.last_cache = self.last_cache or os.date('%d')
- local init_message = '<pre>' .. configuration.connected_message .. '\n\n' .. mattata.escape_html(info_message) .. '\n\n\tPlugins loaded: ' .. #configuration.plugins - #configuration.administrative_plugins .. '\n\tAdministrative plugins loaded: ' .. #configuration.administrative_plugins .. '</pre>'
- mattata.send_message(configuration.log_chat, init_message:gsub('\t', ''), 'html')
- for _, admin in pairs(configuration.admins) do
- mattata.send_message(admin, init_message:gsub('\t', ''), 'html')
- end
- local shutdown = redis:get('mattata:shutdown')
- if shutdown then
- local chat_id, message_id = shutdown:match('^(%-?%d+):(%d*)$')
- mattata.edit_message_text(chat_id, message_id, 'Successfully rebooted!')
- redis:del('mattata:shutdown')
- end
- return true
-end
-
--- Set a bunch of function aliases, for consistency & compatibility.
-for i, v in pairs(api) do
- mattata[i] = v
-end
-for i, v in pairs(tools) do
- mattata[i] = v
-end
-for i, v in pairs(utils) do
- if i ~= 'init' then
- mattata[i] = v
- end
-end
-
-function mattata:run(_, token)
--- mattata's main long-polling function which repeatedly checks the Telegram bot API for updates.
--- The objects received in the updates are then further processed through object-specific functions.
- token = token or configuration.bot_token
- assert(token, 'You need to enter your Telegram bot API token in configuration.lua, or pass it as the second argument when using the mattata:run() function!')
- mattata.is_running = mattata.init(self) -- Initialise the bot.
- utils.init(self, configuration)
- while mattata.is_running do -- Perform the main loop whilst the bot is running.
- local success = api.get_updates( -- Check the Telegram bot API for updates.
- configuration.updates.timeout,
- self.last_update + 1,
- configuration.updates.limit,
- json.encode(
- {
- 'message',
- 'edited_message',
- 'inline_query',
- 'callback_query'
- }
- ),
- configuration.use_beta_endpoint or false
- )
- if success and success.result then
- for _, v in ipairs(success.result) do
- self.last_update = v.update_id
- self.execution_time = socket.gettime()
- if v.message or v.edited_message then
- if v.edited_message then
- v.message = v.edited_message
- v.edited_message = nil
- v.message.old_date = v.message.date
- v.message.date = v.message.edit_date
- v.message.edit_date = nil
- v.message.is_edited = true
- else
- v.message.is_edited = false
- end
- if v.message.reply_to_message then
- v.message.reply = v.message.reply_to_message -- Make the `update.message.reply_to_message`
- -- object `update.message.reply` to make any future handling easier.
- v.message.reply_to_message = nil -- Delete the old value by setting its value to nil.
- end
- mattata.on_message(self, v.message)
- if configuration.debug then
- print(
- string.format(
- '%s[36m[Update #%s] Message%s from %s to %s: %s%s[0m',
- string.char(27),
- v.update_id,
- v.message.is_edited and ' edit' or '',
- v.message.from.id,
- v.message.chat.id,
- v.message.text,
- string.char(27)
- )
- )
- end
- elseif v.inline_query then
- mattata.on_inline_query(self, v.inline_query)
- if configuration.debug then
- print(
- string.format(
- '%s[35m[Update #%s] Inline query from %s%s[0m',
- string.char(27),
- v.update_id,
- v.inline_query.from.id,
- string.char(27)
- )
- )
- end
- elseif v.callback_query then
- if v.callback_query.message and v.callback_query.message.reply_to_message then
- v.callback_query.message.reply = v.callback_query.message.reply_to_message
- v.callback_query.message.reply_to_message = nil
- end
- mattata.on_callback_query(self, v.callback_query.message, v.callback_query)
- if configuration.debug then
- print(
- string.format(
- '%s[33m[Update #%s] Callback query from %s%s[0m',
- string.char(27),
- v.update_id,
- v.callback_query.from.id,
- string.char(27)
- )
- )
- end
- end
- self.result_time = socket.gettime() - self.execution_time
- if configuration.debug then
- print('Update #' .. v.update_id .. ' took ' .. self.result_time .. ' seconds to process.')
- end
- end
- else
- mattata.log_error('There was an error retrieving updates from the Telegram bot API!')
- end
- if self.last_backup ~= os.date('%V') then -- If it's been a week since the last backup, perform another backup.
- self.last_backup = os.date('%V') -- Set the last backup time to now, since we're
- -- now performing one!
- print(io.popen('./backup.sh'):read('*all'))
- end
- if self.last_cron ~= os.date('%M') then -- Perform minutely CRON jobs.
- self.last_cron = os.date('%M')
- for i = 1, #self.plugins do
- local plugin = self.plugins[i]
- if plugin and plugin.cron then
- local cron_success, res = pcall(function()
- plugin.cron(self, configuration)
- end)
- if not cron_success then
- mattata.exception(self, res, 'CRON: ' .. i, configuration.log_chat)
- end
- end
- end
- end
- if self.last_cache ~= os.date('%d') then -- Reset the bot's cache.
- self.last_cache = os.date('%d')
- self.chats = {}
- self.users = {}
- self.replies = {}
- end
- end
- print(self.info.first_name .. ' is shutting down...')
-end
-
-function mattata:on_message(message)
-
- -- If the message is old or is missing necessary fields/values, then we'll stop and allow the bot to start processing the next update(s).
- -- If the message was sent from a blocklisted chat, then we'll stop because we don't want the bot to respond there.
- if not mattata.is_valid(message) then
- return false
- elseif redis:get('blocklisted_chats:' .. message.chat.id) then
- return mattata.leave_chat(message.chat.id)
- end
- message = mattata.sort_message(message) -- Process the message.
- self.is_user_blocklisted, self.is_globally_blocklisted, self.is_globally_banned = mattata.is_user_blocklisted(message)
- -- We only want this functionality if the bot owner has been granted API permission to SpamWatch!
- self.is_spamwatch_blocklisted = configuration.keys.spamwatch ~= '' and mattata.is_spamwatch_blocklisted(message) or false
-
- if self.is_globally_banned and message.chat.type ~= 'private' then -- Only for the worst of the worst
- mattata.ban_chat_member(message.chat.id, message.from.id)
- end
- local language = require('languages.' .. mattata.get_user_language(message.from.id))
- if mattata.is_group(message) and mattata.get_setting(message.chat.id, 'force group language') then
- language = require('languages.' .. (mattata.get_value(message.chat.id, 'group language') or 'en_gb'))
- end
- self.language = language
- if mattata.process_spam(message, configuration) then
- return false
- end
-
- -- Perform the following actions if the user isn't blocklisted.
- if not self.is_user_blocklisted then
- mattata.process_afk(self, message)
- mattata.process_language(self, message)
- if message.text then
- message = mattata.process_natural_language(self, message)
- end
- message = mattata.process_stickers(message)
- message = mattata.check_links(message, false, true, false, true)
- message = mattata.process_deeplinks(message)
- -- If the user isn't current AFK, and they say they're going to be right back, we can
- -- assume that they are now going to be AFK, so we'll help them out and set them that
- -- way by making the message text the /afk command, which will later trigger the plugin.
- if (message.text:lower():match('^i?\'?l?l? ?[bg][rt][bg].?$') and not redis:hget('afk:' .. message.from.id, 'since')) then
- message.text = '/afk'
- end
- -- A boolean value to decide later on, whether the message is intended for the current plugin from the iterated table.
- message = mattata.process_nicknames(message)
- if not self.chats[tostring(message.chat.id)] then
- self.chats[tostring(message.chat.id)] = message.chat
- self.chats[tostring(message.chat.id)].disabled_plugins = redis:smembers('disabled_plugins:' .. message.chat.id) or {}
- end
- if message.reply then
- if not self.replies[tostring(message.chat.id)] then
- self.replies[tostring(message.chat.id)] = {}
- end
- if not self.replies[tostring(message.chat.id)][tostring(message.message_id)] then
- self.replies[tostring(message.chat.id)][tostring(message.message_id)] = message.reply
- end
- if self.replies[tostring(message.chat.id)][tostring(message.reply.message_id)] then
- message.reply.reply = self.replies[tostring(message.chat.id)][tostring(message.reply.message_id)]
- end
- end
- end
- self.is_command = false
- self.is_command_done = false
- self.is_allowed_beta_access = false
- self.is_telegram = false
-
- -- If the message is one of those pesky Telegram channel pins, it won't send a service message. We'll trick it.
- if message.from.id == 777000 and message.forward_from_chat and message.forward_from_chat.type == 'channel' then
- self.is_telegram = true
- message.is_service_message = true
- message.service_message = 'pinned_message'
- message.pinned_message = {
- ['text'] = message.text,
- ['date'] = message.date,
- ['chat'] = message.chat,
- ['from'] = message.from,
- ['message_id'] = message.message_id,
- ['entities'] = message.entities,
- ['forward_from_message_id'] = message.forward_from_message_id,
- ['forward_from_chat'] = message.forward_from_chat,
- ['forward_date'] = message.forward_date
- }
- end
-
- if message.text:match('^[/!#][%w_]+') and message.chat.type == 'supergroup' then
- local command, input = message.text:lower():match('^[/!#]([%w_]+)(.*)$')
- local all = redis:hgetall('chat:' .. message.chat.id .. ':aliases')
- for alias, original in pairs(all) do
- if command == alias then
- message.text = '/' .. original .. input
- message.is_alias = true
- break
- end
- end
- end
-
- -- This is the main loop which iterates over configured plugins and runs the appropriate functions.
- for _, plugin in ipairs(self.plugins) do
- if not mattata.is_plugin_disabled(self, plugin.name, message) then
- if plugin.is_beta_plugin and mattata.is_global_admin(message.from.id) then
- self.is_allowed_beta_access = true
- end
- if not plugin.is_beta_plugin or (plugin.is_beta_plugin and self.is_allowed_beta_access) then
- local commands = #plugin.commands or {}
- for i = 1, commands do
- if message.text:match(plugin.commands[i]) and mattata.is_plugin_allowed(plugin.name, self.is_user_blocklisted, configuration) and not self.is_command_done and not self.is_telegram and (not message.is_edited or mattata.is_global_admin(message.from.id)) then
- self.is_command = true
- message.command = plugin.commands[i]:match('([%w_%-]+)')
- if plugin.on_message then
- local old_message = message.text
- if mattata.is_global_admin(message.from.id) and message.text:match('^.- && .-$') then
- message.text = message.text:match('^(.-) && .-$')
- end
- local success, result = pcall(function()
- return plugin.on_message(self, message, configuration, language)
- end)
- message.text = old_message
- if not success then
- mattata.exception(self, result, string.format('%s: %s', message.from.id, message.text), configuration.log_chat)
- end
- if mattata.get_setting(message.chat.id, 'delete commands') and self.is_command and not redis:sismember('chat:' .. message.chat.id .. ':no_delete', tostring(plugin.name)) and not message.is_natural_language then
- mattata.delete_message(message.chat.id, message.message_id)
- end
- self.is_command_done = true
- end
- end
- end
- end
-
- -- Allow plugins to handle new chat participants.
- if message.new_chat_members and plugin.on_member_join then
- local success, result = pcall(function()
- return plugin.on_member_join(self, message, configuration, language)
- end)
- if not success then
- mattata.exception(self, result, string.format('%s: %s', message.from.id, message.text),
- configuration.log_chat)
- end
- end
-
- -- Allow plugins to handle every new message (handy for anti-spam).
- if (message.text or message.is_media) and plugin.on_new_message then
- local success, result = pcall(function()
- return plugin.on_new_message(self, message, configuration, language)
- end)
- if not success then
- mattata.exception(self, result, string.format('%s: %s', message.from.id, message.text or tostring(message.media_type),
- configuration.log_chat))
- end
- end
-
- -- Allow plugins to handle service messages, and pass the type of service message before the message object.
- if message.is_service_message and plugin.on_service_message then
- local success, result = pcall(function()
- return plugin.on_service_message(self, message.service_message:gsub('_', ' '), message, configuration, language)
- end)
- if not success then
- mattata.exception(self, result, string.format('%s: %s', message.from.id, message.text or tostring(message.media_type),
- configuration.log_chat))
- end
- end
- end
- end
- mattata.process_message(self, message)
- self.is_done = true
- self.is_command_done = false
- self.is_ai = false
- return
-end
-
-function mattata:on_inline_query(inline_query)
- if not inline_query.from then
- return false, 'No `inline_query.from` object was found!'
- elseif redis:get('global_blocklist:' .. inline_query.from.id) then
- return false, 'This user is globally blocklisted!'
- end
- local language = require('languages.' .. mattata.get_user_language(inline_query.from.id))
- inline_query.offset = inline_query.offset and tonumber(inline_query.offset) or 0
- for _, plugin in ipairs(self.plugins) do
- local plugins = plugin.commands or {}
- for i = 1, #plugins do
- local command = plugin.commands[i]
- if not inline_query then
- return false, 'No `inline_query` object was found!'
- end
- if inline_query.query:match(command)
- and plugin.on_inline_query
- then
- local success, result = pcall(
- function()
- return plugin.on_inline_query(self, inline_query, configuration, language)
- end
- )
- if not success then
- local exception = string.format('%s: %s', inline_query.from.id, inline_query.query)
- mattata.exception(self, result, exception, configuration.log_chat)
- return false, result
- elseif not result then
- return api.answer_inline_query(
- inline_query.id,
- api.inline_result()
- :id()
- :type('article')
- :title(configuration.errors.results)
- :description(plugin.help)
- :input_message_content(api.input_text_message_content(plugin.help))
- )
- end
- end
- end
- end
- if not inline_query.query or inline_query.query:gsub('%s', '') == '' then
- local offset = inline_query.offset and tonumber(inline_query.offset) or 0
- local list = mattata.get_inline_list(self.info.username, offset)
- if #list == 0 then
- local title = 'No more results found!'
- local description = 'There were no more inline features found. Use @' .. self.info.username .. ' <query> to search for more information about commands matching the given search query.'
- return mattata.send_inline_article(inline_query.id, title, description)
- end
- return mattata.answer_inline_query(inline_query.id, json.encode(list), 0, false, tostring(offset + 50))
- end
- local help = require('plugins.help')
- return help.on_inline_query(self, inline_query, configuration, language)
-end
-
-function mattata:on_callback_query(message, callback_query)
- if not callback_query.from then return false end
- if not callback_query.message or not callback_query.message.chat then
- message = {
- ['chat'] = {},
- ['message_id'] = callback_query.inline_message_id,
- ['from'] = callback_query.from
- }
- else
- message = callback_query.message
- message.exists = true
- message = mattata.process_nicknames(message)
- callback_query = mattata.process_nicknames(callback_query)
- end
- if not self.chats[tostring(message.chat.id)] then
- self.chats[tostring(message.chat.id)] = message.chat
- self.chats[tostring(message.chat.id)].disabled_plugins = redis:smembers('disabled_plugins:' .. message.chat.id) or {}
- end
- local language = require('languages.' .. mattata.get_user_language(callback_query.from.id))
- if message.chat.id and mattata.is_group(message) and mattata.get_setting(message.chat.id, 'force group language') then
- language = require('languages.' .. (mattata.get_value(message.chat.id, 'group language') or 'en_gb'))
- end
- self.language = language
- if redis:get('global_blocklist:' .. callback_query.from.id) and not callback_query.data:match('^join_captcha') and not mattata.is_global_admin(callback_query.from.id) then
- return false, 'This user is globally blocklisted!'
- elseif message and message.exists then
- if message.reply and message.chat.type ~= 'channel' and callback_query.from.id ~= message.reply.from.id and not callback_query.data:match('^game:') and not callback_query.data:match('^report:') and not mattata.is_global_admin(callback_query.from.id) then
- local output = 'Only ' .. message.reply.from.first_name .. ' can use this!'
- return mattata.answer_callback_query(callback_query.id, output)
- end
- end
- for _, plugin in ipairs(self.plugins) do
- if not callback_query.data or not callback_query.from then
- return false
- elseif plugin.name == callback_query.data:match('^(.-):.-$') and plugin.on_callback_query then
- callback_query.data = callback_query.data:match('^[%a_]+:(.-)$')
- if not callback_query.data then
- plugin = callback_query.data
- callback_query = ''
- end
- local success, result = pcall(
- function()
- return plugin.on_callback_query(self, callback_query, message or false, configuration, language)
- end
- )
- if not success then
- mattata.send_message(configuration.admins[1], json.encode(callback_query, {indent=true}))
- -- mattata.answer_callback_query(callback_query.id, language['errors']['generic'])
- local exception = string.format('%s: %s', callback_query.from.id, callback_query.data)
- mattata.exception(self, result, exception, configuration.log_chat)
- return false, result
- end
- end
- end
- return true
-end
-
-mattata.send_message = api.send_message
-
-
--- A variant of mattata.send_message(), optimised for sending a message as a reply that forces a
--- reply back from the user.
-function mattata.send_force_reply(message, text, parse_mode, disable_web_page_preview, token)
- local success = api.send_message(
- message,
- text,
- parse_mode,
- disable_web_page_preview,
- false,
- message.message_id,
- '{"force_reply":true,"selective":true}',
- token
- )
- return success
-end
-
-function mattata.get_chat(chat_id, only_api, token)
- local user = mattata.get_user(chat_id)
- if user then
- return user
- end
- local success = api.get_chat(chat_id, token)
- if only_api then -- stops antispam using usernames stored in the database
- return success
- elseif success and success.result.type == 'private' then
- mattata.process_user(success.result)
- elseif success then
- mattata.process_chat(success.result)
- end
- chat_id = success and success.result.id or chat_id
- local result = redis:hgetall('chat:' .. tostring(chat_id) .. ':info')
- if not result or type(result) == 'table' and not next(result) then
- return false
- end
- success.result = result
- if not success.result.id then
- success.result.id = chat_id
- redis:hset('chat:' .. chat_id .. ':info', 'id', chat_id)
- end
- return success
-end
-
-function mattata:is_plugin_disabled(plugin, message)
- if not plugin or not message then
- return false
- end
- plugin = plugin:lower():gsub('^administration/', '')
- if mattata.table_contains(configuration.permanent_plugins, plugin) then
- return false
- elseif type(message) ~= 'table' then
- message = {
- ['chat'] = {
- ['id'] = message
- }
- }
- if tostring(message.chat.id):match('^%-100') then
- message.chat.type = 'supergroup'
- else
- message.chat.type = 'private'
- end
- end
- if not self.chats[tostring(message.chat.id)] then
- self.chats[tostring(message.chat.id)] = message.chat
- end
- if not self.chats[tostring(message.chat.id)].disabled_plugins then
- self.chats[tostring(message.chat.id)].disabled_plugins = redis:smembers('disabled_plugins:' .. message.chat.id)
- end
- if not mattata.table_contains(self.chats[tostring(message.chat.id)].disabled_plugins, plugin) then
- return false
- end
- local exists = redis:sismember('disabled_plugins:' .. message.chat.id, plugin)
- return exists and true or false
-end
-
-function mattata:exception(err, message, log_chat)
- local output = string.format(
- '[%s]\n%s: %s\n%s\n',
- os.date('%X'),
- self.info.username,
- mattata.escape_html(err) or '',
- mattata.escape_html(message)
- )
- if log_chat then
- return mattata.send_message(
- log_chat,
- string.format('<pre>%s</pre>', output),
- 'html'
- )
- end
- return output
-end
-
-function mattata.is_group_admin(chat_id, user_id, is_real_admin)
- if not chat_id or not user_id then
- return false
- elseif mattata.is_global_admin(chat_id) or mattata.is_global_admin(user_id) then
- return true
- elseif not is_real_admin and mattata.is_group_mod(chat_id, user_id) then
- return true
- end
- local user, res = mattata.get_chat_member(chat_id, user_id)
- if not user or not user.result then
- return false, res
- elseif user.result.status == 'creator' or user.result.status == 'administrator' then
- return true, res
- end
- return false, user.result.status
-end
-
-function mattata.is_group_mod(chat_id, user_id)
- if not chat_id or not user_id then
- return false
- elseif redis:sismember('administration:' .. chat_id .. ':mods', user_id) then
- return true
- end
- return false
-end
-
-function mattata.process_chat(chat)
- chat.id_str = tostring(chat.id)
- if chat.type == 'private' then
- return mattata.process_user(chat)
- end
- if not redis:hexists('chat:' .. chat.id .. ':info', 'id') then
- print(
- string.format(
- '%s[34m[+] Added the chat %s to the database!%s[0m',
- string.char(27),
- chat.username and '@' .. chat.username or chat.id,
- string.char(27)
- )
- )
- end
- redis:hset('chat:' .. chat.id .. ':info', 'title', chat.title)
- redis:hset('chat:' .. chat.id .. ':info', 'type', chat.type)
- if chat.username then
- chat.username = chat.username:lower()
- redis:hset('chat:' .. chat.id .. ':info', 'username', chat.username)
- redis:set('username:' .. chat.username, chat.id)
- if not redis:sismember('chat:' .. chat.id .. ':usernames', chat.username) then
- redis:sadd('chat:' .. chat.id .. ':usernames', chat.username)
- end
- end
- redis:hset('chat:' .. chat.id .. ':info', 'id', chat.id)
- return chat
-end
-
-function mattata.process_user(user)
- if not user then return user end
- if not user.id or not user.first_name then return false end
- redis:hset('user:' .. user.id .. ':info', 'id', user.id)
- local new = false
- user.name = user.first_name
- if user.last_name then
- user.name = user.name .. ' ' .. user.last_name
- end
- if not redis:hget('user:' .. user.id .. ':info', 'id') and configuration.debug then
- print(
- string.format(
- '%s[34m[+] Added the user %s to the database!%s%s[0m',
- string.char(27),
- user.username and '@' .. user.username or user.id,
- user.language_code and ' Language: ' .. user.language_code or '',
- string.char(27)
- )
- )
- new = true
- elseif configuration.debug then
- print(
- string.format(
- '%s[34m[+] Updated information about the user %s in the database!%s%s[0m',
- string.char(27),
- user.username and '@' .. user.username or user.id,
- user.language_code and ' Language: ' .. user.language_code or '',
- string.char(27)
- )
- )
- end
- redis:hset('user:' .. user.id .. ':info', 'type', 'private')
- redis:hset('user:' .. user.id .. ':info', 'name', user.name)
- redis:hset('user:' .. user.id .. ':info', 'first_name', user.first_name)
- if user.last_name then
- redis:hset('user:' .. user.id .. ':info', 'last_name', user.last_name)
- else
- redis:hdel('user:' .. user.id .. ':info', 'last_name')
- end
- if user.username then
- user.username = user.username:lower()
- redis:hset('user:' .. user.id .. ':info', 'username', user.username)
- redis:set('username:' .. user.username, user.id)
- if not redis:sismember('user:' .. user.id .. ':usernames', user.username) then
- redis:sadd('user:' .. user.id .. ':usernames', user.username)
- end
- else
- redis:hdel('user:' .. user.id .. ':info', 'username')
- end
- if user.language_code then
- if mattata.does_language_exist(user.language_code) and not redis:hget('chat:' .. user.id .. ':settings', 'language') then
- -- If a translation exists for the user's language code, and they haven't selected
- -- a language already, then set it as their primary language!
- redis:hset('chat:' .. user.id .. ':settings', 'language', user.language_code)
- end
- redis:hset('user:' .. user.id .. ':info', 'language_code', user.language_code)
- else
- redis:hdel('user:' .. user.id .. ':info', 'language_code')
- end
- redis:hset('user:' .. user.id .. ':info', 'is_bot', tostring(user.is_bot))
- if new then
- redis:hset('user:' .. user.id .. ':info', 'id', user.id)
- end
- if redis:get('nick:' .. user.id) then
- user.first_name = redis:get('nick:' .. user.id)
- user.name = user.first_name
- user.last_name = nil
- end
- return user, new
-end
-
-function mattata.sort_message(message)
- message.is_natural_language = false
- message.text = message.text or message.caption or '' -- Ensure there is always a value assigned to message.text.
- message.text = message.text:gsub('^/(%a+)%_', '/%1 ')
- if message.text:match('^[/!#]start .-$') then -- Allow deep-linking through the /start command.
- message.text = '/' .. message.text:match('^[/!#]start (.-)$')
- end
- message.is_media = mattata.is_media(message)
- message.media_type = mattata.media_type(message)
- message.file_id = mattata.file_id(message)
- message.is_alias = false -- We sort this later.
- message.is_service_message, message.service_message = mattata.service_message(message)
- if message.caption_entities then
- message.entities = message.caption_entities
- message.caption_entities = nil
- end
- if message.from.language_code then
- message.from.language_code = message.from.language_code:lower():gsub('%-', '_') -- make it fit with the names of our language files
- if message.from.language_code:len() == 2 and message.from.language_code ~= 'en' then
- message.from.language_code = message.from.language_code .. '_' .. message.from.language_code
- elseif message.from.language_code:len() == 2 or message.from.language_code == 'root' then -- not sure why but some english users were having `root` return as their language
- message.from.language_code = 'en_us'
- end
- end
- message.reply = message.reply and mattata.sort_message(message.reply) or nil
- if message.from then
- message.from = mattata.process_user(message.from)
- end
- if message.reply then
- message.reply.from = mattata.process_user(message.reply.from)
- end
- if message.forward_from then
- message.forward_from = mattata.process_user(message.forward_from)
- end
- if message.chat and message.chat.type ~= 'private' then
- -- Add the user to the set of users in the current chat.
- if configuration.administration.store_chat_members and message.from then
- if not redis:sismember('chat:' .. message.chat.id .. ':users', message.from.id) then
- redis:sadd('chat:' .. message.chat.id .. ':users', message.from.id)
- end
- end
- if message.new_chat_members then
- message.chat = mattata.process_chat(message.chat)
- for i = 1, #message.new_chat_members do
- if configuration.administration.store_chat_users then
- redis:sadd('chat:' .. message.chat.id .. ':users', message.new_chat_members[i].id) -- add users to the chat's set in the database
- end
- message.new_chat_members[i] = mattata.process_user(message.new_chat_members[i])
- end
- elseif message.left_chat_member then -- if they've left the chat then there's no need for them to be in the set anymore
- message.chat = mattata.process_chat(message.chat)
- message.left_chat_member = mattata.process_user(message.left_chat_member)
- if configuration.administration.store_chat_users then
- redis:srem('chat:' .. message.chat.id .. ':users', message.left_chat_member.id)
- end
- end
- end
- if message.text and message.chat and message.reply and message.reply.from and message.reply.from.id == api.info.id then
- local action = redis:get('action:' .. message.chat.id .. ':' .. message.reply.message_id)
- -- If an action was saved for the replied-to message (as part of a multiple step command), then
- -- we'll get information about the action.
- if action then
- message.text = action .. ' ' .. message.text -- Concatenate the saved action's command
- -- with the new `message.text`.
- message.reply = nil -- This caused some issues with administrative commands which would
- -- prioritise replied-to users over users given by arguments.
- redis:del(action) -- Delete the action for this message, since we've done what we needed to do
- -- with it now.
- end
- end
- if message.entities then
- for n, entities in pairs(message.entities) do
- if entities.type == 'text_mention' then
- message.text = message.text:gsub(message.entities[n].user.first_name, message.entities[n].user.id)
- end
- end
- end
- return message
-end
-
-function mattata.is_global_admin(id)
- for _, v in pairs(configuration.admins) do
- if id == v then
- return true
- end
- end
- return false
-end
-
-function mattata.get_user(input, force_api, is_id_plugin, cache_only)
- if tonumber(input) == nil and input then -- check it's not an ID
- input = input:match('^%@?(.-)$')
- input = redis:get('username:' .. input:lower())
- end
- if not input or tonumber(input) == nil then -- if it's still not an ID then we'll give up
- return false
- end
- local user = redis:hgetall('user:' .. tostring(input) .. ':info')
- if is_id_plugin and user.id then
- local success = mattata.get_chat(user.id) -- Try and get latest info about the user for the ID plugin
- if success then
- return success
- end
- end
- if user.username and not cache_only then
- local scrape, scrape_res = https.request('https://t.me/' .. user.username)
- if scrape_res == 200 then
- local bio = scrape:match('%<div class="tgme_page_description "%>(.-)%</div%>')
- if bio then
- bio = bio:gsub('%b<>', '')
- bio = html.decode(bio)
- user.bio = bio
- end
- end
- end
- if user.id then
- return {
- ['result'] = {
- ['id'] = tonumber(user.id),
- ['type'] = user.type,
- ['name'] = user.name,
- ['first_name'] = user.first_name,
- ['last_name'] = user.last_name,
- ['username'] = user.username,
- ['is_bot'] = user.is_bot,
- ['bio'] = user.bio
- }
- }
- end
- if force_api then
- return mattata.get_chat(input)
- end
- return false
-end
-
-function mattata.get_inline_list(username, offset)
- offset = offset and tonumber(offset) or 0
- local inline_list = {}
- table.sort(inline_plugin_list)
- for k, v in pairs(inline_plugin_list) do
- if k > offset and k < offset + 50 then -- The bot API only accepts a maximum of 50 results, hence we need the offset.
- v = v:gsub('\n', ' ')
- table.insert(
- inline_list,
- mattata.inline_result()
- :type('article')
- :id(tostring(k))
- :title(v:match('^(/.-) %- .-$'))
- :description(v:match('^/.- %- (.-)$'))
- :input_message_content(
- mattata.input_text_message_content(
- string.format(
- '• %s - %s\n\nTo use this command inline, you must use the syntax:\n@%s %s',
- v:match('^(/.-) %- .-$'),
- v:match('^/.- %- (.-)$'),
- username,
- v:match('^(/.-) %- .-$')
- )
- )
- )
- :reply_markup(
- mattata.inline_keyboard():row(
- mattata.row():switch_inline_query_button('Show me how!', v:match('^(/.-) '))
- )
- )
- )
- end
- end
- return inline_list
-end
-
-function mattata:get_help(is_administrative, chat_id)
- local list_to_use = is_administrative == true and administrative_plugin_list or plugin_list
- local help = {}
- local count = 1
- table.sort(list_to_use)
- for _, v in pairs(list_to_use) do
- if v:match('^/.- %- .-$') then
- -- Do some replacement for plugins that have different primary commands to their plugin name.
- local to_match = v:gsub('/np', '/lastfm'):gsub('/r/', '/reddit '):gsub('/s/', '/sed '):gsub('(/cat)', '%1s')
- local plugin = to_match:match('^/([%w_]+) .-$')
- if not chat_id or not mattata.is_plugin_disabled(self, plugin, chat_id) then
- local command, description = v:match('^(.-) %- (.-)$')
- local parameters = ' '
- if not command then mattata.send_message(configuration.admins[1], v) end
- if command:match(' [%[<]') then
- command, parameters = command:match('^(.-)( .-)$')
- parameters = '<code>' .. mattata.escape_html(parameters) .. '</code> '
- end
- local output = command .. parameters .. '- <em>' .. mattata.escape_html(description) .. '</em>'
- table.insert(help, utf8.char(8226) .. ' ' .. output)
- count = count + 1
- end
- end
- end
- return help
-end
-
-function mattata.format_time(seconds)
- if not seconds or tonumber(seconds) == nil then
- return false
- end
- seconds = tonumber(seconds) -- Make sure we're handling a numerical value
- local minutes = math.floor(seconds / 60)
- if minutes == 0 then
- return seconds ~= 1 and seconds .. ' seconds' or seconds .. ' second'
- elseif minutes < 60 then
- return minutes ~= 1 and minutes .. ' minutes' or minutes .. ' minute'
- end
- local hours = math.floor(seconds / 3600)
- if hours == 0 then
- return minutes ~= 1 and minutes .. ' minutes' or minutes .. ' minute'
- elseif hours < 24 then
- return hours ~= 1 and hours .. ' hours' or hours .. ' hour'
- end
- local days = math.floor(seconds / 86400)
- if days == 0 then
- return hours ~= 1 and hours .. ' hours' or hours .. ' hour'
- elseif days < 7 then
- return days ~= 1 and days .. ' days' or days .. ' day'
- end
- local weeks = math.floor(seconds / 604800)
- if weeks == 0 then
- return days ~= 1 and days .. ' days' or days .. ' day'
- else
- return weeks ~= 1 and weeks .. ' weeks' or weeks .. ' week'
- end
-end
-
-function mattata.does_language_exist(language)
- return pcall( -- nice and simple, perform a pcall to require the language, and if it errors then it doesn't exist
- function()
- return require('languages.' .. language)
- end
- )
-end
-
-function mattata.save_to_file(content, file_path)
- if not content then
- return false
- end
- file_path = file_path or ('/tmp/temp_' .. os.time() .. '.txt')
- local file = io.open(file_path, 'w+')
- file:write(tostring(content))
- file:close()
- return true
-end
-
-function mattata.insert_keyboard_row(keyboard, first_text, first_callback, second_text, second_callback, third_text, third_callback)
--- todo: get rid of this function as it's dirty, who only allows 3 buttons in a row??
- table.insert(
- keyboard['inline_keyboard'],
- {
- {
- ['text'] = first_text,
- ['callback_data'] = first_callback
- },
- {
- ['text'] = second_text,
- ['callback_data'] = second_callback
- },
- {
- ['text'] = third_text,
- ['callback_data'] = third_callback
- }
- }
- )
- return keyboard
-end
-
-function mattata.is_user_blocklisted(message)
- if not message or not message.from or not message.chat then
- return false, false, false
- elseif mattata.is_global_admin(message.from.id) then
- return false, false, false
- end
- local gbanned = redis:get('global_ban:' .. message.from.id) -- Check if the user is globally
- -- blocklisted from using the bot.
- local group = redis:get('group_blocklist:' .. message.chat.id .. ':' .. message.from.id) -- Check
- -- if the user is blocklisted from using the bot in the current group.
- local gblocklisted = redis:get('global_blocklist:' .. message.from.id)
- return group, gblocklisted, gbanned
-end
-
-function mattata.is_spamwatch_blocklisted(message, force_check)
- if tonumber(message) ~= nil then -- Add support for passing just the user ID too!
- message = {
- ['from'] = {
- ['id'] = tonumber(message)
- }
- }
- elseif not message or not message.from then
- return false, nil, 'No valid message object was passed! It needs to have a message.from as well!', 404
- end
- local is_cached = redis:get('not_blocklisted:' .. message.from.id)
- if is_cached and not force_check then -- We don't want to perform an HTTPS call every time the bot sees a chat!
- return false, nil, 'That user is cached as not blocklisted!', 404
- end
- local response = {}
- local _ = https.request(
- {
- ['url'] = 'https://api.spamwat.ch/banlist/' .. message.from.id,
- ['method'] = 'GET',
- ['headers'] = {
- ['Authorization'] = 'Bearer ' .. configuration.keys.spamwatch
- },
- ['sink'] = ltn12.sink.table(response)
- }
- )
- response = table.concat(response)
- local jdat = json.decode(response)
- if not jdat then
- return false, nil, 'The server appears to be offline', 521
- elseif jdat.error then
- if jdat.code == 404 then -- The API returns a 404 code when the user isn't in the SpamWatch database
- redis:set('not_blocklisted:' .. message.from.id, true)
- redis:expire('not_blocklisted:' .. message.from.id, 604800) -- Let the key last a week!
- end
- return false, jdat, jdat.error, jdat.code
- elseif jdat.id then
- return true, jdat, 'Success', 200
- end
- return false, jdat, 'Error!', jdat.code or 404
-end
-
-function mattata:process_afk(message) -- Checks if the message references an AFK user and tells the
--- person mentioning them that they are marked AFK. If a user speaks and is currently marked as AFK,
--- then the bot will announce their return along with how long they were gone for.
- if message.from.username
- and redis:hget('afk:' .. message.from.id, 'since')
- and not mattata.is_plugin_disabled(self, 'afk', message)
- and not message.text:match('^[/!#]afk')
- and not message.text:lower():match('^i?\'?l?l? ?[bg][rt][bg].?$')
- then
- local since = os.time() - tonumber(redis:hget('afk:' .. message.from.id, 'since'))
- redis:hdel('afk:' .. message.from.id, 'since')
- redis:hdel('afk:' .. message.from.id, 'note')
- local keys = redis:keys('afk:' .. message.from.id .. ':replied:*')
- if #keys > 0 then
- for _, key in pairs(keys) do
- redis:del(key)
- end
- end
- local output = message.from.first_name .. ' has returned, after being /AFK for ' .. mattata.format_time(since) .. '.'
- mattata.send_message(message.chat.id, output)
- elseif (message.text:match('@[%w_]+') -- If a user gets mentioned, check to see if they're AFK.
- or message.reply) and not redis:get('afk:' .. message.from.id .. ':replied:' .. message.chat.id) then
- local username = message.reply and message.reply.from.id or message.text:match('@([%w_]+)')
- local success = mattata.get_user(username)
- if not success or not success.result or not success.result.id then
- return false
- end
- local exists = redis:hexists('afk:' .. success.result.id, 'since')
- if success and success.result and exists then -- If all the checks are positive, the mentioned user is AFK, so we'll tell the person mentioning them that this is the case!
- if message.reply then
- redis:set('afk:' .. message.from.id .. ':replied:' .. message.chat.id, true)
- end
- local output = success.result.first_name .. ' is currently AFK!'
- local note = redis:hget('afk:' .. message.from.id, 'note')
- if note then
- output = output .. '\nNote: ' .. note
- end
- mattata.send_reply(message, output)
- end
- end
-end
-
-function mattata.process_stickers(message)
- if message.chat.type == 'supergroup' and message.sticker then
- -- Process each sticker to see if they are one of the configured, command-performing stickers.
- for _, v in pairs(configuration.stickers.ban) do
- if message.sticker.file_unique_id == v then
- message.text = '/ban'
- end
- end
- for _, v in pairs(configuration.stickers.warn) do
- if message.sticker.file_unique_id == v then
- message.text = '/warn'
- end
- end
- for _, v in pairs(configuration.stickers.kick) do
- if message.sticker.file_unique_id == v then
- message.text = '/kick'
- end
- end
- end
- return message
-end
-
-function mattata:process_natural_language(message)
- local text = message.text:lower()
- local name = self.info.first_name:lower()
- if text:match(name .. '.- ban @?[%w_-]+ ?') then
- message.text = '/ban ' .. text:match(name .. '.- ban (@?[%w_-]+) ?')
- elseif text:match(name .. '.- warn @?[%w_-]+ ?') then
- message.text = '/warn ' .. text:match(name .. '.- warn (@?[%w_-]+) ?')
- elseif text:match(name .. '.- kick @?[%w_-]+ ?') then
- message.text = '/kick ' .. text:match(name .. '.- kick (@?[%w_-]+) ?')
- elseif text:match(name .. '.- unban @?[%w_-]+ ?') then
- message.text = '/unban ' .. text:match(name .. '.- unban (@?[%w_-]+) ?')
- elseif text:match(name .. '.- resume my music') then
- local myspotify = require('plugins.myspotify')
- local success = myspotify.reauthorise_account(message.from.id, configuration)
- local output = success and myspotify.play(message.from.id) or 'An error occured whilst trying to connect to your Spotify account, are you sure you\'ve connected me to it?'
- mattata.send_message(message.chat.id, output)
- end
- message.is_natural_language = true
- return message
-end
-
-function mattata.process_spam(message)
- if message.forward_from then return false end
- local msg_count = tonumber(
- redis:get('antispam:' .. message.chat.id .. ':' .. message.from.id) -- Check to see if the user
- -- has already sent 1 or more messages to the current chat, in the past 5 seconds.
- )
- or 1 -- If this is the first time the user has posted in the past 5 seconds, we'll make it 1 accordingly.
- redis:setex(
- 'antispam:' .. message.chat.id .. ':' .. message.from.id,
- configuration.administration.global_antispam.ttl, -- set the TTL
- msg_count + 1 -- Increase the current message count by 1.
- )
- if msg_count == configuration.administration.global_antispam.message_warning_amount -- If the user has sent x messages in the past y seconds, send them a warning.
- -- and not mattata.is_global_admin(message.from.id)
- and message.chat.type == 'private' then
- -- Don't run the antispam plugin if the user is configured as a global admin in `configuration.lua`.
- mattata.send_reply( -- Send a warning message to the user who is at risk of being blocklisted for sending
- -- too many messages.
- message,
- string.format(
- 'Hey %s, please don\'t send that many messages, or you\'ll be forbidden to use me for 24 hours!',
- message.from.username and '@' .. message.from.username or message.from.name
- )
- )
- elseif msg_count == configuration.administration.global_antispam.message_blocklist_amount -- If the user has sent x messages in the past y seconds, blocklist them globally from
- -- using the bot for 24 hours.
- -- and not mattata.is_global_admin(message.from.id) -- Don't blocklist the user if they are configured as a global
- -- admin in `configuration.lua`.
- then
- redis:set('global_blocklist:' .. message.from.id, true)
- if configuration.administration.global_antispam.blocklist_length ~= -1 and configuration.administration.global_antispam.blocklist_length ~= 'forever' then
- redis:expire('global_blocklist:' .. message.from.id, configuration.administration.global_antispam.blocklist_length)
- end
- return mattata.send_reply(
- message,
- string.format(
- 'Sorry, %s, but you have been blocklisted from using me for the next 24 hours because you have been spamming!',
- message.from.username and '@' .. message.from.username or message.from.name
- )
- )
- end
- return false
-end
-
-function mattata:process_language(message)
- if message.from.language_code then
- if not mattata.does_language_exist(message.from.language_code) then
- if not redis:sismember('mattata:missing_languages', message.from.language_code) then -- If we haven't stored the missing language file, add it into the database.
- redis:sadd('mattata:missing_languages', message.from.language_code)
- end
- if (message.text == '/start' or message.text == '/start@' .. self.info.username) and message.chat.type == 'private' then
- mattata.send_message(
- message.chat.id,
- 'It appears that I haven\'t got a translation in your language (' .. message.from.language_code .. ') yet. If you would like to voluntarily translate me into your language, please join <a href="https://t.me/mattataDev">my official development group</a>. Thanks!',
- 'html'
- )
- end
- elseif redis:sismember('mattata:missing_languages', message.from.language_code) then
- -- If the language file is found, yet it's recorded as missing in the database, it's probably
- -- new, so it is deleted from the database to prevent confusion when processing this list!
- redis:srem('mattata:missing_languages', message.from.language_code)
- end
- end
-end
-
-function mattata.process_deeplinks(message)
- if message.text:match('^/[%a_]+_%-%d+$') and message.chat.type == 'private' then
- message.text = message.text:gsub('^(/[%a_]+)_(.-)$', '%1 %2')
- end
- return message
-end
-
-function mattata.toggle_setting(chat_id, setting, value)
- value = (type(value) ~= 'string' and tostring(value) ~= 'nil') and value or true
- if not chat_id or not setting then
- return false
- elseif not redis:hexists('chat:' .. chat_id .. ':settings', tostring(setting)) then
- return redis:hset('chat:' .. chat_id .. ':settings', tostring(setting), value)
- end
- return redis:hdel('chat:' .. chat_id .. ':settings', tostring(setting))
-end
-
-function mattata.get_usernames(user_id)
- if not user_id then
- return false
- elseif tonumber(user_id) == nil then
- user_id = tostring(user_id):match('^@(.-)$') or tostring(user_id)
- user_id = redis:get('username:' .. user_id:lower())
- if not user_id then
- return false
- end
- end
- return redis:smembers('user:' .. user_id .. ':usernames')
-end
-
-function mattata.check_links(message, get_links, only_valid, allowlist, return_message, delete)
- message.is_invite_link = false
- message.is_valid_invite_link = false
- local links = {}
- if message.entities then
- for i = 1, #message.entities do
- if message.entities[i].type == 'text_link' then
- message.text = message.text .. ' ' .. message.entities[i].url
- end
- end
- end
- for n in message.text:gmatch('%@[%w_]+') do
- table.insert(links, n:match('^%@([%w_]+)$'))
- end
- for n in message.text:gmatch('[Tt]%.[Mm][Ee]/[Jj][Oo][Ii][Nn][Cc][Hh][Aa][Tt]/[%w_]+') do
- table.insert(links, n:match('/([Jj][Oo][Ii][Nn][Cc][Hh][Aa][Tt]/[%w_]+)$'))
- end
- for n in message.text:gmatch('[Tt]%.[Mm][Ee]/[%w_]+') do
- if not n:match('/[Jj][Oo][Ii][Nn][Cc][Hh][Aa][Tt]$') then
- table.insert(links, n:match('/([%w_]+)$'))
- end
- end
- for n in message.text:gmatch('[Tt][Ee][Ll][Ee][Gg][Rr][Aa][Mm]%.[Mm][Ee]/[Jj][Oo][Ii][Nn][Cc][Hh][Aa][Tt]/[%w_]+') do
- table.insert(links, n:match('/([Jj][Oo][Ii][Nn][Cc][Hh][Aa][Tt]/[%w_]+)$'))
- end
- for n in message.text:gmatch('[Tt][Ee][Ll][Ee][Gg][Rr][Aa][Mm]%.[Mm][Ee]/[%w_]+') do
- if not n:match('/[Jj][Oo][Ii][Nn][Cc][Hh][Aa][Tt]$') then
- table.insert(links, n:match('/([%w_]+)$'))
- end
- end
- for n in message.text:gmatch('[Tt][Ee][Ll][Ee][Gg][Rr][Aa][Mm]%.[Dd][Oo][Gg]/[Jj][Oo][Ii][Nn][Cc][Hh][Aa][Tt]/[%w_]+') do
- table.insert(links, n:match('/([Jj][Oo][Ii][Nn][Cc][Hh][Aa][Tt]/[%w_]+)$'))
- end
- for n in message.text:gmatch('[Tt][Ee][Ll][Ee][Gg][Rr][Aa][Mm]%.[Dd][Oo][Gg]/[%w_]+') do
- if not n:match('/[Jj][Oo][Ii][Nn][Cc][Hh][Aa][Tt]$') then
- table.insert(links, n:match('/([%w_]+)$'))
- end
- end
- for n in message.text:gmatch('[Tt][Gg]://[Jj][Oo][Ii][Nn]%?[Ii][Nn][Vv][Ii][Tt][Ee]=[%w_]+') do
- table.insert(links, '[Jj][Oo][Ii][Nn][Cc][Hh][Aa][Tt]/' .. n:match('=([%w_]+)$'))
- end
- for n in message.text:gmatch('[Tt][Gg]://[Rr][Ee][Ss][Oo][Ll][Vv][Ee]%?[Dd][Oo][Mm][Aa][Ii][Nn]=[%w_]+') do
- table.insert(links, n:match('=([%w_]+)$'))
- end
- if allowlist then
- local count = 0
- for _, v in pairs(links) do
- v = v:match('^[Jj][Oo][Ii][Nn][Cc][Hh][Aa][Tt]') and v or v:lower()
- if delete then
- redis:del('allowlisted_links:' .. message.chat.id .. ':' .. v)
- else
- redis:set('allowlisted_links:' .. message.chat.id .. ':' .. v, true)
- end
- count = count + 1
- end
- return string.format(
- '%s link%s ha%s been %s in this chat!',
- count,
- count == 1 and '' or 's',
- count == 1 and 's' or 've',
- delete and 'blocklisted' or 'allowlisted'
- )
- end
- local checked = {}
- local valid = {}
- for _, v in pairs(links) do
- if not mattata.is_allowlisted_link(v:lower(), message.chat.id) then
- if v:match('^[Jj][Oo][Ii][Nn][Cc][Hh][Aa][Tt]/') then
- message.is_invite_link = true
- if only_valid then
- local str, res = https.request('https://t.me/' .. v)
- if res == 200 and str and str:match('tgme_page_title') then
- table.insert(valid, v)
- message.is_valid_invite_link = true
- end
- end
- if not get_links then
- return return_message and message or true
- end
- elseif not mattata.table_contains(checked, v:lower()) then
- if not mattata.get_user(v:lower()) then
- local success = mattata.get_chat('@' .. v:lower(), true)
- if success and success.result and success.result.type ~= 'private' and success.result.id ~= message.chat.id then
- message.is_invite_link = true
- if not get_links then
- return return_message and message or true
- end
- table.insert(valid, v:lower())
- end
- table.insert(checked, v:lower())
- end
- end
- end
- end
- if get_links then
- if only_valid then
- return valid
- end
- return checked
- end
- return return_message and message or false
-end
-
-function mattata:process_message(message)
- if not message.chat then
- return true
- end
- if message.chat and message.chat.type ~= 'private' and not mattata.service_message(message) and not mattata.is_plugin_disabled(self, 'statistics', message) and not mattata.is_privacy_enabled(message.from.id) and not self.is_blocklisted then
- redis:incr('messages:' .. message.from.id .. ':' .. message.chat.id)
- end
- if message.new_chat_members and mattata.get_setting(message.chat.id, 'use administration') and mattata.get_setting(message.chat.id, 'antibot') and not mattata.is_group_admin(message.chat.id, message.from.id) and not mattata.is_global_admin(message.from.id) then
- local kicked = {}
- local usernames = {}
- for _, v in pairs(message.new_chat_members) do
- if v.username and v.username:lower():match('bot$') and v.id ~= message.from.id and v.id ~= self.info.id and tostring(v.is_bot) == 'true' then
- local success = mattata.kick_chat_member(message.chat.id, v.id)
- if success then
- table.insert(kicked, mattata.escape_html(v.first_name) .. ' [' .. v.id .. ']')
- table.insert(usernames, '@' .. v.username)
- end
- end
- end
- if #kicked > 0 and #usernames > 0 and #kicked == #usernames then
- local log_chat = mattata.get_log_chat(message.chat.id)
- mattata.send_message(log_chat, string.format('<pre>%s [%s] has kicked %s from %s [%s] because anti-bot is enabled.</pre>', mattata.escape_html(self.info.first_name), self.info.id, table.concat(kicked, ', '), mattata.escape_html(message.chat.title), message.chat.id), 'html')
- return mattata.send_message(message, string.format('Kicked %s because anti-bot is enabled.', table.concat(usernames, ', ')))
- end
- end
-end
-
-function mattata.process_nicknames(message)
- local nickname = redis:hget('user:' .. message.from.id .. ':info', 'nickname')
- if nickname then
- message.from.original_name = message.from.name
- message.from.has_nickname = true
- message.from.name = nickname
- message.from.first_name = nickname
- message.from.last_name = nil
- else
- message.from.has_nickname = false
- end
- if message.reply then
- nickname = redis:hget('user:' .. message.reply.from.id .. ':info', 'nickname')
- if nickname then
- message.reply.from.original_name = message.reply.from.name
- message.reply.from.has_nickname = true
- message.reply.from.name = nickname
- message.reply.from.first_name = nickname
- message.reply.from.last_name = nil
- else
- message.reply.from.has_nickname = false
- end
- end
- return message
-end
-
-return mattata
\ No newline at end of file
diff --git a/migrate.lua b/migrate.lua
deleted file mode 100644
index 1c2f55c..0000000
--- a/migrate.lua
+++ /dev/null
@@ -1,20 +0,0 @@
-local redis = dofile('libs/redis.lua')
-local disabled_plugin_keys = redis:keys('chat:*:disabled_plugins')
-if next(disabled_plugin_keys) then
- for _, v in pairs(disabled_plugin_keys) do
- local plugins = redis:hgetall(v)
- if #plugins > 2 then
- for plugin, value in pairs(plugins) do
- if plugin then
- if tostring(value) == 'true' then
- local chat_id = v:match(':(%-?%d+):')
- redis:sadd('disabled_plugins:' .. chat_id, plugin:lower())
- print('Migrated disabled plugin "' .. plugin.lower() .. '" for ' .. chat_id)
- end
- end
- end
- redis:del(v)
- end
- end
-end
-return 'Migration complete!'
\ No newline at end of file
diff --git a/patch/malloc.patch b/patch/malloc.patch
deleted file mode 100644
index 9629953..0000000
--- a/patch/malloc.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-diff --git a/src/captcha.c b/src/captcha.c
-index e0a8382..2c6df2e 100644
---- a/src/captcha.c
-+++ b/src/captcha.c
-@@ -51,10 +51,8 @@ static int generate(lua_State* L) {
- if (elements == 0) {
- luaL_argerror (L, 0, "Fonts directory has not fonts");
- }
-- path = (char*)lua_newuserdata(L, strlen(usr_path)+usr_length+strlen(usr_fmt)+1); // works like malloc, adding dat to gc
-- lua_pop(L, 1); // continues
-- captcha = (char*)lua_newuserdata(L, strlen(usr_path)+usr_length+strlen(usr_fmt)+1); // works like malloc, adding dat to gc
-- lua_pop(L, 1); // continues
-+ path = malloc(strlen(usr_path)+usr_length+strlen(usr_fmt)+1); // works like malloc, adding dat to gc
-+ captcha = calloc(usr_length+1, 0); // works like malloc, adding dat to gc
- sprintf(path, "%s/", usr_path);
- FILE *out;
- int x_image = usr_fntsize*usr_length; // calcule width image, using length * font size
-@@ -99,6 +97,8 @@ static int generate(lua_State* L) {
- gdImageDestroy(im);
- lua_pushstring(L, path);
- lua_pushstring(L, captcha);
-+ free(path);
-+ free(captcha);
- return 2;
- }
- static int setlength(lua_State* L) {
diff --git a/plugins/about.lua b/plugins/about.lua
deleted file mode 100644
index 0fef1ac..0000000
--- a/plugins/about.lua
+++ /dev/null
@@ -1,20 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local about = {}
-local mattata = require('mattata')
-
-function about:init()
- about.commands = mattata.commands(self.info.username):command('about').table
- about.help = '/about - View information about the bot.'
-end
-
-function about:on_message(message)
- local developer = mattata.get_formatted_user(221714512, 'Matt', 'html')
- local output = 'Created by %s. Powered by <code>mattata v%s</code> and %s. Latest stable source code available <a href="https://github.com/wrxck/mattata">on GitHub</a>.'
- return mattata.send_message(message.chat.id, string.format(output, developer, self.version, utf8.char(10084)), 'html')
-end
-
-return about
\ No newline at end of file
diff --git a/plugins/addcommand.lua b/plugins/addcommand.lua
deleted file mode 100644
index 8b49756..0000000
--- a/plugins/addcommand.lua
+++ /dev/null
@@ -1,38 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local addcommand = {}
-local mattata = require('mattata')
-
-function addcommand:init()
- addcommand.commands = mattata.commands(self.info.username):command('addcommand').table
-end
-
-function addcommand.on_message(_, message, _, language)
- if not mattata.is_global_admin(message.from.id) then
- return false
- end
- local input = mattata.input(message.text)
- if not input or not input:match('^[/!#]?[%w_]+ %- .-$') then
- return mattata.send_reply(message, language['addcommand']['1'], 'html')
- end
- local commands = mattata.get_my_commands()
- if not commands then
- return mattata.send_reply(message, language['addcommand']['2'])
- end
- commands = type(commands.result) == 'table' and commands.result or {}
- local command, description = input:match('^/?([%w_]+) %- (.-)$')
- if description:len() > 256 then
- return mattata.send_reply(message, language['addcommand']['3'])
- end
- commands = table.insert(commands, { ['command'] = command, ['description'] = description })
- local success = mattata.set_my_commands(commands)
- if not success then
- return mattata.send_reply(message, language['addcommand']['4'])
- end
- return mattata.send_reply(message, language['addcommand']['5'])
-end
-
-return addcommand
\ No newline at end of file
diff --git a/plugins/addslap.lua b/plugins/addslap.lua
deleted file mode 100644
index e457d39..0000000
--- a/plugins/addslap.lua
+++ /dev/null
@@ -1,37 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local addslap = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function addslap:init()
- addslap.commands = mattata.commands(self.info.username):command('addslap').table
- addslap.help = '/addslap <slap> - Adds a new slap to /slap. Slaps must only contain letters, numbers, hyphens, underscores, commands, forward slashes or full stops. Use the placeholders {ME} for the person slapping, and {THEM} for the person being slapped. An example would be: {ME} threw {THEM} into a house fire. Slaps can be no longer than 256 characters long, but there is currently no limit to how many you can add. This feature is in beta, and there is currently no way to delete a slap you add - this will be added later. If you want to delete yours, send a PM to @wrxck.'
-end
-
-function addslap.on_message(_, message, _, language)
- if message.chat.type == 'private' then
- return mattata.send_reply(message, language['addslap']['1'])
- elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
- return mattata.send_reply(message, language.errors.admin)
- end
- local input = mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, addslap.help)
- elseif not input:match('{ME}') or not input:match('{THEM}') then
- return mattata.send_reply(message, language['addslap']['5'])
- end
- local valid = input:gsub('{ME}', ''):gsub('{THEM}', '')
- if valid:match('[{}]') then
- return mattata.send_reply(message, language['addslap']['2'])
- elseif input:len() > 256 then
- return mattata.send_reply(message, language['addslap']['3'])
- end
- redis:sadd('slaps:' .. message.chat.id, input)
- return mattata.send_reply(message, language['addslap']['4'])
-end
-
-return addslap
\ No newline at end of file
diff --git a/plugins/addsticker.lua b/plugins/addsticker.lua
deleted file mode 100644
index daf6e13..0000000
--- a/plugins/addsticker.lua
+++ /dev/null
@@ -1,194 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local addsticker = {}
-local mattata = require('mattata')
-local http = require('socket.http')
-local ltn12 = require('ltn12')
-local mime = require('mime')
-local json = require('dkjson')
-local redis = require('libs.redis')
-
-function addsticker:init()
- addsticker.commands = mattata.commands(self.info.username):command('addsticker'):command('getsticker').table
- addsticker.help = '/addsticker [pack name] - Converts the replied-to photo into a sticker and adds it to your pack. Specify a name for the pack via command input on first use, this cannot be changed after, until you\'ve hit 120 stickers and it makes a new set, or you\'ve deleted your pack in @stickers. Use /getsticker to get the uncompressed file to send to @stickers.'
-end
-
-function addsticker.delete_file(file)
- os.execute('rm ' .. file .. ' && rm output.png')
- return true
-end
-
-function addsticker:on_message(message, configuration, language)
- local is_sticker, is_text
- local input = mattata.input(message.text)
- if not message.reply then
- return mattata.send_reply(message, 'You must use this command in reply to a photo!')
- elseif not message.reply.is_media and message.reply.text then
- local sizes
- local reply = {}
- local success = mattata.get_user_profile_photos(message.reply.from.id)
- if success and success.result.total_count > 0 then
- sizes = {
- ['small_file_id'] = success.result.photos[1][1].file_id,
- ['small_file_unique_id'] = success.result.photos[1][1].file_unique_id,
- ['big_file_id'] = success.result.photos[1][#success.result.photos[1]].file_id,
- ['big_file_unique_id'] = success.result.photos[1][#success.result.photos[1]].file_unique_id
- }
- end
- if message.reply.reply then -- Check the context object for a reply to a reply.
- local reply_original_name = message.reply.reply.from.has_nickname and message.reply.reply.from.original_name or message.reply.reply.from.name
- reply = {
- ['chatId'] = message.chat.id,
- ['from'] = {
- ['id'] = message.reply.reply.from.id,
- ['name'] = reply_original_name
- },
- ['text'] = message.reply.reply.text
- }
- end
- local original_name = message.reply.from.has_nickname and message.reply.from.original_name or message.reply.from.name
- if (message.reply.text:match('^[\216-\219][\128-\191]') or message.reply.text:match('^' .. utf8.char(0x202e)) or message.reply.text:match('^' .. utf8.char(0x200f))) then
- message.reply.text = mattata.split_string(message.reply.text, true)
- message.reply.text = table.concat(message.reply.text, ' ')
- end
- local payload = {
- ['type'] = 'quote',
- ['backgroundColor'] = '#243447',
- ['width'] = 512,
- ['height'] = 512,
- ['scale'] = 2,
- ['messages'] = {
- {
- ['message'] = {
- ['chatId'] = message.chat.id,
- ['avatar'] = true,
- ['from'] = {
- ['id'] = message.reply.from.id,
- ['name'] = original_name
- },
- ['text'] = message.reply.text
- },
- ['replyMessage'] = reply,
- ['entities'] = {}
- }
- }
- }
- if type(sizes) == 'table' then
- payload.messages[1].message.from.photo = sizes
- end
- if message.reply.from.username then
- payload.messages[1].message.from.username = message.reply.from.username
- end
- if message.reply.entities then
- payload.messages[1].entities = message.reply.entities
- end
- payload = json.encode(payload) -- Serialise the payload.
- local response = {}
- local old_timeout = http.TIMEOUT
- http.TIMEOUT = 3
- local _, res = http.request({
- ['url'] = 'http://localhost:3000/generate',
- ['method'] = 'POST',
- ['headers'] = {
- ['Content-Type'] = 'application/json',
- ['Content-Length'] = payload:len()
- },
- ['source'] = ltn12.source.string(payload),
- ['sink'] = ltn12.sink.table(response)
- })
- http.TIMEOUT = old_timeout
- if res ~= 200 then
- return false
- end
- response = table.concat(response)
- local jdat = json.decode(response)
- local output = configuration.bot_directory .. '/output.webp'
- ltn12.pump.all(
- ltn12.source.string(jdat.result.image),
- ltn12.sink.chain(
- mime.decode('base64'),
- ltn12.sink.file(io.open(output, 'w'))
- )
- )
- is_text = true
- elseif message.reply.sticker then
- if message.reply.sticker.is_animated then
- return mattata.send_reply(message, 'I\'m afraid animated stickers aren\'t supported at the moment.')
- end
- is_sticker = true
- elseif not message.reply.photo and not message.reply.document then
- local success = mattata.get_user_profile_photos(message.reply.from.id)
- if not success or success.result.total_count == 0 then
- return mattata.send_reply(message, 'This user doesn\'t allow me to see their profile picture. You must use this command in reply to a photo!')
- end
- message.reply.file_id = success.result.photos[1][#success.result.photos[1]].file_id
- elseif message.reply.document then
- if (message.reply.document.mime_type ~= 'image/jpeg' and message.reply.document.mime_type ~= 'image/png') or not message.reply.document.file_name:match('%.[JjPp][PpNn][Ee]?[Gg]$') then
- return mattata.send_reply(message, 'The file must be JPEG or a PNG image.')
- elseif message.reply.document.file_size > 1048576 then
- return mattata.send_reply(message, 'Please send a photo that is 1MB or smaller in file size!')
- end
- end
- local file, file_name
- if not is_text and message.reply.is_media then
- file = mattata.get_file(message.reply.file_id)
- if not file then
- return mattata.send_reply(message, language.errors.generic)
- end
- file_name = file.result.file_path
- local file_path = string.format('https://api.telegram.org/file/bot%s/%s', configuration.bot_token, file_name)
- file = mattata.download_file(file_path, file_name:match('/(.-)$'), configuration.bot_directory)
- if not file then
- return false
- end
- file_name = file_name:match('/(.-)$')
- else
- file_name = 'output.webp'
- file = configuration.bot_directory .. '/output.webp'
- end
- local command = is_sticker and string.format('dwebp %s -o output.png', file_name) or string.format('convert ' .. file_name .. ' -resize 512x512 output.png', file)
- os.execute(command)
- local output_file = configuration.bot_directory .. '/output.png'
- if message.text:match('^[/!#]getsticker') then
- mattata.send_document(message.chat.id, output_file)
- return addsticker.delete_file(file)
- end
- local set_name = string.format('U%s_by_%s', message.from.id, self.info.username:lower())
- local set_title = message.from.original_name or message.from.first_name
- local exists = mattata.get_sticker_set(set_name)
- if exists then
- if #exists.result.stickers == 120 then -- Maximum amount of stickers allowed per-pack.
- local amount = exists.result.name:match('^U%d+_(%d*)')
- local new = (amount and tonumber(amount) or 1) + 1
- set_name = string.format('U%s_%s_by_%s', message.from.id, new, self.info.username:lower())
- amount = redis:hget('user:' .. message.from.id .. ':info', 'sticker_packs') or 1
- amount = math.floor(tonumber(amount)) + 1
- redis:hset('user:' .. message.from.id .. ':info', 'sticker_packs', amount)
- else
- local success = mattata.add_sticker_to_set(message.from.id, set_name, output_file, utf8.char(128045))
- addsticker.delete_file(file)
- if not success then
- return mattata.send_reply(message, language.errors.generic)
- end
- return mattata.send_reply(message, 'I\'ve added that to [your pack](https://t.me/addstickers/' .. set_name .. ')!', true, true)
- end
- end
- if input then
- if input:len() > 64 then
- addsticker.delete_file(file)
- return mattata.send_reply(message, 'The sticker pack title cannot be longer than 64 characters in length!')
- end
- set_title = input
- end
- local success = mattata.create_new_sticker_set(message.from.id, set_name, set_title, output_file, utf8.char(128045))
- addsticker.delete_file(file)
- if not success then
- return mattata.send_reply(message, language.errors.generic)
- end
- return mattata.send_reply(message, 'I\'ve created you a pack called _' .. mattata.escape_markdown(set_title) .. '_ and added that sticker to [your new pack](https://t.me/addstickers/' .. set_name .. ')!', true, true)
-end
-
-return addsticker
\ No newline at end of file
diff --git a/plugins/administration.lua b/plugins/administration.lua
deleted file mode 100644
index 34949bc..0000000
--- a/plugins/administration.lua
+++ /dev/null
@@ -1,425 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local administration = {}
-local mattata = require('mattata')
-local json = require('dkjson')
-local redis = require('libs.redis')
-local configuration = require('configuration')
-
-function administration:init()
- administration.commands = mattata.commands(self.info.username):command('administration'):command('settings').table
- administration.help = '/administration [chat] - Returns the administrative settings panel for the group it is being executed from. Optionally, group admins may edit the settings using a @mention in PM to the bot, i.e. /administration @devTalk. Alias: /settings.'
-end
-
-function administration.get_initial_keyboard(chat_id, page, language)
- if not mattata.get_setting(chat_id, 'use administration') then
- return mattata.inline_keyboard():row(mattata.row():callback_data_button(language['administration']['1'], 'administration:' .. chat_id .. ':toggle'))
- end
- if not page or tonumber(page) <= 1 then
- return mattata.inline_keyboard():row(
- mattata.row():callback_data_button(
- language['administration']['2'],
- 'administration:' .. chat_id .. ':toggle'
- )
- ):row(
- mattata.row():callback_data_button(language['administration']['3'], 'antispam:' .. chat_id)
- ):row(
- mattata.row():callback_data_button(language['administration']['4'], 'administration:' .. chat_id .. ':warnings')
- ):row(
- mattata.row()
- :callback_data_button(language['administration']['6'], 'administration:nil')
- :callback_data_button(
- mattata.get_setting(chat_id, 'welcome message') and utf8.char(9989) or utf8.char(10060),
- 'administration:' .. chat_id .. ':welcome_message:1'
- )
- ):row(
- mattata.row()
- :callback_data_button(language['administration']['7'], 'administration:nil')
- :callback_data_button(
- mattata.get_setting(chat_id, 'send rules on join') and utf8.char(9989) or utf8.char(10060),
- 'administration:' .. chat_id .. ':rules_on_join:1'
- )
- ):row(
- mattata.row()
- :callback_data_button(language['administration']['8'], 'administration:nil')
- :callback_data_button(
- mattata.get_setting(chat_id, 'send rules in group') and utf8.char(9989) or utf8.char(10060),
- 'administration:' .. chat_id .. ':rules_in_group:1'
- )
- ):row(
- mattata.row()
- :callback_data_button(mattata.symbols.back .. ' ' .. language['administration']['9'], 'help:settings')
- :callback_data_button(language['administration']['10'] .. ' ' .. mattata.symbols.next, 'administration:' .. chat_id .. ':page:2')
- )
- elseif tonumber(page) == 2 then
- return mattata.inline_keyboard():row(
- mattata.row()
- :callback_data_button(language['administration']['11'], 'administration:nil')
- :callback_data_button(
- mattata.get_setting(chat_id, 'word filter') and 'On' or 'Off',
- 'administration:' .. chat_id .. ':word_filter:2'
- )
- ):row(
- mattata.row()
- :callback_data_button(language['administration']['12'], 'administration:nil')
- :callback_data_button(
- mattata.get_setting(chat_id, 'antibot') and utf8.char(9989) or utf8.char(10060),
- 'administration:' .. chat_id .. ':antibot:2'
- )
- :callback_data_button(language['administration']['13'], 'administration:nil')
- :callback_data_button(
- mattata.get_setting(chat_id, 'antilink') and utf8.char(9989) or utf8.char(10060),
- 'administration:' .. chat_id .. ':antilink:2'
- )
- ):row(
- mattata.row()
- :callback_data_button(language['administration']['14'], 'administration:nil')
- :callback_data_button(
- mattata.get_setting(chat_id, 'log administrative actions') and utf8.char(9989) or utf8.char(10060),
- 'administration:' .. chat_id .. ':log:2'
- )
- :callback_data_button(language['administration']['15'], 'administration:nil')
- :callback_data_button(
- mattata.get_setting(chat_id, 'antirtl') and utf8.char(9989) or utf8.char(10060),
- 'administration:' .. chat_id .. ':rtl:2'
- )
- ):row(
- mattata.row()
- :callback_data_button(language['administration']['16'], 'administration:nil')
- :callback_data_button(
- mattata.get_setting(chat_id, 'ban not kick') and language['administration']['17'] or language['administration']['18'],
- 'administration:' .. chat_id .. ':action:2'
- )
- ):row(
- mattata.row()
- :callback_data_button(language['administration']['19'], 'administration:nil')
- :callback_data_button(
- mattata.get_setting(chat_id, 'delete commands') and utf8.char(9989) or utf8.char(10060),
- 'administration:' .. chat_id .. ':delete_commands:2'
- )
- ):row(
- mattata.row()
- :callback_data_button(language['administration']['20'], 'administration:nil')
- :callback_data_button(
- mattata.get_setting(chat_id, 'force group language') and utf8.char(9989) or utf8.char(10060),
- 'administration:' .. chat_id .. ':force_group_language:2'
- )
- ):row(
- mattata.row()
- :callback_data_button(mattata.symbols.back .. ' ' .. language['administration']['9'], 'administration:' .. chat_id .. ':page:1')
- :callback_data_button(language['administration']['10'] .. ' ' .. mattata.symbols.next, 'administration:' .. chat_id .. ':page:3')
- )
- elseif tonumber(page) == 3 then
- return mattata.inline_keyboard():row(
- mattata.row()
- :callback_data_button(language['administration']['21'], 'administration:nil')
- :callback_data_button(
- mattata.get_setting(chat_id, 'settings in group') and utf8.char(9989) or utf8.char(10060),
- 'administration:' .. chat_id .. ':settings_in_group:3'
- )
- ):row(
- mattata.row()
- :callback_data_button(language['administration']['22'], 'administration:nil')
- :callback_data_button(
- mattata.get_setting(chat_id, 'delete reply on action') and utf8.char(9989) or utf8.char(10060),
- 'administration:' .. chat_id .. ':delete_reply_on_action:3'
- )
- ):row(
- mattata.row()
- :callback_data_button(language['administration']['23'], 'administration:nil')
- :callback_data_button(
- mattata.get_setting(chat_id, 'require captcha') and utf8.char(9989) or utf8.char(10060),
- 'administration:' .. chat_id .. ':require_captcha:3'
- )
- ):row(
- mattata.row()
- :callback_data_button(language['administration']['25'], 'administration:nil')
- :callback_data_button(
- mattata.get_setting(chat_id, 'ban spamwatch users') and utf8.char(9989) or utf8.char(10060),
- 'administration:' .. chat_id .. ':ban_spamwatch_users:4'
- )
- ):row(
- mattata.row()
- :callback_data_button(language['administration']['46'], 'administration:nil')
- :callback_data_button(
- mattata.get_setting(chat_id, 'remove channel pins') and utf8.char(9989) or utf8.char(10060),
- 'administration:' .. chat_id .. ':remove_channel_pins:4'
- )
- ):row(
- mattata.row()
- :callback_data_button(language['administration']['50'], 'administration:nil')
- :callback_data_button(
- mattata.get_setting(chat_id, 'kick media on join') and utf8.char(9989) or utf8.char(10060),
- 'administration:' .. chat_id .. ':kick_media_on_join:3'
- )
- ):row(
- mattata.row()
- :callback_data_button(mattata.symbols.back .. ' ' .. language['administration']['9'], 'administration:' .. chat_id .. ':page:2')
- :callback_data_button(language['administration']['10'] .. ' ' .. mattata.symbols.next, 'administration:' .. chat_id .. ':page:4')
- )
- elseif tonumber(page) >= 4 then
- return mattata.inline_keyboard():row(
- mattata.row()
- :callback_data_button(language['administration']['47'], 'administration:nil')
- :callback_data_button(
- mattata.get_setting(chat_id, 'remove other pins') and utf8.char(9989) or utf8.char(10060),
- 'administration:' .. chat_id .. ':remove_other_pins:4'
- )
- ):row(
- mattata.row()
- :callback_data_button(language['administration']['48'], 'administration:nil')
- :callback_data_button(
- mattata.get_setting(chat_id, 'remove pasted code') and utf8.char(9989) or utf8.char(10060),
- 'administration:' .. chat_id .. ':remove_pasted_code:4'
- )
- ):row(
- mattata.row()
- :callback_data_button(language['administration']['49'], 'administration:nil')
- :callback_data_button(
- mattata.get_setting(chat_id, 'prevent inline bots') and utf8.char(9989) or utf8.char(10060),
- 'administration:' .. chat_id .. ':prevent_inline_bots:4'
- )
- ):row(
- mattata.row()
- :callback_data_button(language['administration']['51'], 'administration:nil')
- :callback_data_button(
- mattata.get_setting(chat_id, 'enable plugins for admins') and utf8.char(9989) or utf8.char(10060),
- 'administration:' .. chat_id .. ':enable_plugins_for_admins:5'
- )
- ):row(
- mattata.row()
- :callback_data_button(language['administration']['52'], 'administration:nil')
- :callback_data_button(
- mattata.get_setting(chat_id, 'kick urls on join') and utf8.char(9989) or utf8.char(10060),
- 'administration:' .. chat_id .. ':kick_urls_on_join:5'
- )
- ):row(
- mattata.row():callback_data_button(mattata.symbols.back .. ' ' .. language['administration']['9'], 'administration:' .. chat_id .. ':page:3')
- )
- end
- return false
-end
-
-function administration.get_warnings(chat_id, language)
- local keyboard = {
- ['inline_keyboard'] = {}
- }
- local current = mattata.get_setting(chat_id, 'max warnings') or configuration.administration.warnings.default
- local ban_kick_status = redis:get('administration:' .. chat_id .. ':ban_kick') and true or false
- local action = ban_kick_status and 'kick' or 'ban'
- local less = tonumber(current) - 1
- local more = tonumber(current) + 1
- table.insert(keyboard.inline_keyboard, {{
- ['text'] = string.format(language['administration']['26'], action),
- ['callback_data'] = 'administration:nil'
- }})
- mattata.insert_keyboard_row(
- keyboard, '-',
- 'administration:' .. chat_id .. ':max_warnings:' .. less,
- tostring(current),
- 'administration:nil', '+',
- 'administration:' .. chat_id .. ':max_warnings:' .. more
- )
- table.insert(keyboard.inline_keyboard, {{
- ['text'] = language['administration']['9'],
- ['callback_data'] = 'administration:' .. chat_id .. ':page:1'
- }})
- return keyboard
-end
-
-function administration.del_chat(message, language)
- local title = message.text:match('^/chats del (.-)$')
- if not title then
- return false
- end
- for _, v in pairs(redis:smembers('mattata:configuration:chats')) do
- if not v or not json.decode(v).link or not json.decode(v).title then
- return
- elseif json.decode(v).title == title then
- redis:srem('mattata:configuration:chats', v)
- return mattata.send_reply(message, string.format(language['administration']['29'], title))
- end
- end
- return mattata.send_reply(message, string.format(language['administration']['30'], title))
-end
-
-function administration.on_callback_query(_, callback_query, message, _, language)
- if callback_query.data == 'nil' then -- An invalid callback_query payload was received, abort!
- return mattata.answer_callback_query(callback_query.id)
- elseif not mattata.is_group_admin(callback_query.data:match('^(%-%d+)'), callback_query.from.id) then
- return mattata.answer_callback_query(callback_query.id, language['administration']['31'])
- end
- local keyboard
- if callback_query.data:match('^%-%d+:warnings$') then
- local chat_id = callback_query.data:match('^(%-%d+):warnings$')
- keyboard = administration.get_warnings(chat_id, language)
- elseif callback_query.data:match('^%-%d+:max_warnings:.-$') then
- local chat_id, max_warnings = callback_query.data:match('^(%-%d+):max_warnings:(.-)$')
- if tonumber(max_warnings) > configuration.administration.warnings.maximum then
- return mattata.answer_callback_query(callback_query.id, string.format(language['administration']['36'], configuration.administration.warnings.maximum))
- elseif tonumber(max_warnings) < configuration.administration.warnings.minimum then
- return mattata.answer_callback_query(callback_query.id, string.format(language['administration']['37'], configuration.administration.warnings.minimum))
- elseif tonumber(max_warnings) == nil then
- return false
- end
- redis:hset('chat:' .. chat_id .. ':settings', 'max warnings', tonumber(max_warnings))
- keyboard = administration.get_warnings(chat_id, language)
- elseif callback_query.data:match('^%-%d+:toggle$') then
- local chat_id = callback_query.data:match('^(%-%d+):toggle$')
- mattata.toggle_setting(chat_id, 'use administration')
- keyboard = administration.get_initial_keyboard(chat_id, 1, language)
- elseif callback_query.data:match('^%-%d+:rtl:%d*$') then
- local chat_id, page = callback_query.data:match('^(%-%d+):rtl:(%d*)$')
- mattata.toggle_setting(chat_id, 'antirtl')
- keyboard = administration.get_initial_keyboard(chat_id, page, language)
- elseif callback_query.data:match('^%-%d+:rules_on_join:%d*$') then
- local chat_id, page = callback_query.data:match('^(%-%d+):rules_on_join:(%d*)$')
- mattata.toggle_setting(chat_id, 'send rules on join')
- keyboard = administration.get_initial_keyboard(chat_id, page, language)
- elseif callback_query.data:match('^%-%d+:rules_in_group:%d*$') then
- local chat_id, page = callback_query.data:match('^(%-%d+):rules_in_group:(%d*)$')
- mattata.toggle_setting(chat_id, 'send rules in group')
- keyboard = administration.get_initial_keyboard(chat_id, page, language)
- elseif callback_query.data:match('^%-%d+:word_filter:%d*$') then
- local chat_id, page = callback_query.data:match('^(%-%d+):word_filter:(%d*)$')
- mattata.toggle_setting(chat_id, 'word filter')
- keyboard = administration.get_initial_keyboard(chat_id, page, language)
- mattata.answer_callback_query(callback_query.id, language['administration']['38'], true)
- elseif callback_query.data:match('^%-%d+:inactive:%d*$') then
- local chat_id, page = callback_query.data:match('^(%-%d+):inactive:(%d*)$')
- mattata.toggle_setting(chat_id, 'remove inactive users')
- keyboard = administration.get_initial_keyboard(chat_id, page, language)
- elseif callback_query.data:match('^%-%d+:action:%d*$') then
- local chat_id, page = callback_query.data:match('^(%-%d+):action:(%d*)$')
- mattata.toggle_setting(chat_id, 'ban not kick')
- keyboard = administration.get_initial_keyboard(chat_id, page, language)
- elseif callback_query.data:match('^%-%d+:antibot:%d*$') then
- local chat_id, page = callback_query.data:match('^(%-%d+):antibot:(%d*)$')
- mattata.toggle_setting(chat_id, 'antibot')
- keyboard = administration.get_initial_keyboard(chat_id, page, language)
- elseif callback_query.data:match('^%-%d+:antilink:%d*$') then
- local chat_id, page = callback_query.data:match('^(%-%d+):antilink:(%d*)$')
- mattata.toggle_setting(chat_id, 'antilink')
- keyboard = administration.get_initial_keyboard(chat_id, page, language)
- elseif callback_query.data:match('^%-%d+:antispam:%d*$') then
- local chat_id, page = callback_query.data:match('^(%-%d+):antispam:(%d*)$')
- mattata.toggle_setting(chat_id, 'antispam')
- keyboard = administration.get_initial_keyboard(chat_id, page, language)
- elseif callback_query.data:match('^%-%d+:welcome_message:%d*$') then
- local chat_id, page = callback_query.data:match('^(%-%d+):welcome_message:(%d*)$')
- mattata.toggle_setting(chat_id, 'welcome message')
- keyboard = administration.get_initial_keyboard(chat_id, page, language)
- elseif callback_query.data:match('^%-%d+:delete_commands:%d*$') then
- local chat_id, page = callback_query.data:match('^(%-%d+):delete_commands:(%d*)$')
- mattata.toggle_setting(chat_id, 'delete commands')
- keyboard = administration.get_initial_keyboard(chat_id, page, language)
- elseif callback_query.data:match('^%-%d+:misc_responses:%d*$') then
- local chat_id, page = callback_query.data:match('^(%-%d+):misc_responses:(%d*)$')
- mattata.toggle_setting(chat_id, 'misc responses')
- keyboard = administration.get_initial_keyboard(chat_id, page, language)
- elseif callback_query.data:match('^%-%d+:force_group_language:%d*$') then
- local chat_id, page = callback_query.data:match('^(%-%d+):force_group_language:(%d*)$')
- mattata.toggle_setting(chat_id, 'force group language')
- keyboard = administration.get_initial_keyboard(chat_id, page, language)
- elseif callback_query.data:match('^%-%d+:log:%d*$') then
- local chat_id, page = callback_query.data:match('^(%-%d+):log:(%d*)$')
- mattata.toggle_setting(chat_id, 'log administrative actions')
- keyboard = administration.get_initial_keyboard(chat_id, page, language)
- elseif callback_query.data:match('^%-%d+:settings_in_group:%d*$') then
- local chat_id, page = callback_query.data:match('^(%-%d+):settings_in_group:(%d*)$')
- mattata.toggle_setting(chat_id, 'settings in group')
- keyboard = administration.get_initial_keyboard(chat_id, page, language)
- elseif callback_query.data:match('^%-%d+:kick_media_on_join:%d*$') then
- local chat_id, page = callback_query.data:match('^(%-%d+):kick_media_on_join:(%d*)$')
- mattata.toggle_setting(chat_id, 'kick media on join')
- keyboard = administration.get_initial_keyboard(chat_id, page, language)
- elseif callback_query.data:match('^%-%d+:delete_reply_on_action:%d*$') then
- local chat_id, page = callback_query.data:match('^(%-%d+):delete_reply_on_action:(%d*)$')
- mattata.toggle_setting(chat_id, 'delete reply on action')
- keyboard = administration.get_initial_keyboard(chat_id, page, language)
- elseif callback_query.data:match('^%-%d+:require_captcha:%d*$') then
- local chat_id, page = callback_query.data:match('^(%-%d+):require_captcha:(%d*)$')
- mattata.toggle_setting(chat_id, 'require captcha')
- keyboard = administration.get_initial_keyboard(chat_id, page, language)
- elseif callback_query.data:match('^%-%d+:ban_spamwatch_users:%d*$') then
- local chat_id, page = callback_query.data:match('^(%-%d+):ban_spamwatch_users:(%d*)$')
- mattata.toggle_setting(chat_id, 'ban spamwatch users')
- keyboard = administration.get_initial_keyboard(chat_id, page, language)
- elseif callback_query.data:match('^%-%d+:remove_channel_pins:%d*$') then
- local chat_id, page = callback_query.data:match('^(%-%d+):remove_channel_pins:(%d*)$')
- mattata.toggle_setting(chat_id, 'remove channel pins')
- keyboard = administration.get_initial_keyboard(chat_id, page, language)
- elseif callback_query.data:match('^%-%d+:remove_other_pins:%d*$') then
- local chat_id, page = callback_query.data:match('^(%-%d+):remove_other_pins:(%d*)$')
- mattata.toggle_setting(chat_id, 'remove other pins')
- keyboard = administration.get_initial_keyboard(chat_id, page, language)
- elseif callback_query.data:match('^%-%d+:remove_pasted_code:%d*$') then
- local chat_id, page = callback_query.data:match('^(%-%d+):remove_pasted_code:(%d*)$')
- mattata.toggle_setting(chat_id, 'remove pasted code')
- keyboard = administration.get_initial_keyboard(chat_id, page, language)
- elseif callback_query.data:match('^%-%d+:prevent_inline_bots:%d*$') then
- local chat_id, page = callback_query.data:match('^(%-%d+):prevent_inline_bots:(%d*)$')
- mattata.toggle_setting(chat_id, 'prevent inline bots')
- keyboard = administration.get_initial_keyboard(chat_id, page, language)
- elseif callback_query.data:match('^%-%d+:enable_plugins_for_admins:%d*$') then
- local chat_id, page = callback_query.data:match('^(%-%d+):enable_plugins_for_admins:(%d*)$')
- mattata.toggle_setting(chat_id, 'disable plugins for all')
- keyboard = administration.get_initial_keyboard(chat_id, page, language)
- elseif callback_query.data:match('^%-%d+:kick_urls_on_join:%d*$') then
- local chat_id, page = callback_query.data:match('^(%-%d+):kick_urls_on_join:(%d*)$')
- mattata.toggle_setting(chat_id, 'kick urls on join')
- keyboard = administration.get_initial_keyboard(chat_id, page, language)
- elseif callback_query.data:match('^%-%d+:page:%d*$') then
- local chat_id, page = callback_query.data:match('^(%-%d+):page:(%d*)$')
- keyboard = administration.get_initial_keyboard(chat_id, page, language)
- return mattata.edit_message_reply_markup(message.chat.id, message.message_id, nil, keyboard)
- elseif callback_query.data == 'dismiss_disabled_message' then
- redis:set('administration:' .. message.chat.id .. ':dismiss_disabled_message', true)
- return mattata.answer_callback_query(callback_query.id, language['administration']['39'], true)
- else return mattata.answer_callback_query(callback_query.id) end
- mattata.answer_callback_query(callback_query.id)
- return mattata.edit_message_reply_markup(message.chat.id, message.message_id, nil, keyboard)
-end
-
-function administration:on_message(message, _, language)
- if message.chat.type == 'private' then
- local input = mattata.input(message.text)
- if input then
- if tonumber(input) == nil and not input:match('^@') then
- input = '@' .. input
- end
- local resolved = mattata.get_chat(input)
- if resolved and mattata.is_group_admin(resolved.result.id, message.from.id) then
- message.chat = resolved.result
- message.message_id = nil
- elseif resolved then
- return mattata.send_reply(message, language['administration']['40'])
- else
- return mattata.send_reply(message, language['administration']['41'])
- end
- else
- return mattata.send_reply(message, language['administration']['42'])
- end
- end
- if mattata.is_group_admin(message.chat.id, message.from.id) then
- local keyboard = administration.get_initial_keyboard(message.chat.id, 1, language)
- local recipient = message.from.id
- if mattata.get_setting(message.chat.id, 'settings in group') then
- recipient = message.chat.id
- end
- local output = string.format(language['administration']['43'], mattata.escape_html(message.chat.title))
- local success = mattata.send_message(recipient, output, 'html', true, false, nil, keyboard)
- if not success and recipient == message.from.id then
- return mattata.send_reply(message, string.format(language['administration']['44'], self.info.username:lower()), true)
- elseif recipient == message.from.id then
- return mattata.send_reply(message, language['administration']['45'])
- end
- return success
- end
- return false
-end
-
-return administration
\ No newline at end of file
diff --git a/plugins/administration/addalias.lua b/plugins/administration/addalias.lua
deleted file mode 100644
index 5c79e76..0000000
--- a/plugins/administration/addalias.lua
+++ /dev/null
@@ -1,65 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local addalias = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function addalias:init(configuration)
- addalias.commands = mattata.commands(self.info.username):command('addalias'):command('setalias').table
- addalias.help = '/addalias </alias> </command> - Allows custom aliases to be bound to existing commands. The alias must not be an existing command. All aliases/commands are automatically converted into lowercase text, and can contain letters, numbers and underscores. Alias: /setalias.'
- addalias.limits = configuration.administration.aliases
-end
-
-function addalias:on_message(message, configuration, language)
- if message.chat.type ~= 'supergroup' then
- return mattata.send_reply(message, language.errors.supergroup)
- elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
- return mattata.send_reply(message, language.errors.admin)
- end
- local input = mattata.input(message.text)
- if not input or not input:match('^/[%w_]+ /[%w_]+$') then
- return mattata.send_reply(message, 'Please use the format /addalias /command /alias.')
- end
- local existing, alias = input:match('^/([%w_]+) /([%w_]+)$')
- local length = alias:len()
- if length < addalias.limits.length.min then
- return mattata.send_reply(message, 'The alias must be a minimum of ' .. addalias.limits.length.min .. ' characters long!')
- elseif length > addalias.limits.length.max then
- return mattata.send_reply(message, 'The alias must not be longer than ' .. addalias.limits.length.max .. ' characters long!')
- end
- local total = redis:hgetall('chat:' .. message.chat.id .. ':aliases')
- if #total >= addalias.limits.total then
- return mattata.send_reply(message, 'You\'ve can\'t add anymore than ' .. addalias.limits.total .. ' aliases, please use /aliases and delete some to add more!')
- end
- existing = existing:lower()
- alias = alias:lower()
- local plugins = self.plugins
- local all = {}
- for _, plugin in pairs(plugins) do
- for _, command in pairs(plugin.commands) do
- table.insert(all, command)
- end
- end
- local is_valid = false
- for _, command in pairs(all) do
- if ('/' .. alias):match(command) then
- return mattata.send_reply(message, 'You can\'t set this as a command alias, because this is already bound to a plugin!')
- elseif ('/' .. existing):match(command) then
- is_valid = true
- end
- end
- if not is_valid then
- return mattata.send_reply(message, 'I couldn\'t set that as an alias because the command you specified doesn\'t exist!')
- end
- local exists = redis:hget('chat:' .. message.chat.id .. ':aliases', alias)
- if exists then
- return mattata.send_reply(message, 'I can\'t set /' .. alias .. ' as an alias because it\'s already bound to the following command: /' .. exists)
- end
- redis:hset('chat:' .. message.chat.id .. ':aliases', alias, existing)
- return mattata.send_reply(message, 'Success! You can now trigger the command /' .. existing .. ' using the alias /' .. alias .. '!')
-end
-
-return addalias
\ No newline at end of file
diff --git a/plugins/administration/addrule.lua b/plugins/administration/addrule.lua
deleted file mode 100644
index cf3e694..0000000
--- a/plugins/administration/addrule.lua
+++ /dev/null
@@ -1,38 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local addrule = {}
-local mattata = require('mattata')
-
-function addrule:init()
- addrule.commands = mattata.commands(self.info.username):command('addrule').table
- addrule.help = '/addrule <text> - Allows you to add another group rule!'
-end
-
-function addrule.on_message(_, message, _, language)
- if message.chat.type == 'private' then return false end
- if not mattata.is_group_admin(message.chat.id, message.from.id) then
- return mattata.send_reply(message, language.errors.admin)
- end
- local input = mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, language['addrule']['1'])
- end
- local rules = mattata.get_value(message.chat.id, 'rules')
- if not rules then
- return mattata.send_reply(message, language['addrule']['2'])
- end
- local new_rules = rules .. '\n' .. input
- local success = mattata.send_message(message.chat.id, new_rules, 'markdown')
- if not success and utf8.len(new_rules) > 4096 then
- return mattata.send_reply(message, language['addrule']['3'])
- elseif not success then
- return mattata.send_reply(message, language['addrule']['4'])
- end
- mattata.set_value(message.chat.id, 'rules', new_rules)
- return mattata.edit_message_text(message.chat.id, success.result.message_id, language['addrule']['5'])
-end
-
-return addrule
\ No newline at end of file
diff --git a/plugins/administration/addtrigger.lua b/plugins/administration/addtrigger.lua
deleted file mode 100644
index c6b8673..0000000
--- a/plugins/administration/addtrigger.lua
+++ /dev/null
@@ -1,47 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local addtrigger = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function addtrigger:init()
- addtrigger.commands = mattata.commands(self.info.username):command('addtrigger'):command('newtrigger'):command('addcustom').table
- addtrigger.help = '/addtrigger <trigger> \\n <value> - Allows admins to add triggers, which makes the bot reply with the given value when the trigger is sent in chat. Triggers can be no longer than 32 characters long, and values can be no more than 512 characters long. Trigger values must be sent on a new line. Aliases: /newtrigger, /addcustom.'
-end
-
-function addtrigger:on_message(message, _, language)
- if message.chat.type ~= 'supergroup' then
- return mattata.send_reply(message, language.errors.supergroup)
- elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
- return mattata.send_reply(message, language.errors.admin)
- end
- local input = mattata.input(message.text)
- if not input or not input:match('^.-\n.-$') then
- return mattata.send_reply(message, addtrigger.help)
- end
- local trigger, value = input:match('^(.-)\n(.-)$')
- local count = 0
- local is_duplicate = false
- local all = redis:hgetall('triggers:' .. message.chat.id)
- for _, v in ipairs(all) do
- count = count + 1
- if v == trigger then
- is_duplicate = true
- end
- end
- if is_duplicate then
- return mattata.send_reply(message, 'That trigger already exists! To modify it, delete it first using /triggers.')
- end
- if trigger:len() > 32 then
- return mattata.send_reply(message, 'The trigger needs to be 1-32 characters long, and alpha-numerical.')
- elseif value:len() > 512 then
- return mattata.send_reply(message, 'The value must be no more than 512 characters long!')
- end
- redis:hset('triggers:' .. message.chat.id, trigger, value)
- return mattata.send_reply(message, 'Successfully added that trigger! To view all of this chat\'s triggers, send /triggers.')
-end
-
-return addtrigger
\ No newline at end of file
diff --git a/plugins/administration/allowbot.lua b/plugins/administration/allowbot.lua
deleted file mode 100644
index 0e9256f..0000000
--- a/plugins/administration/allowbot.lua
+++ /dev/null
@@ -1,53 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local allowbot = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function allowbot:init()
- allowbot.commands = mattata.commands(self.info.username):command('allowbot'):command('allowbots'):command('wb').table
- allowbot.help = '/allowbot <bots> - Allowlists the given bots in the current chat. Requires administrative privileges. Aliases: /allowbots, /wb.'
- allowbot.example_bots = { 'gif', 'imdb', 'wiki', 'music', 'youtube', 'bold', 'sticker', 'vote', 'like', 'gamee', 'coub', 'pic', 'vid', 'bing' }
-end
-
-function allowbot:on_new_message(message, configuration, language)
- if message.chat.type ~= 'supergroup' then
- return false
- elseif mattata.get_setting(message.chat.id, 'prevent inline bots') and message.via_bot and not mattata.is_group_admin(message.chat.id, message.from.id) then
- return mattata.delete_message(message.chat.id, message.message_id)
- end
-end
-
-function allowbot:on_message(message, configuration, language)
- if not mattata.is_group_admin(message.chat.id, message.from.id) then
- return mattata.send_reply(message, language.errors.admin)
- end
- local input = mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, 'Please specify the @usernames of the bots you\'d like to allowlist.')
- elseif not input:match('@?[%w_]') then
- return mattata.send_reply(message, 'Please make sure you\'re specifying valid bot usernames!')
- end
- local bots = {}
- for bot in input:gmatch('@?([%w_]+bot)') do
- table.insert(bots, bot)
- end
- for _, bot in pairs(allowbot.example_bots) do
- if input:match('@?' .. bot) then
- table.insert(bots, bot)
- end
- end
- if #bots == 0 then
- return mattata.send_reply(message, 'Please make sure you\'re specifying valid bot usernames!')
- end
- for _, bot in pairs(bots) do
- redis:sadd('allowlisted_bots:' .. message.chat.id, bot)
- end
- local output = string.format('Successfully allowlisted the following bots in this chat: %s', table.concat(bots, ', '))
- return mattata.send_reply(message, output)
-end
-
-return allowbot
\ No newline at end of file
diff --git a/plugins/administration/allowedlinks.lua b/plugins/administration/allowedlinks.lua
deleted file mode 100644
index 310c494..0000000
--- a/plugins/administration/allowedlinks.lua
+++ /dev/null
@@ -1,35 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local allowedlinks = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function allowedlinks:init()
- allowedlinks.commands = mattata.commands(self.info.username):command('allowedlinks'):command('al').table
- allowedlinks.help = '/allowedlinks - View the Telegram invite links you\'re allowed to send in this chat. Alias: /al.'
-end
-
-function allowedlinks:on_message(message, _, language)
- if message.chat.type ~= 'supergroup' then
- return mattata.send_reply(message, language.errors.supergroup)
- elseif not mattata.get_setting(message.chat.id, 'antilink') then
- return mattata.send_reply(message, 'You\'re as free as a bird! Feel free to send any links in this chat (make sure you check the `/rules` first!). Admins can setup anti-link by using `/settings`, enabling `Anti-Link` and sending `/allowlink <links>`.', true)
- end
- local allowed = redis:keys('allowlisted_links:' .. message.chat.id .. ':*')
- local output = { 'You\'re allowed to send the following links in this group:\n' }
- if #allowed == 0 then
- return mattata.send_reply(message, 'There are no allowlisted groups here. Admins can allowlist Telegram links (or @username) by sending `/allowlink <links>`.', true)
- end
- for _, link in pairs(allowed) do
- link = link:match('^allowlisted_links:' .. tostring(message.chat.id):gsub('%-', '%%-') .. ':(.-)$')
- link = 't.me/' .. link
- table.insert(output, mattata.symbols.bullet .. ' ' .. link)
- end
- output = table.concat(output, '\n')
- return mattata.send_reply(message, output, nil, true)
-end
-
-return allowedlinks
\ No newline at end of file
diff --git a/plugins/administration/allowlink.lua b/plugins/administration/allowlink.lua
deleted file mode 100644
index edb4867..0000000
--- a/plugins/administration/allowlink.lua
+++ /dev/null
@@ -1,43 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local allowlink = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function allowlink:init()
- allowlink.commands = mattata.commands(self.info.username):command('allowlink'):command('wl').table
- allowlink.help = '/allowlink <links> - Allowlists the given links in the current chat. Requires administrative privileges. Use /allowlink -del <links> to Alias: /wl.'
-end
-
-function allowlink:on_callback_query(callback_query, message, _, language)
- if message.chat.type ~= 'supergroup' then
- return mattata.answer_callback_query(callback_query.id, language.errors.supergroup)
- elseif not mattata.is_group_admin(message.chat.id, callback_query.from.id) then
- return mattata.answer_callback_query(callback_query.id, language.errors.admin)
- end
- redis:set('allowlisted_links:' .. message.chat.id .. ':' .. callback_query.data, true)
- mattata.answer_callback_query(callback_query.id, 'Successfully allowlisted that link!', true)
- return mattata.delete_message(message.chat.id, message.message_id)
-end
-
-function allowlink:on_message(message)
- if not mattata.is_group_admin(message.chat.id, message.from.id) then
- return false
- end
- local input = mattata.input(message.text)
- local delete = false
- if not input then
- return mattata.send_reply(message, 'Please specify the URLs or @usernames you\'d like to allowlist.')
- elseif input:match('^%-del .-$') then
- input = input:match('^%-del (.-)$')
- delete = true
- end
- message.text = input
- local output = mattata.check_links(message, false, false, true, false, delete)
- return mattata.send_reply(message, output)
-end
-
-return allowlink
\ No newline at end of file
diff --git a/plugins/administration/allowlist.lua b/plugins/administration/allowlist.lua
deleted file mode 100644
index be1044c..0000000
--- a/plugins/administration/allowlist.lua
+++ /dev/null
@@ -1,167 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local allowlist = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function allowlist:init()
- allowlist.commands = mattata.commands(self.info.username):command('allowlist').table
- allowlist.help = '/allowlist [user] - Allowlists a user to use the bot in the current chat. This command can only be used by moderators and administrators of a supergroup.'
-end
-
-function allowlist:on_message(message, configuration, language)
- if message.chat.type ~= 'supergroup'
- then
- return mattata.send_reply(
- message,
- language['errors']['supergroup']
- )
- elseif not mattata.is_group_admin(
- message.chat.id,
- message.from.id
- )
- then
- return mattata.send_reply(
- message,
- language['errors']['admin']
- )
- end
- local reason = false
- local input = message.reply
- and (
- message.reply.from.username
- or tostring(message.reply.from.id)
- )
- or mattata.input(message.text)
- if not input
- then
- local success = mattata.send_force_reply(
- message,
- language['allowlist']['1']
- )
- if success
- then
- redis:set(
- string.format(
- 'action:%s:%s',
- message.chat.id,
- success.result.message_id
- ),
- '/allowlist'
- )
- end
- return
- elseif not message.reply
- then
- if input:match('^.- .-$')
- then
- reason = input:match(' (.-)$')
- input = input:match('^(.-) ')
- end
- elseif mattata.input(message.text)
- then
- reason = mattata.input(message.text)
- end
- if tonumber(input) == nil
- and not input:match('^%@')
- then
- input = '@' .. input
- end
- local user = mattata.get_user(input)
- or mattata.get_chat(input) -- Resolve the username/ID to a user object.
- if not user
- then
- return mattata.send_reply(
- message,
- language['errors']['unknown']
- )
- elseif user.result.id == self.info.id
- then
- return
- end
- user = user.result
- local status = mattata.get_chat_member(
- message.chat.id,
- user.id
- )
- if not status
- then
- return mattata.send_reply(
- message,
- language['errors']['generic']
- )
- elseif mattata.is_group_admin(
- message.chat.id,
- user.id
- )
- or status.result.status == 'creator'
- or status.result.status == 'administrator'
- then -- We won't try and allowlist moderators and administrators.
- return mattata.send_reply(
- message,
- language['allowlist']['2']
- )
- elseif status.result.status == 'left'
- or status.result.status == 'kicked'
- then -- Check if the user is in the group or not.
- return mattata.send_reply(
- message,
- status.result.status == 'left'
- and language['allowlist']['3']
- or language['allowlist']['4']
- )
- end
- redis:del('group_allowlist:' .. message.chat.id .. ':' .. user.id)
- redis:hincrby(
- string.format(
- 'chat:%s:%s',
- message.chat.id,
- user.id
- ),
- 'allowlists',
- 1
- )
- if redis:hget(
- string.format(
- 'chat:%s:settings',
- message.chat.id
- ),
- 'log administrative actions'
- ) then
- mattata.send_message(
- mattata.get_log_chat(message.chat.id),
- string.format(
- '<pre>%s%s [%s] has allowlisted %s%s [%s] in %s%s [%s]%s.</pre>',
- message.from.username and '@' or '',
- message.from.username or mattata.escape_html(message.from.first_name),
- message.from.id,
- user.username and '@' or '',
- user.username or mattata.escape_html(user.first_name),
- user.id,
- message.chat.username and '@' or '',
- message.chat.username or mattata.escape_html(message.chat.title),
- message.chat.id,
- reason and ', for ' .. reason or ''
- ),
- 'html'
- )
- end
- mattata.unban_chat_member(message.chat.id, user.id) -- attempt to unban the user too
- return mattata.send_message(
- message.chat.id,
- string.format(
- '<pre>%s%s has allowlisted %s%s%s.</pre>',
- message.from.username and '@' or '',
- message.from.username or mattata.escape_html(message.from.first_name),
- user.username and '@' or '',
- user.username or mattata.escape_html(user.first_name),
- reason and ', for ' .. reason or ''
- ),
- 'html'
- )
-end
-
-return allowlist
\ No newline at end of file
diff --git a/plugins/administration/anticrypto.lua b/plugins/administration/anticrypto.lua
deleted file mode 100644
index 02c885f..0000000
--- a/plugins/administration/anticrypto.lua
+++ /dev/null
@@ -1,65 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local anticrypto = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function anticrypto:on_new_message(message, configuration)
- if 1+1 == 2 then return false end
- if message.chat.type ~= 'supergroup' or tonumber(redis:get('messages:' .. message.from.id .. ':' .. message.chat.id)) > 20 or not message.photo or (mattata.is_group_admin(message.chat.id, message.from.id) and not mattata.is_global_admin(message.from.id)) then
- return false
- elseif not redis:sismember('anticrypto:groups', message.chat.id) then
- return false
- end
- local file_id = message.photo[#message.photo].file_id
- local file = mattata.get_file(file_id)
- if not file then
- return false
- end
- local file_name = file.result.file_path
- local file_path = string.format('https://api.telegram.org/file/bot%s/%s', configuration.bot_token, file_name)
- file = mattata.download_file(file_path, file_name:match('/(.-)$'), configuration.download_location)
- if not file then
- return false
- end
- local command = string.format('tesseract --tessdata-dir /home/matt/matticatebot/tesseract/ --oem 3 %s stdout', file)
- local exec = io.popen(command)
- local contents = exec:read('*all')
- exec:close()
- os.execute('rm ' .. file)
- local matches = {
- '[Tt][Ee][Ss][LlTt][Aa]',
- '[Bb][Ii][Tt][Cc][Oo][Ii][Nn]',
- '[AaEe]Ll][Oo][Nn] ?[Mm][Nn]?[Uu][Ss][Kk]',
- '[Gg][Ii][Vv][Ee][Aa][Ww][Aa][Yy]',
- '[Ff][Ii][Nn][Aa][Nn][Cc][Ii][Aa][Ll]',
- '[Dd][Rr][Oo][Pp][EeAa][LlI][Oo][Nn]'
- }
- for _, match in pairs(matches) do
- if contents:match(match) then
- local punishment = mattata.get_setting(message.chat.id, 'ban not kick')
- local action = punishment and mattata.ban_chat_member or mattata.kick_chat_member
- action(message.chat.id, message.from.id)
- punishment = punishment and 'banned' or 'kicked'
- local bot_username = mattata.get_formatted_user(self.info.id, self.info.first_name, 'html')
- local offender_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
- local output
- if mattata.get_setting(message.chat.id, 'log administrative actions') then
- local log_chat = mattata.get_log_chat(message.chat.id)
- output = '%s <code>[%s]</code> has %s %s <code>[%s]</code> from %s <code>[%s]</code> for sending crypto-spam.\n%s %s'
- output = string.format(output, bot_username, self.info.id, punishment, offender_username, message.from.id, mattata.escape_html(message.chat.title), message.chat.id, '#chat' .. tostring(message.chat.id):gsub('^-100', ''), '#user' .. message.from.id)
- mattata.send_message(log_chat, output, 'html')
- else
- output = string.format('%s %s for sending crypto-spam.', punishment:gsub('^%l', string.upper), offender_username)
- mattata.send_message(message.chat.id, output, 'html')
- end
- return mattata.delete_message(message.chat.id, message.message_id)
- end
- end
- return mattata.send_message(configuration.admins[1], contents)
-end
-
-return anticrypto
\ No newline at end of file
diff --git a/plugins/administration/antispam.lua b/plugins/administration/antispam.lua
deleted file mode 100644
index 7a89ec0..0000000
--- a/plugins/administration/antispam.lua
+++ /dev/null
@@ -1,345 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local antispam = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function antispam:init(configuration)
- antispam.commands = mattata.commands(self.info.username):command('antispam').table
- antispam.media_types = {
- 'text',
- 'forwarded',
- 'sticker',
- 'photo',
- 'video',
- 'location',
- 'voice',
- 'game',
- 'venue',
- 'video note',
- 'invoice',
- 'contact',
- 'dice',
- 'poll'
- }
- antispam.default_values = {
- ['text'] = configuration.administration.default.antispam.text,
- ['forwarded'] = configuration.administration.default.antispam.forwarded,
- ['sticker'] = configuration.administration.default.antispam.sticker,
- ['photo'] = configuration.administration.default.antispam.photo,
- ['video'] = configuration.administration.default.antispam.video,
- ['location'] = configuration.administration.default.antispam.location,
- ['voice'] = configuration.administration.default.antispam.voice,
- ['game'] = configuration.administration.default.antispam.game,
- ['venue'] = configuration.administration.default.antispam.venue,
- ['video note'] = configuration.administration.default.antispam.video_note,
- ['invoice'] = configuration.administration.default.antispam.invoice,
- ['contact'] = configuration.administration.default.antispam.contact,
- ['dice'] = configuration.administration.default.antispam.dice,
- ['poll'] = configuration.administration.default.antispam.poll
- }
-end
-
-function antispam.on_member_join(_, message)
- for _, user in pairs(message.new_chat_members) do
- redis:set('join_time:' .. user.id .. ':' .. message.chat.id, os.time())
- end
-end
-
-function antispam:on_new_message(message, configuration, language)
- if message.chat.type == 'supergroup' then
- local spamming = antispam.process_message(self, message, configuration, language)
- if spamming then
- return
- end
- end
- if message.from.id == 777000 then
- return false
- end
- -- Thanks to GingerPlusPlus for the idea
- if message.chat.type ~= 'private' and mattata.get_setting(message.chat.id, 'remove pasted code') then
- if message.entities then
- for _, entity in pairs(message.entities) do
- if (entity.type == 'pre' or entity.type == 'code') and entity.length > configuration.administration.global_antispam.max_code_length and not mattata.is_group_admin(message.chat.id, message.from.id) then
- local success = mattata.delete_message(message.chat.id, message.message_id)
- if success then
- local name = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
- local output = string.format(language['antispam']['11'], name, configuration.administration.global_antispam.max_code_length, self.info.username:lower())
- return mattata.send_message(message.chat.id, output, 'html', true)
- end
- return false
- end
- end
- end
- end
- if message.chat.type == 'supergroup' and mattata.get_setting(message.chat.id, 'antilink') and message.is_invite_link then
- if not mattata.is_group_admin(message.chat.id, message.from.id) and not mattata.is_global_admin(message.from.id) and message.is_invite_link then
- local action = mattata.get_setting(message.chat.id, 'ban not kick') and mattata.ban_chat_member or mattata.kick_chat_member
- local punishment = mattata.get_setting(message.chat.id, 'ban not kick') and 'banned' or 'kicked'
- local success = action(message.chat.id, message.from.id)
- local output
- if success then
- local banned_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
- if mattata.get_setting(message.chat.id, 'log administrative actions') then
- local log_chat = mattata.get_log_chat(message.chat.id)
- local admin_username = mattata.get_formatted_user(self.info.id, self.info.first_name, 'html')
- output = string.format(language['antispam']['12'], admin_username, self.info.id, punishment, banned_username, message.from.id, mattata.escape_html(message.chat.title), message.chat.id, tostring(message.chat.id):gsub('^%-100', ''), message.from.id)
- mattata.send_message(log_chat, output, 'html')
- else
- output = string.format(language['antispam']['13'], punishment:gsub('^%l', string.upper), banned_username)
- mattata.send_message(message.chat.id, output, 'html')
- end
- mattata.delete_message(message.chat.id, message.message_id)
- return
- end
- else
- local allowlisted = true
- local blocked_link
- local links = mattata.check_links(message, true, true)
- if links and #links > 0 then
- for _, link in pairs(links) do
- if not redis:get('allowlisted_links:' .. message.chat.id .. ':' .. link) and not mattata.table_contains(configuration.administration.allowed_links, link:lower()) then
- allowlisted = false
- blocked_link = link:lower()
- break
- end
- end
- end
- if not allowlisted and not message.text:match('^[!/#]allowlink') and not message.text:match('^[!/#]wl') then
- local keyboard = mattata.inline_keyboard():row(mattata.row():callback_data_button('Allowlist it!', 'allowlink:' .. blocked_link))
- return mattata.send_reply(message, language['antispam']['14'], nil, true, keyboard)
- end
- end
- end
- local messages = redis:get('messages:' .. message.from.id .. ':' .. message.chat.id) or 0
- local join_time = redis:get('join_time:' .. message.from.id .. ':' .. message.chat.id)
- if message.chat.type == 'supergroup' and not mattata.is_group_admin(message.chat.id, message.from.id) and messages <= 3 and join_time and mattata.get_setting(message.chat.id, 'kick urls on join') and message.entities then
- for _, entity in pairs(message.entities) do
- if entity.type == 'url' then
- redis:del('messages:' .. message.from.id .. ':' .. message.chat.id)
- local log_actions = mattata.get_setting(message.chat.id, 'log administrative actions')
- local log_chat = mattata.get_log_chat(message.chat.id)
- local kicked_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
- local output = string.format(language['antispam']['16'], kicked_username, message.from.id, mattata.escape_html(message.chat.title), message.chat.id, tostring(message.chat.id):gsub('^%-100', ''), message.from.id)
- for _, entities in pairs(message.entities) do
- if entities.type == 'url' then
- mattata.delete_message(message.chat.id, message.message_id)
- if log_actions then
- mattata.send_message(log_chat, output, 'html')
- end
- return mattata.kick_chat_member(message.chat.id, message.from.id)
- end
- end
- end
- end
- end
- if message.chat.type == 'supergroup' and (message.entities or message.photo or message.document) and mattata.get_setting(message.chat.id, 'kick media on join') and messages <= 2 and not mattata.is_group_admin(message.chat.id, message.from.id) and join_time then
- redis:del('messages:' .. message.from.id .. ':' .. message.chat.id)
- local log_actions = mattata.get_setting(message.chat.id, 'log administrative actions')
- local log_chat = mattata.get_log_chat(message.chat.id)
- local kicked_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
- local output = string.format(language['antispam']['15'], kicked_username, message.from.id, mattata.escape_html(message.chat.title), message.chat.id, tostring(message.chat.id):gsub('^%-100', ''), message.from.id)
- if message.photo or message.document then
- mattata.delete_message(message.chat.id, message.message_id)
- if log_actions then
- mattata.send_message(log_chat, output, 'html')
- end
- return mattata.kick_chat_member(message.chat.id, message.from.id)
- end
- end
-end
-
-function antispam.get_keyboard(chat_id, language)
- local status = redis:hget('chat:' .. chat_id .. ':settings', 'antispam') and true or false
- local caption = status and language['antispam']['1'] or language['antispam']['2']
- local keyboard = {
- ['inline_keyboard'] = {}
- }
- table.insert(keyboard.inline_keyboard, {{
- ['text'] = caption,
- ['callback_data'] = 'antispam:' .. chat_id .. ':' .. caption:lower()
- }})
- local actions = {
- language['antispam']['18'],
- language['antispam']['19'],
- language['antispam']['20']
- }
- local action = mattata.get_setting(chat_id, 'antispam action') or 1
- action = math.floor(action)
- if status then
- for _, media in pairs(antispam.media_types) do
- local current = mattata.get_value(chat_id, media .. ' limit') or antispam.default_values[media]
- if not mattata.get_setting(chat_id, 'allow ' .. media) then
- table.insert(keyboard.inline_keyboard, {{
- ['text'] = media:gsub('^%l', string.upper),
- ['callback_data'] = 'antispam:nil'
- }, {
- ['text'] = '-',
- ['callback_data'] = 'antispam:' .. chat_id .. ':limit:' .. media .. ':' .. tonumber(current) - 1
- }, {
- ['text'] = tostring(current),
- ['callback_data'] = 'antispam:nil'
- }, {
- ['text'] = '+',
- ['callback_data'] = 'antispam:' .. chat_id .. ':limit:' .. media .. ':' .. tonumber(current) + 1
- }, {
- ['text'] = language['antispam']['3'],
- ['callback_data'] = 'antispam:' .. chat_id .. ':toggle:' .. media
- }})
- else
- table.insert(keyboard.inline_keyboard, {{
- ['text'] = media:gsub('^%l', string.upper),
- ['callback_data'] = 'antispam:nil'
- }, {
- ['text'] = string.format(language['antispam']['4'], media),
- ['callback_data'] = 'antispam:' .. chat_id .. ':toggle:' .. media
- }})
- end
- end
- end
- table.insert(keyboard.inline_keyboard, {{
- ['text'] = language['antispam']['17'],
- ['callback_data'] = 'antispam:nil'
- }, {
- ['text'] = actions[action],
- ['callback_data'] = 'antispam:' .. chat_id .. ':action'
- }})
- table.insert(keyboard.inline_keyboard, {{
- ['text'] = mattata.symbols.back .. ' ' .. language['antispam']['5'],
- ['callback_data'] = 'administration:' .. chat_id .. ':page:1'
- }})
- return keyboard
-end
-
-function antispam.is_user_spamming(message)
- if message.media_type == '' or mattata.get_setting(message.chat.id, 'allow ' .. message.media_type) then
- return false
- end
- local limit = mattata.get_value(message.chat.id, message.media_type .. ' limit') or antispam.default_values[message.media_type]
- local current = redis:get('antispam:' .. message.media_type .. ':' .. message.chat.id .. ':' .. message.from.id) or 1
- redis:setex('antispam:' .. message.media_type .. ':' .. message.chat.id .. ':' .. message.from.id, 5, tonumber(current) + 1)
- if tonumber(current) == tonumber(limit) then
- return true, message.media_type
- elseif message.media_type == 'rtl' and mattata.get_setting(message.chat.id, 'antirtl') then
- return true, 'rtl'
- end
- return false
-end
-
-function antispam:process_message(message, _, language)
- if message.chat.type ~= 'supergroup' then
- return false, 'The chat is not a supergroup!'
- elseif mattata.is_group_admin(message.chat.id, message.from.id) then
- return false, 'That user is an administrator in this chat!'
- elseif mattata.is_global_admin(message.from.id) then
- return false, 'That user is a global admin!'
- elseif not mattata.get_setting(message.chat.id, 'use administration') then
- return false, 'The administration plugin is switched off in this chat!'
- elseif not mattata.get_setting(message.chat.id, 'antispam') then
- return false, 'The antispam plugin is switched off in this chat!'
- end
- local is_spamming, media_type = antispam.is_user_spamming(message)
- if not is_spamming then
- return false, 'This user is not spamming!'
- end
- local action = mattata.get_setting(message.chat.id, 'antispam action') or 1
- action = math.floor(action)
- local success, error_message
- local output
- if action == 1 then
- success, error_message = mattata.kick_chat_member(message.chat.id, message.from.id)
- output = language['antispam']['7']
- elseif action == 2 then
- success, error_message = mattata.ban_chat_member(message.chat.id, message.from.id)
- output = 'Banned %s for hitting the configured antispam limit for [%s] media.'
- else
- success, error_message = mattata.restrict_chat_member(message.chat.id, message.from.id, os.time(), false, false, false, false, false, false, false, false)
- output = 'Muted %s for hitting the configured antispam limit for [%s] media.'
- end
- if not success then
- return false, error_message
- elseif mattata.get_setting(message.chat.id, 'log administrative actions') then
- mattata.send_message(
- mattata.get_log_chat(message.chat.id),
- string.format(
- '<pre>' .. language['antispam']['6'] .. '</pre>',
- mattata.escape_html(self.info.first_name),
- self.info.id,
- mattata.escape_html(message.from.first_name),
- message.from.id,
- mattata.escape_html(message.chat.title),
- message.chat.id,
- media_type
- ),
- 'html'
- )
- end
- return mattata.send_message(
- message,
- string.format(
- output,
- message.from.username and '@' .. message.from.username or message.from.first_name,
- media_type
- )
- )
-end
-
-function antispam.on_callback_query(_, callback_query, message, _, language)
- local chat_id = (message and message.chat and message.chat.type == 'supergroup') and message.chat.id or callback_query.data:match('^(%-%d+):?')
- if not chat_id then
- mattata.answer_callback_query(callback_query.id, language['errors']['generic'])
- return false, 'No chat ID was found!'
- elseif not mattata.is_group_admin(chat_id, callback_query.from.id) then
- mattata.answer_callback_query(callback_query.id, language['errors']['admin'])
- return false, 'That user is not an admin/mod in this chat!'
- end
- if callback_query.data:match('^%-%d+:limit:.-:.-$') then
- local spam_type, limit = callback_query.data:match('^%-%d+:limit:(.-):(.-)$')
- if tonumber(limit) > 100 then
- local output = language['antispam']['8']
- mattata.answer_callback_query(callback_query.id, output)
- return false, output
- elseif tonumber(limit) < 1 then
- local output = language['antispam']['9']
- mattata.answer_callback_query(callback_query.id, output)
- return false, output
- elseif tonumber(limit) == nil then
- return false, 'The limit given wasn\'t of type "number"!'
- end
- redis:hset('chat:' .. chat_id .. ':info', spam_type .. ' limit', tonumber(limit))
- elseif callback_query.data:match('^%-%d+:toggle:.-$') then
- local spam_type = callback_query.data:match('^%-%d+:toggle:(.-)$')
- mattata.toggle_setting(chat_id, 'allow ' .. spam_type)
- elseif callback_query.data:match('^%-%d+:disable$') then
- redis:hdel('chat:' .. chat_id .. ':settings', 'antispam')
- elseif callback_query.data:match('^%-%d+:enable$') then
- redis:hset('chat:' .. chat_id .. ':settings', 'antispam', true)
- elseif callback_query.data:match('^%-%d+:action$') then
- local current = mattata.get_setting(chat_id, 'antispam action') or 1
- local new = current + 1
- if new > 3 then
- new = 1
- end
- redis:hset('chat:' .. chat_id .. ':settings', 'antispam action', new)
- end
- local keyboard = antispam.get_keyboard(chat_id, language)
- return mattata.edit_message_reply_markup(message.chat.id, message.message_id, nil, keyboard)
-end
-
-function antispam.on_message(_, message, _, language)
- if message.chat.type ~= 'supergroup' then
- mattata.send_reply(message, language['errors']['supergroup'])
- return false, 'The chat is not a supergroup!'
- elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
- mattata.send_reply(message, language['errors']['admin'])
- return false, 'That user is not an admin/mod in this chat!'
- end
- local output = string.format(language['antispam']['10'], message.chat.title)
- local keyboard = antispam.get_keyboard(message.chat.id, language)
- return mattata.send_message(message.chat.id, output, nil, true, false, nil, keyboard)
-end
-
-return antispam
\ No newline at end of file
diff --git a/plugins/administration/ban.lua b/plugins/administration/ban.lua
deleted file mode 100644
index f3c3f8b..0000000
--- a/plugins/administration/ban.lua
+++ /dev/null
@@ -1,94 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local ban = {}
-local mattata = require('mattata')
-
-function ban:init()
- ban.commands = mattata.commands(self.info.username):command('ban').table
- ban.help = '/ban [user] - Bans a user from the current chat. This command can only be used by moderators and administrators of a supergroup.'
-end
-
-function ban:on_message(message, _, language)
- if message.chat.type ~= 'supergroup' then
- local output = language['errors']['supergroup']
- return mattata.send_reply(message, output)
- elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
- local output = language['errors']['admin']
- return mattata.send_reply(message, output)
- end
- local reason = false
- local user = false
- local input = mattata.input(message)
- -- check the message object for any users this command
- -- is intended to be executed on
- if message.reply then
- user = message.reply.from.id
- if input then
- reason = input
- end
- elseif input and input:match(' ') then
- user, reason = input:match('^(.-) (.-)$')
- elseif input then
- user = input
- end
- if not user then
- local output = language['ban']['1']
- local success = mattata.send_force_reply(message, output)
- if success then
- mattata.set_command_action(message.chat.id, success.result.message_id, '/ban')
- end
- return
- end
- if reason and type(reason) == 'string' and reason:match('^[Ff][Oo][Rr] ') then
- reason = reason:match('^[Ff][Oo][Rr] (.-)$')
- end
- if tonumber(user) == nil and not user:match('^%@') then
- user = '@' .. user
- end
- local user_object = mattata.get_user(user) or mattata.get_chat(user) -- resolve the username/ID to a user object
- if not user_object then
- return mattata.send_reply(message, language.errors.unknown)
- elseif user_object.result.id == self.info.id then
- return false -- don't let the bot ban itself
- end
- user_object = user_object.result
- local status = mattata.get_chat_member(message.chat.id, user_object.id)
- local is_admin = mattata.is_group_admin(message.chat.id, user_object.id)
- if not status then
- local output = language['errors']['generic']
- return mattata.send_reply(message, output)
- elseif is_admin then -- we won't try and ban moderators and administrators.
- local output = language['ban']['2']
- return mattata.send_reply(message, output)
- elseif status.result.status == 'kicked' then -- check if the user has already been kicked
- local output = language['ban']['4']
- return mattata.send_reply(message, output)
- end
- local success = mattata.ban_chat_member(message.chat.id, user_object.id) -- attempt to ban the user from the group
- if not success then -- since we've ruled everything else out, it's safe to say if it wasn't a success then the bot just isn't an administrator in the group
- local output = language['ban']['5']
- return mattata.send_reply(message, output)
- end
- mattata.increase_administrative_action(message.chat.id, user_object.id, 'bans')
- reason = reason and '\nReason: ' .. reason or ''
- local admin_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
- local banned_username = mattata.get_formatted_user(user_object.id, user_object.first_name, 'html')
- local output
- if mattata.get_setting(message.chat.id, 'log administrative actions') then
- local log_chat = mattata.get_log_chat(message.chat.id)
- output = string.format(language['ban']['6'], admin_username, message.from.id, banned_username, user_object.id, mattata.escape_html(message.chat.title), message.chat.id, reason, '#chat' .. tostring(message.chat.id):gsub('^-100', ''), '#user' .. user_object.id)
- mattata.send_message(log_chat, output, 'html')
- else
- output = string.format(language['ban']['7'], admin_username, banned_username, reason)
- mattata.send_message(message.chat.id, output, 'html')
- end
- if message.reply and mattata.get_setting(message.chat.id, 'delete reply on action') then
- mattata.delete_message(message.chat.id, message.reply.message_id)
- end
- return mattata.delete_message(message.chat.id, message.message_id)
-end
-
-return ban
\ No newline at end of file
diff --git a/plugins/administration/banpack.lua b/plugins/administration/banpack.lua
deleted file mode 100644
index 1a42d9a..0000000
--- a/plugins/administration/banpack.lua
+++ /dev/null
@@ -1,51 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local banpack = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function banpack:init()
- banpack.commands = mattata.commands(self.info.username):command('banpack'):command('bp').table
- banpack.help = '/banpack - Bans, and removes when sent by normal users, any stickers from the replied-to sticker\'s pack. This command can only be used by moderators and administrators of a supergroup, who are also exempt from being disallowed to send stickers from these packs. Alias: /bp.'
-end
-
-function banpack:on_new_message(message)
- if message.chat.type ~= 'supergroup' or not message.sticker or not message.sticker.set_name then
- return false
- elseif redis:sismember('banned_sticker_packs:' .. message.chat.id, message.sticker.set_name) and not mattata.is_group_admin(message.chat.id, message.from.id) then
- return mattata.delete_message(message.chat.id, message.message_id)
- end
- return false
-end
-
-function banpack:on_message(message, _, language)
- if message.chat.type ~= 'supergroup' then
- return mattata.send_reply(message, language.errors.supergroup)
- elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
- return mattata.send_reply(message, language.errors.admin)
- elseif not message.reply then
- return mattata.send_reply(message, 'Please reply to a sticker from the sticker set you\'d like to ban.')
- elseif not message.reply.sticker then
- return mattata.send_reply(message, 'You must use this command in reply to a sticker!')
- elseif not message.reply.sticker.set_name then
- return mattata.send_reply(message, 'That sticker isn\'t from a set, it\'s just a file - I\'m afraid I can\'t ban that!')
- end
- local set_name = message.reply.sticker.set_name
- if redis:sismember('banned_sticker_packs:' .. message.chat.id, set_name) then
- mattata.send_reply(message, 'That [sticker pack](https://t.me/addstickers/' .. set_name .. ') is already banned in this chat! To unban it, send /unbanpack in reply to one of the stickers from it!', true, true)
- end
- redis:sadd('banned_sticker_packs:' .. message.chat.id, set_name)
- if mattata.get_setting(message.chat.id, 'log administrative actions') then
- local log_chat = mattata.get_log_chat(message.chat.id)
- local output = '%s <code>[%s]</code> has banned the sticker pack <a href="https://t.me/addstickers/%s">%s</a> in %s <code>[%s]</code>.\n#chat%s #user%s'
- local admin = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
- output = string.format(output, admin, message.from.id, set_name, set_name, mattata.escape_html(message.chat.title), message.chat.id, tostring(message.chat.id):gsub('^%-100', ''), message.from.id)
- mattata.send_message(log_chat, output, 'html')
- end
- return mattata.send_reply(message, 'I\'ve successfully banned [that sticker pack](https://t.me/addstickers/' .. set_name .. ') in this chat! To unban it, send /unbanpack in reply to a sticker from it - admins can still send these stickers!', true, true)
-end
-
-return banpack
\ No newline at end of file
diff --git a/plugins/administration/blocklist.lua b/plugins/administration/blocklist.lua
deleted file mode 100644
index 6e49490..0000000
--- a/plugins/administration/blocklist.lua
+++ /dev/null
@@ -1,77 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local allowlist = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function allowlist:init()
- allowlist.commands = mattata.commands(self.info.username):command('allowlist').table
- allowlist.help = '/allowlist [user] - Blocklists a user from using the bot in the current chat. This command can only be used by moderators and administrators of a supergroup.'
-end
-
-function allowlist:on_message(message, _, language)
- if message.chat.type ~= 'supergroup' then
- return mattata.send_reply(message, language.errors.supergroup)
- elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
- return mattata.send_reply(message, language.errors.admin)
- end
- local reason = false
- local input = message.reply and message.reply.from.id or mattata.input(message.text)
- if not input then
- local success = mattata.send_force_reply(message, language['allowlist']['1'])
- if success then
- mattata.set_command_action(message.chat.id, success.result.message_id, '/allowlist')
- end
- return
- elseif not message.reply then
- if input:match('^.- .-$') then
- input, reason = input:match('^(.-) (.-)$')
- end
- elseif mattata.input(message.text) then
- reason = mattata.input(message.text)
- end
- if tonumber(input) == nil and not input:match('^%@') then
- input = '@' .. input
- end
- local user = mattata.get_user(input) -- Resolve the username/ID to a user object.
- if not user then
- return mattata.send_reply(message, language.errors.unknown)
- elseif user.result.id == self.info.id then
- return
- end
- user = user.result
- local status = mattata.get_chat_member(message.chat.id, user.id)
- if not status then
- return mattata.send_reply(message, language.errors.generic)
- elseif mattata.is_group_admin(message.chat.id, user.id) then -- We won't try and allowlist moderators and administrators.
- return mattata.send_reply(message, language['allowlist']['2'])
- elseif status.result.status == 'left' or status.result.status == 'kicked' then -- Check if the user is in the group or not.
- local output = status.result.status == 'left' and language['allowlist']['3'] or language['allowlist']['4']
- return mattata.send_reply(message, output)
- end
- redis:set('group_allowlist:' .. message.chat.id .. ':' .. user.id, true)
- mattata.increase_administrative_action(message.chat.id, user.id, 'allowlists')
- reason = reason and ', for ' .. reason or ''
- local admin_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
- local allowlisted_username = mattata.get_formatted_user(user.id, user.first_name, 'html')
- local bot_username = mattata.get_formatted_user(self.info.id, self.info.first_name, 'html')
- local output
- if mattata.get_setting(message.chat.id, 'log administrative actions') then
- local log_chat = mattata.get_log_chat(message.chat.id)
- output = string.format(language['allowlist']['5'], admin_username, message.from.id, allowlisted_username, user.id, bot_username, self.info.id, mattata.escape_html(message.chat.title), message.chat.id, reason, '#chat' .. tostring(message.chat.id):gsub('^-100', ''), '#user' .. user.id)
- mattata.send_message(log_chat, output, 'html')
- else
- output = string.format(language['allowlist']['6'], admin_username, allowlisted_username, bot_username, reason)
- mattata.send_message(message.chat.id, output, 'html')
- end
- if message.reply and mattata.get_setting(message.chat.id, 'delete reply on action') then
- mattata.delete_message(message.chat.id, message.reply.message_id)
- mattata.delete_message(message.chat.id, message.message_id)
- end
- return
-end
-
-return allowlist
\ No newline at end of file
diff --git a/plugins/administration/channel.lua b/plugins/administration/channel.lua
deleted file mode 100644
index aa726db..0000000
--- a/plugins/administration/channel.lua
+++ /dev/null
@@ -1,94 +0,0 @@
---[[
- Based on a plugin by topkecleon. Licensed under GNU AGPLv3
- https://github.com/topkecleon/otouto/blob/master/LICENSE.
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local channel = {}
-local mattata = require('mattata')
-local socket = require('socket')
-local json = require('dkjson')
-local redis = require('libs.redis')
-
-function channel:init()
- channel.commands = mattata.commands(self.info.username):command('channel'):command('ch'):command('msg').table
- channel.help = '/channel <channel> <message> - Sends a message to a Telegram channel/group. The channel/group can be specified via ID or username. Messages can be formatted with Markdown. Users can only send messages to channels/groups they own/administrate. Aliases: /ch, /msg.'
-end
-
-function channel:on_callback_query(callback_query, message, configuration, language)
- local request = redis:hget('temp:channel', callback_query.data)
- if not request then
- return false
- end
- request = json.decode(request)
- if request.from ~= callback_query.from.id then
- return mattata.answer_callback_query(callback_query.id, language['channel']['1'])
- elseif not mattata.is_group_admin(request.target, request.from) then
- return mattata.answer_callback_query(callback_query.id, language['channel']['2'])
- end
- local success = mattata.send_message(request.target, request.text, 'markdown')
- if not success then
- return mattata.edit_message_text(message.chat.id, message.message_id, language['channel']['3'])
- end
- redis:hdel('temp:channel', callback_query.data)
- return mattata.edit_message_text(message.chat.id, message.message_id, language['channel']['4'])
-end
-
-function channel:on_message(message, configuration, language)
- if message.chat.type == 'channel' then
- return false
- end
- local input = mattata.input(message)
- if not input then
- return mattata.send_reply(message, channel.help)
- end
- local target = mattata.get_word(input)
- if tonumber(target) == nil and not target:match('^@') then
- target = '@' .. target
- end
- target = mattata.get_chat_id(target) or target
- local admin_list = mattata.get_chat_administrators(target)
- if not admin_list and not mattata.is_global_admin(message.from.id) then
- return mattata.send_reply(message, language['channel']['5'])
- elseif not mattata.is_global_admin(message.from.id) then -- Make configured owners an exception.
- local is_admin = false
- for _, admin in ipairs(admin_list.result) do
- if admin.user.id == message.from.id then
- is_admin = true
- end
- end
- if not is_admin then
- return mattata.send_reply(message, language['channel']['6'])
- end
- end
- local text = input:match(' (.-)$')
- if not text then
- return mattata.send_reply(message, language['channel']['7'])
- end
- local request_id = tostring(socket.gettime()):gsub('%D', '')
- local keyboard = json.encode({
- ['inline_keyboard'] = {
- {
- {
- ['text'] = language['channel']['9'],
- ['callback_data'] = 'channel:' .. request_id
- }
- }
- }
- })
- local temp_text = '*' .. language['channel']['8'] .. '*\n\n' .. text
- local success = mattata.send_message(message.chat.id, temp_text, 'markdown', true, false, nil, keyboard)
- if not success then
- return mattata.send_reply(message, language['channel']['10'])
- end
- local payload = json.encode({
- ['target'] = target,
- ['text'] = text,
- ['from'] = message.from.id
- })
- redis:hset('temp:channel', request_id, payload)
- return success
-end
-
-return channel
\ No newline at end of file
diff --git a/plugins/administration/delete.lua b/plugins/administration/delete.lua
deleted file mode 100644
index 8e5ce31..0000000
--- a/plugins/administration/delete.lua
+++ /dev/null
@@ -1,61 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local delete = {}
-local mattata = require('mattata')
-
-function delete:init()
- delete.commands = mattata.commands(self.info.username):command('delete').table
- delete.help = '/delete [message ID] - Deletes the specified (or replied-to) message.'
-end
-
-function delete:on_message(message, configuration, language)
- if message.chat.type ~= 'supergroup'
- then
- return mattata.send_reply(
- message,
- language['errors']['supergroup']
- )
- elseif not mattata.is_group_admin(
- message.chat.id,
- message.from.id
- )
- then
- return mattata.send_reply(
- message,
- language['errors']['admin']
- )
- end
- local input = mattata.input(message.text)
- or (
- message.reply
- and message.reply.message_id
- )
- if not input
- or tonumber(input) == nil
- then
- return mattata.send_reply(
- message,
- delete.help
- )
- end
- local success = mattata.delete_message(
- message.chat.id,
- tonumber(input)
- )
- if not success
- then
- return mattata.send_reply(
- message,
- language['delete']['1']
- )
- end
- return mattata.delete_message(
- message.chat.id,
- message.message_id
- )
-end
-
-return delete
\ No newline at end of file
diff --git a/plugins/administration/delfed.lua b/plugins/administration/delfed.lua
deleted file mode 100644
index 6290152..0000000
--- a/plugins/administration/delfed.lua
+++ /dev/null
@@ -1,63 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local delfed = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function delfed:init()
- delfed.commands = mattata.commands(self.info.username):command('delfed').table
- delfed.help = '/delfed <fed UUID> - Allows the Fed creator to delete a Fed, specified by its UUID.'
-end
-
-function delfed:on_new_message(message)
- if message.chat.type == 'private' then
- return false
- end
- local feds = redis:smembers('chat:' .. message.chat.id .. ':feds')
- if #feds == 0 then
- return false
- end
- for _, fed in pairs(feds) do
- if not redis:hexists('fed:' .. fed, 'creator') then
- redis:srem('chat:' .. message.chat.id .. ':feds', fed)
- mattata.send_message(message.chat.id, 'The Fed this chat is part of has been deleted! To start a new one, use `/newfed <name>`.', true)
- end
- end
- return
-end
-
-function delfed:on_message(message, configuration, language)
- local input = mattata.input(message.text)
- if message.chat.type ~= 'supergroup' and not mattata.is_group_admin(message.chat.id, message.from.id) then
- return false
- elseif not input then
- return mattata.send_reply(message, 'You must specify the UUID of the Fed you\'d like to delete, in the format `/delfed <fed UUID>`!', true)
- elseif not input:match('^%w+%-%w+%-%w+%-%w+%-%w+$') then
- return mattata.send_reply(message, 'That\'s not a valid UUID!')
- end
- local creator = redis:hget('fed:' .. input, 'creator')
- if not creator then
- return mattata.send_reply(message, 'I couldn\'t find that Fed, perhaps it has already been deleted?')
- elseif creator ~= message.from.id then
- return mattata.send_reply(message, 'You must be the creator of the Fed in order to delete it!')
- end
- local title = redis:hget('fed:' .. input, 'title')
- redis:del('fedadmins:' .. input)
- redis:del('fedmembers:' .. input)
- redis:del('fed:' .. input)
- redis:srem('feds:' .. message.from.id, input)
- if message.chat.type ~= 'private' then
- local current = redis:sismember('chat:' .. message.chat.id .. ':feds', input)
- if current then
- redis:srem('chat:' .. message.chat.id .. ':feds', input)
- end
- end
- local output = 'Successfully deleted the Fed "<b>%s</b>" <code>%s</code>!'
- output = string.format(output, mattata.escape_html(title), input)
- return mattata.send_reply(message, output)
-end
-
-return delfed
\ No newline at end of file
diff --git a/plugins/administration/demote.lua b/plugins/administration/demote.lua
deleted file mode 100644
index 59e06fd..0000000
--- a/plugins/administration/demote.lua
+++ /dev/null
@@ -1,162 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local demote = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function demote:init()
- demote.commands = mattata.commands(self.info.username)
- :command('demote')
- :command('demod').table
- demote.help = '/demote [user] - Demotes a user to a standard user of the current chat. This command can only be used by administrators of a supergroup. Alias: /demod.'
-end
-
-function demote:on_message(message, configuration, language)
- if message.chat.type ~= 'supergroup'
- then
- return mattata.send_reply(
- message,
- language['errors']['supergroup']
- )
- elseif not mattata.is_group_admin(
- message.chat.id,
- message.from.id,
- true
- )
- then
- return mattata.send_reply(
- message,
- language['errors']['admin']
- )
- end
- local input = message.reply
- and tostring(message.reply.from.id)
- or mattata.input(message)
- if not input
- then
- local success = mattata.send_force_reply(
- message,
- language['demote']['1']
- )
- if success
- then
- redis:set(
- string.format(
- 'action:%s:%s',
- message.chat.id,
- success.result.message_id
- ),
- '/demote'
- )
- end
- return
- elseif tonumber(input) == nil
- and not input:match('^%@')
- then
- input = '@' .. input
- end
- local user = mattata.get_user(input)
- or mattata.get_chat(input) -- Resolve the username/ID to a user object.
- if not user
- then
- return mattata.send_reply(
- message,
- language['errors']['unknown']
- )
- elseif user.result.id == self.info.id
- then
- return
- end
- user = user.result
- local status = mattata.get_chat_member(
- message.chat.id,
- user.id
- )
- if not status
- then
- return mattata.send_reply(
- message,
- language['errors']['generic']
- )
- elseif not mattata.is_group_admin(
- message.chat.id,
- user.id
- )
- then -- We won't try and demote users who aren't moderators/administrators.
- return mattata.send_reply(
- message,
- language['demote']['2']
- )
- elseif status.result.status == 'left'
- or status.result.status == 'kicked'
- then -- Check if the user is in the group or not.
- return mattata.send_reply(
- message,
- string.format(
- status.result.status == 'left'
- and language['demote']['3']
- or language['demote']['4']
- )
- )
- end
- redis:srem(
- 'administration:' .. message.chat.id .. ':mods',
- user.id
- )
- if redis:hget(
- string.format(
- 'chat:%s:settings',
- message.chat.id
- ),
- 'log administrative actions'
- )
- then
- mattata.send_message(
- mattata.get_log_chat(message.chat.id),
- string.format(
- '<pre>%s%s [%s] has demoted %s%s [%s] in %s%s [%s].</pre>',
- message.from.username
- and '@'
- or '',
- message.from.username
- or mattata.escape_html(message.from.first_name),
- message.from.id,
- user.username
- and '@'
- or '',
- user.username
- or mattata.escape_html(user.first_name),
- user.id,
- message.chat.username
- and '@'
- or '',
- message.chat.username
- or mattata.escape_html(message.chat.title),
- message.chat.id
- ),
- 'html'
- )
- end
- return mattata.send_message(
- message.chat.id,
- string.format(
- '<pre>%s%s has demoted %s%s.</pre>',
- message.from.username
- and '@'
- or '',
- message.from.username
- or mattata.escape_html(message.from.first_name),
- user.username
- and '@'
- or '',
- user.username
- or mattata.escape_html(user.first_name)
- ),
- 'html'
- )
-end
-
-return demote
\ No newline at end of file
diff --git a/plugins/administration/fadmins.lua b/plugins/administration/fadmins.lua
deleted file mode 100644
index cc2269f..0000000
--- a/plugins/administration/fadmins.lua
+++ /dev/null
@@ -1,50 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local fadmins = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function fadmins:init()
- fadmins.commands = mattata.commands(self.info.username):command('fadmins'):command('fa').table
- fadmins.help = '/fadmins [Fed UUID] - View a list of users who are admins in your Fed. If you have multiple Feds, you will need to specify the Fed by its UUID. Alias: /fa.'
-end
-
-function fadmins.on_message(_, message)
- local input = mattata.input(message.text)
- input = (input and input:match('^%w+%-%w+%-%w+%-%w+%-%w+$')) and input or false
- local feds = redis:keys('fed:*')
- local owned = {}
- for _, fed in pairs(feds) do
- if mattata.is_fed_creator(fed:match('^fed:(.-)$'), message.from.id) then
- table.insert(owned, fed:match('^fed:(.-)$'))
- end
- end
- if input and mattata.table_contains(owned, input) then
- feds = redis:smembers('fedadmins:' .. input)
- elseif #owned == 0 then
- return mattata.send_reply(message, 'You don\'t own any Feds! To create your own, use /newfed <Fed name>.')
- elseif input then
- return mattata.send_reply(message, 'I\'m afraid it looks like you don\'t own that Fed, therefore you can\'t view the list of admins for it!')
- else
- if #owned > 1 then
- return mattata.send_reply(message, 'You own multiple Feds! You need to specify which Fed you want to view the admins for by using /fadmins <Fed UUID>. To view a list of Feds you own, use /myfeds.')
- end
- feds = redis:smembers('fedadmins:' .. owned[1])
- input = owned[1]
- end
- local title = redis:hget('fed:' .. input, 'title')
- local output = { 'The following users are admin in <b>' .. mattata.escape_html(title) .. '</b>:\n' }
- for _, admin in pairs(feds) do
- local user = mattata.get_user(admin).result
- local name = mattata.get_formatted_user(user.id, user.first_name, 'html')
- table.insert(output, mattata.symbols.bullet .. ' ' .. name .. ' <code>[' .. user.id .. ']</code>' )
- end
- table.insert(output, '\nTo promote more users, use <code>/fpromote [user] ' .. input .. '</code>')
- output = table.concat(output, '\n')
- return mattata.send_reply(message, output, 'html')
-end
-
-return fadmins
\ No newline at end of file
diff --git a/plugins/administration/fallowlist.lua b/plugins/administration/fallowlist.lua
deleted file mode 100644
index ae16c3c..0000000
--- a/plugins/administration/fallowlist.lua
+++ /dev/null
@@ -1,81 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local fallowlist = {}
-local mattata = require('mattata')
-
-function fallowlist:init()
- fallowlist.commands = mattata.commands(self.info.username):command('fallowlist'):command('fal').table
- fallowlist.help = '/fallowlist [user] - Allowlists a user from the current chat\'s Feds. Only works per chat, not per fed. This command can only be used by Fed admins. Alias: /fal.'
-end
-
-function fallowlist:on_message(message, configuration, language)
- if message.chat.type ~= 'supergroup' then
- local output = language['errors']['supergroup']
- return mattata.send_reply(message, output)
- end
- local fed_ids = mattata.get_feds(message.chat.id)
- if #fed_ids == 0 then
- return mattata.send_reply(message, 'This group isn\'t part of a fed. Ask a group admin to join one!')
- end
- local user = message.reply and message.reply.from.id or mattata.input(message.text)
- if not user then
- local output = 'You need to specify the user you\'d like to allowlist from the Fed, either by username/ID or in reply.'
- local success = mattata.send_force_reply(message, output)
- if success then
- mattata.set_command_action(message.chat.id, success.result.message_id, '/fallowlist')
- end
- return
- end
- if tonumber(user) == nil and not user:match('^%@') then
- user = '@' .. user
- end
- local user_object = mattata.get_user(user) -- resolve the username/ID to a user object
- if not user_object then
- local output = language['errors']['unknown']
- return mattata.send_reply(message, output)
- elseif user_object.result.id == self.info.id then
- return false -- don't let the bot Fed-allowlist itself
- end
- user_object = user_object.result
- local status = mattata.get_chat_member(message.chat.id, user_object.id)
- local is_admin = mattata.is_group_admin(message.chat.id, user_object.id)
- if not status then
- local output = language['errors']['generic']
- return mattata.send_reply(message, output)
- elseif is_admin or status.result.status == ('creator' or 'administrator') then -- we won't try and Fed-allowlist moderators and administrators.
- local output = 'I can\'t allowlist that user from the Fed because they\'re an admin in one of the groups!'
- return mattata.send_reply(message, output)
- end
- mattata.fed_allowlist(message.chat.id, user_object.id)
- if mattata.get_setting(message.chat.id, 'log administrative actions') then
- local log_chat = mattata.get_log_chat(message.chat.id)
- local admin_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
- local allowlisted_username = mattata.get_formatted_user(user_object.id, user_object.first_name, 'html')
- local output = '%s <code>[%s]</code> has Fed-allowlisted %s <code>[%s]</code> from %s <code>[%s]</code>.'
- if #fed_ids > 1 then
- output = '%s <code>[%s]</code> has Fed-allowlisted %s <code>[%s]</code> from %s in the following Feds:<pre>%s</pre>'
- output = string.format(output, admin_username, message.from.id, allowlisted_username, user_object.id, mattata.escape_html(message.chat.title), table.concat(fed_ids, '\n'))
- else
- output = string.format(output, admin_username, message.from.id, allowlisted_username, user_object.id, mattata.escape_html(message.chat.title), message.chat.id)
- end
- mattata.send_message(message.chat.id, output, 'html')
- end
- if message.reply and mattata.get_setting(message.chat.id, 'delete reply on action') then
- mattata.delete_message(message.chat.id, message.reply.message_id)
- end
- local admin_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
- local allowlisted_username = mattata.get_formatted_user(user_object.id, user_object.first_name, 'html')
- local output = '%s has Fed-allowlisted %s.'
- if #fed_ids > 1 then
- output = '%s has Fed-allowlisted %s; in the following Feds:<pre>%s</pre>'
- output = string.format(output, admin_username, allowlisted_username, table.concat(fed_ids, '\n'))
- else
- output = string.format(output, admin_username, allowlisted_username)
- end
- return mattata.send_message(message.chat.id, output, 'html')
-end
-
-return fallowlist
\ No newline at end of file
diff --git a/plugins/administration/fban.lua b/plugins/administration/fban.lua
deleted file mode 100644
index 10662a9..0000000
--- a/plugins/administration/fban.lua
+++ /dev/null
@@ -1,131 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local fban = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function fban:init()
- fban.commands = mattata.commands(self.info.username):command('fban'):command('fedban'):command('fb').table
- fban.help = '/fban [user] - Bans a user from the current chat and the Fed the group is part of. This command can only be used by Fed admins. Aliases: /fedban, /fb.'
-end
-
-function fban.on_new_message(_, message)
- if message.chat.type ~= 'supergroup' then
- return false
- elseif mattata.is_user_fedbanned(message.chat.id, message.from.id) and not mattata.is_user_fed_allowlisted(message.chat.id, message.from.id) then
- mattata.send_message(message.chat.id, 'Banned ' .. message.from.first_name .. ', because they\'ve been banned in one of this group\'s Feds!')
- return mattata.ban_chat_member(message.chat.id, message.from.id)
- end
- return false
-end
-
-function fban:on_message(message, _, language)
- if message.chat.type ~= 'supergroup' then
- local output = language['errors']['supergroup']
- return mattata.send_reply(message, output)
- end
- local fed_ids = mattata.get_feds(message.chat.id)
- if #fed_ids == 0 then
- return mattata.send_reply(message, 'This group isn\'t part of a fed. Ask a group admin to join one!')
- end
- local is_admin_feds = {}
- for _, fed in pairs(fed_ids) do
- if mattata.is_fed_admin(fed, message.from.id) then
- table.insert(is_admin_feds, fed)
- end
- end
- if #is_admin_feds == 0 then
- return mattata.send_reply(message, 'You need to be a Fed admin in at least one of this group\'s Feds in order to be able to use this command!')
- end
- local reason = false
- local user = false
- local input = mattata.input(message)
- -- check the message object for any users this command
- -- is intended to be executed on
- if message.reply then
- user = message.reply.from.id
- if input then
- reason = input
- end
- elseif input and input:match(' ') then
- user, reason = input:match('^(.-) (.-)$')
- elseif input then
- user = input
- end
- if not user then
- local output = 'You need to specify the user you\'d like to ban from the Fed, either by username/ID or in reply.'
- local success = mattata.send_force_reply(message, output)
- if success then
- mattata.set_command_action(message.chat.id, success.result.message_id, '/fban')
- end
- return
- end
- if reason and type(reason) == 'string' and reason:match('^[Ff][Oo][Rr] ') then
- reason = reason:match('^[Ff][Oo][Rr] (.-)$')
- end
- if tonumber(user) == nil and not user:match('^%@') then
- user = '@' .. user
- end
- local user_object = mattata.get_user(user) or mattata.get_chat(user) -- resolve the username/ID to a user object
- if not user_object then
- local output = language['errors']['unknown']
- return mattata.send_reply(message, output)
- elseif user_object.result.id == self.info.id then
- return false -- don't let the bot Fed-ban itself
- end
- user_object = user_object.result
- local status = mattata.get_chat_member(message.chat.id, user_object.id)
- local is_admin = mattata.is_group_admin(message.chat.id, user_object.id)
- if not status then
- local output = language['errors']['generic']
- return mattata.send_reply(message, output)
- elseif is_admin then -- we won't try and Fed-ban moderators and administrators.
- local output = 'I can\'t ban that user from the Fed because they\'re an admin in one of the groups!'
- return mattata.send_reply(message, output)
- end
- local success = mattata.fed_ban_chat_member(message.chat.id, user_object.id, is_admin_feds) -- attempt to Fed-ban the user from the group
- if not success then
- mattata.send_reply(message, 'I couldn\'t ban that user in this group, because it appears I don\'t have permission to! I have still added them to the Fed-ban list(s) though!')
- end
- for _, fed in pairs(is_admin_feds) do
- mattata.increase_administrative_action(message.chat.id, user_object.id, 'fbans')
- redis:hset('fedban:' .. fed .. ':' .. user_object.id, 'banned_by', message.from.id)
- redis:hset('fedban:' .. fed .. ':' .. user_object.id, 'time', os.time())
- if reason then
- redis:hset('fedban:' .. fed .. ':' .. user_object.id, 'reason', reason)
- end
- redis:sadd('fedbans:' .. fed, tonumber(user_object.id))
- end
- reason = reason and '\nReason: ' .. reason or ''
- local admin_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
- local banned_username = mattata.get_formatted_user(user_object.id, user_object.first_name, 'html')
- if mattata.get_setting(message.chat.id, 'log administrative actions') then
- local log_chat = mattata.get_log_chat(message.chat.id)
- local output = '%s <code>[%s]</code> has Fed-banned %s <code>[%s]</code> from %s <code>[%s]</code>%s.\n%s %s'
- if #is_admin_feds > 1 then
- output = '%s <code>[%s]</code> has Fed-banned %s <code>[%s]</code> from %s in the following Feds:<pre>%s</pre>\n%s %s'
- output = string.format(output, admin_username, message.from.id, banned_username, user_object.id, mattata.escape_html(message.chat.title), table.concat(is_admin_feds, '\n'), '#chat' .. tostring(message.chat.id):gsub('^-100', ''), '#user' .. user_object.id)
- else
- output = string.format(output, admin_username, message.from.id, banned_username, user_object.id, mattata.escape_html(message.chat.title), message.chat.id, reason, '#chat' .. tostring(message.chat.id):gsub('^-100', ''), '#user' .. user_object.id)
- end
- mattata.send_message(log_chat, output, 'html')
- else
- local output = '%s has Fed-banned %s%s.'
- if #is_admin_feds > 1 then
- output = '%s has Fed-banned %s%s; in the following Feds:<pre>%s</pre>'
- output = string.format(output, admin_username, banned_username, reason, table.concat(is_admin_feds, '\n'))
- else
- output = string.format(output, admin_username, banned_username, reason)
- end
- mattata.send_message(message.chat.id, output, 'html')
- end
- if message.reply and mattata.get_setting(message.chat.id, 'delete reply on action') then
- mattata.delete_message(message.chat.id, message.reply.message_id)
- end
- return mattata.delete_message(message.chat.id, message.message_id)
-end
-
-return fban
\ No newline at end of file
diff --git a/plugins/administration/fbaninfo.lua b/plugins/administration/fbaninfo.lua
deleted file mode 100644
index c0ac162..0000000
--- a/plugins/administration/fbaninfo.lua
+++ /dev/null
@@ -1,53 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local fbaninfo = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function fbaninfo:init()
- fbaninfo.commands = mattata.commands(self.info.username):command('fbaninfo'):command('fbi').table
- fbaninfo.help = '/fbaninfo [Fed UUID] - View information about the Feds you are banned from. When applicable, specify the UUID of a Fed to see your reason. Alias: /fbi.'
-end
-
-function fbaninfo.on_message(_, message)
- local input = mattata.input(message.text)
- input = (input and input:match('^%w+%-%w+%-%w+%-%w+%-%w+$')) and input or false
- if not input then
- local all = redis:keys('fedban:*:' .. message.from.id)
- if #all == 0 then
- return mattata.send_reply(message, 'Looks like you\'ve been good! You\'re not banned from any Feds at the moment.')
- end
- local feds = {}
- for _, fed in pairs(all) do
- fed = fed:match('^fedban:(.-):' .. message.from.id .. '$')
- local title = redis:hget('fed:' .. fed, 'title')
- fed = string.format(mattata.symbols.bullet .. ' ' .. mattata.escape_html(title) .. ' <code>[%s]</code>')
- table.insert(feds, fed)
- end
- feds = table.concat(feds, '\n')
- return mattata.send_reply(message, 'I\'m afraid some admins found your messages annoying and you\'ve been Fed-banned from the followings Feds:\n' .. feds, 'html')
- end
- if not redis:hexists('fed:' .. input, 'date_created') then
- return mattata.send_reply(message, 'It appears the UUID you\'ve specified doesn\'t match an existing Fed! Please check you spelled it correctly, then try again.')
- end
- local title = redis:hget('fed:' .. input, 'title')
- local reason = redis:hget('fedban:' .. input .. ':' .. message.from.id, 'reason')
- local banned_on = redis:hget('fedban:' .. input .. ':' .. message.from.id, 'time')
- if not reason then
- return mattata.send_reply(message, 'Phew! It looks like you\'re not banned from that Fed, at this moment in time!')
- end
- local info = {
- '<b>Fed:</b> <em>' .. mattata.escape_html(title) .. '</em>',
- '<b>Ban reason:</b> <em>' .. mattata.escape_html(reason) .. '</em>'
- }
- if banned_on then
- table.insert(info, '<b>Date of ban:</b> <em>' .. os.date('%x', tonumber(banned_on)) .. '</em>')
- end
- info = table.concat(info, '\n')
- return mattata.send_reply(message, info, 'html')
-end
-
-return fbaninfo
\ No newline at end of file
diff --git a/plugins/administration/fdemote.lua b/plugins/administration/fdemote.lua
deleted file mode 100644
index 42d8d65..0000000
--- a/plugins/administration/fdemote.lua
+++ /dev/null
@@ -1,52 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local fdemote = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function fdemote:init()
- fdemote.commands = mattata.commands(self.info.username):command('fdemote'):command('feddemote'):command('fd').table
- fdemote.help = '/fdemote [user] - Allows the Fed creator to demote a user (by reply or mention), removing their access to Fed admin commands. If you have multiple feds, please specify the Fed as a second parameter, if not it will pick your first one. Aliases: /feddemote, /fd.'
-end
-
-function fdemote:on_message(message, configuration, language)
- local fed, id = mattata.has_fed(message.from.id)
- local input = mattata.input(message.text)
- if message.reply and input then
- input = message.reply.from.id .. ' ' .. input
- end
- local input, selected = (message.reply and not input) and tostring(message.reply.from.id) or input, nil
- if input:match('^[@%w_]+ ([%w%-]+)$') then
- input, selected = input:match('^([@%w_]+) ([%w%-]+)$')
- end
- fed, id = mattata.has_fed(message.from.id, selected)
- if not fed then
- local output = 'You need to have your own Fed in order to use this command!'
- if selected then
- output = 'That\'s not one of your Feds!'
- end
- return mattata.send_reply(message, output)
- elseif not input then
- return mattata.send_reply(message, fdemote.help)
- end
- local user = mattata.get_user(input)
- if not user then
- return mattata.send_reply(message, 'I couldn\'t find any information about that user! Try sending this in reply to one of their messages.')
- elseif user.result.id == message.from.id then
- return mattata.send_reply(message, 'You can\'t demote yourself you donut!')
- elseif user.result.id == self.info.id then
- return mattata.send_reply(message, 'Why do you need to demote me? I control all of the Feds!')
- elseif not mattata.is_fed_admin(id, user.result.id) then
- return mattata.send_reply(message, 'That user isn\'t an admin in your Fed anyway!')
- end
- local title = redis:hget('fed:' .. id, 'title')
- redis:srem('fedadmins:' .. id, user.result.id)
- local output = 'Successfully demoted <b>%s</b> from Fed admin in <b>%s</b> <code>[%s]</code>!'
- output = string.format(output, mattata.escape_html(user.result.first_name), mattata.escape_html(title), id)
- return mattata.send_reply(message, output, 'html')
-end
-
-return fdemote
\ No newline at end of file
diff --git a/plugins/administration/feds.lua b/plugins/administration/feds.lua
deleted file mode 100644
index 47ec0d6..0000000
--- a/plugins/administration/feds.lua
+++ /dev/null
@@ -1,38 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local feds = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function feds:init()
- feds.commands = mattata.commands(self.info.username):command('feds').table
- feds.help = '/feds - Allows group admins to view the group\'s current Feds.'
-end
-
-function feds:on_message(message, configuration, language)
- if message.chat.type == 'private' then
- return mattata.send_reply(message, language.errors.supergroup)
- elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
- return mattata.send_reply(message, language.errors.admin)
- end
- local all = redis:smembers('chat:' .. message.chat.id .. ':feds')
- if #all == 0 then
- local output = '<b>%s</b> isn\'t part of any Feds! To join one, use <code>/joinfed &lt;fed UUID&gt;</code>!'
- output = string.format(output, mattata.escape_html(message.chat.title))
- return mattata.send_reply(message, output, 'html')
- end
- local output = { '<b>' .. mattata.escape_html(message.chat.title) .. '</b> is part of the following Feds:' }
- for _, fed in pairs(all) do
- local formatted = mattata.symbols.bullet .. ' <em>%s</em> <code>[%s]</code>'
- local title = redis:hget('fed:' .. fed, 'title')
- formatted = string.format(formatted, mattata.escape_html(title), fed)
- table.insert(output, formatted)
- end
- output = table.concat(output, '\n')
- return mattata.send_reply(message, output, 'html')
-end
-
-return feds
\ No newline at end of file
diff --git a/plugins/administration/filter.lua b/plugins/administration/filter.lua
deleted file mode 100644
index 1ca3ddf..0000000
--- a/plugins/administration/filter.lua
+++ /dev/null
@@ -1,87 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local filter = {}
-local mattata = require('mattata')
-local json = require('dkjson')
-local redis = require('libs.redis')
-
-function filter:init()
- filter.commands = mattata.commands(self.info.username):command('filter').table
- filter.help = '/filter <words> - Add to the list of words that users will be kicked upon for saying. This feature requires the bot to have administrative permissions. The kick will only be a soft-ban (meaning the targeted user is able to return to the chat immediately), unless the "Ban Not Kick" setting is enabled in the /administration menu.'
-end
-
-function filter:on_message(message, configuration, language)
- if message.chat.type ~= 'supergroup'
- then
- return mattata.send_reply(
- message,
- language['errors']['supergroup']
- )
- elseif not mattata.is_group_admin(
- message.chat.id,
- message.from.id
- )
- then
- return mattata.send_reply(
- message,
- language['errors']['admin']
- )
- end
- local input = mattata.input(message.text)
- if not input
- or not input:match('%w+')
- then
- return mattata.send_reply(
- message,
- filter.help
- )
- end
- local new_total = 0
- local words = {}
- for word in input:gmatch('%w+')
- do
- table.insert(
- words,
- word
- )
- end
- local total = redis:smembers('word_filter:' .. message.chat.id)
- if #total + #words >= 200
- then
- local remaining = 200 - #total
- return mattata.send_reply(
- message,
- 'You may only have 200 words filtered at a time. There are currently ' .. tostring(#total) .. ' word(s) filtered in this chat, so you may only add up to ' .. tostring(remaining) .. ' more.'
- )
- end
- local new = {}
- for n, word in pairs(words)
- do
- if not redis:sismember(
- 'word_filter:' .. message.chat.id,
- word
- )
- then
- local success = redis:sadd(
- 'word_filter:' .. message.chat.id,
- word
- )
- if success
- then
- table.insert(
- new,
- word
- )
- end
- end
- end
- return mattata.send_message(
- message.chat.id,
- tostring(#new) .. ' word(s) have been added to this chat\'s word filter. Use /unfilter <words> to remove words from this filter.'
- )
-end
-
-return filter
\ No newline at end of file
diff --git a/plugins/administration/fpromote.lua b/plugins/administration/fpromote.lua
deleted file mode 100644
index 83aff0a..0000000
--- a/plugins/administration/fpromote.lua
+++ /dev/null
@@ -1,58 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local fpromote = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function fpromote:init()
- fpromote.commands = mattata.commands(self.info.username):command('fpromote'):command('fedpromote'):command('fp').table
- fpromote.help = '/fpromote [user] [fed UUID] - Allows the Fed creator to promote a user (by reply or mention), granting them access to Fed admin commands. If you have multiple feds, please specify the Fed as a second parameter. Aliases: /fedpromote, /fp.'
-end
-
-function fpromote:on_message(message)
- local fed, id, multiple = mattata.has_fed(message.from.id)
- local input = mattata.input(message.text)
- local selected
- if message.reply and input then
- input = message.reply.from.id .. ' ' .. input
- end
- input, selected = (message.reply and not input) and tostring(message.reply.from.id) or input, nil
- if input and input:match('^[@%w_]+ ([%w%-]+)$') then
- input, selected = input:match('^([@%w_]+) ([%w%-]+)$')
- elseif not input then
- return mattata.send_reply(message, fpromote.help)
- end
- if not selected and multiple then
- return mattata.send_reply(message, 'Since this group is part of multiple Feds, you need to specify the Fed UUID at the end of your message (i.e. /fpromote @wrxck your-uuid-here). To view Fed UUIDs, send /feds.')
- end
- fed, id = mattata.has_fed(message.from.id, selected)
- if not fed then
- local output = 'You need to have your own Fed in order to use this command!'
- if selected then
- output = 'That\'s not one of your Feds!'
- end
- return mattata.send_reply(message, output)
- elseif not input then
- return mattata.send_reply(message, fpromote.help)
- end
- local user = mattata.get_user(input)
- if not user then
- return mattata.send_reply(message, 'I couldn\'t find any information about that user! Try sending this in reply to one of their messages.')
- elseif user.result.id == message.from.id then
- return mattata.send_reply(message, 'You can\'t promote yourself you donut!')
- elseif user.result.id == self.info.id then
- return mattata.send_reply(message, 'Why do you need to promote me? I control all of the Feds!')
- elseif mattata.is_fed_admin(id, user.result.id) then
- return mattata.send_reply(message, 'That user is already an admin in your Fed!')
- end
- local title = redis:hget('fed:' .. id, 'title')
- redis:sadd('fedadmins:' .. id, user.result.id)
- local output = 'Successfully promoted <b>%s</b> to Fed admin in <b>%s</b> <code>[%s]</code>!'
- output = string.format(output, mattata.escape_html(user.result.first_name), mattata.escape_html(title), id)
- return mattata.send_reply(message, output, 'html')
-end
-
-return fpromote
\ No newline at end of file
diff --git a/plugins/administration/groups.lua b/plugins/administration/groups.lua
deleted file mode 100644
index 90229c0..0000000
--- a/plugins/administration/groups.lua
+++ /dev/null
@@ -1,54 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local groups = {}
-local mattata = require('mattata')
-local json = require('dkjson')
-local redis = require('libs.redis')
-
-function groups:init()
- groups.commands = mattata.commands(self.info.username):command('groups').table
- groups.help = '/groups [query] - View a list of mattata\'s groups (that is, all of the ones added by the bot owner), or search for groups by passing a Lua pattern as a command argument.'
-end
-
-function groups:on_message(message, configuration, language)
- local input = mattata.input(message.text)
- local output = {}
- for title, link in pairs(configuration.groups) do
- if input then
- local validate = pcall(
- function()
- return title:lower():match(input:lower())
- end
- )
- if not validate then
- local output = 'Your search query contains a malformed Lua pattern! If you\'re not sure what this means, try searching without any symbols.'
- return mattata.send_reply(message, output)
- end
- end
- if (input and title:lower():match(input:lower())) or not input then
- local result = string.format('• <a href="%s">%s</a>', mattata.escape_html(link), mattata.escape_html(title))
- table.insert(output, result)
- end
- end
- if not next(output) then
- local output = 'No groups were found. If you\'d like your group to appear here, contact @wrxck.'
- if input then
- output = string.format('No groups were found matching "%s"! Use /groups to view a complete list of available groups.', input)
- end
- return mattata.send_reply(message, output)
- end
- if configuration.sort_groups then
- table.sort(output)
- end
- output = table.concat(output, '\n')
- if input then
- local heading = string.format('Groups found matching "%s":\n', mattata.escape_html(input))
- output = heading .. output
- end
- return mattata.send_message(message.chat.id, output, 'html')
-end
-
-return groups
\ No newline at end of file
diff --git a/plugins/administration/import.lua b/plugins/administration/import.lua
deleted file mode 100644
index d4ba23b..0000000
--- a/plugins/administration/import.lua
+++ /dev/null
@@ -1,53 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local import = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function import:init()
- import.commands = mattata.commands(self.info.username):command('import').table
- import.help = '/import - Import administrative settings & toggled plugins from another mattata-administrated group.'
-end
-
-function import.on_message(_, message, _, language)
- if message.chat.type ~= 'supergroup' then
- return mattata.send_reply(message, language.errors.supergroup)
- elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
- return mattata.send_reply(message, language.errors.admin)
- end
- local input = mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, import.help)
- end
- input = mattata.get_chat(input)
- if not input then
- return mattata.send_reply(message, language['import']['1'])
- elseif input.result.type ~= 'supergroup' then
- return mattata.send_reply(message, language['import']['2'])
- end
- local current = redis:hgetall('chat:' .. message.chat.id .. ':settings')
- local settings = redis:hgetall('chat:' .. input.result.id .. ':settings')
- for k, _ in pairs(current) do
- if k ~= 'use administration' then
- redis:hdel('chat:' .. message.chat.id .. ':settings', k)
- end
- end
- for k, v in pairs(settings) do
- redis:hset('chat:' .. message.chat.id .. ':settings', k, v)
- end
- current = redis:smembers('disabled_plugins:' .. message.chat.id)
- local plugins = redis:smembers('disabled_plugins:' .. input.result.id)
- for _, v in pairs(current) do
- redis:srem('disabled_plugins:' .. message.chat.id, v)
- end
- for _, v in pairs(plugins) do
- redis:sadd('disabled_plugins:' .. message.chat.id, v)
- end
- local output = string.format(language['import']['3'], input.result.title, message.chat.title)
- return mattata.send_message(message.chat.id, output)
-end
-
-return import
\ No newline at end of file
diff --git a/plugins/administration/join_captcha.lua b/plugins/administration/join_captcha.lua
deleted file mode 100644
index b62a356..0000000
--- a/plugins/administration/join_captcha.lua
+++ /dev/null
@@ -1,160 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local join_captcha = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-local captcha_lib = require('captcha')
-
-function join_captcha.cron(_, configuration)
- local keys = redis:keys('chat:*:captcha:*')
- for _, key in pairs(keys) do
- local chat_id, user_id = key:match('^chat:(%-?%d+):captcha:(%d+)$')
- if not redis:get('captcha:' .. chat_id .. ':' .. user_id) then
- local message_id = redis:hget(key, 'id')
- mattata.delete_message(chat_id, message_id)
- local user = mattata.get_user(user_id, nil, nil, true)
- local kicked_user = mattata.get_formatted_user(user_id, user.result.first_name, 'html')
- local action = mattata.get_setting(chat_id, 'ban not kick')
- local punishment = action and 'Banned' or 'Kicked'
- local timeout = mattata.get_setting(chat_id, 'captcha timeout') or configuration.administration.captcha.timeout.default
- timeout = math.floor(timeout)
- if punishment == 'Banned' then
- action = mattata.ban_chat_member
- else action = mattata.kick_chat_member end
- local success = action(chat_id, user_id)
- if not success then
- mattata.wipe_redis_captcha(chat_id, user_id)
- else
- local output = punishment .. ' ' .. kicked_user .. ' <code>[' .. user_id .. ']</code> %sbecause they didn\'t complete the CAPTCHA within %s minutes!'
- if mattata.get_setting(chat_id, 'log administrative actions') then
- local chat = mattata.get_chat(chat_id)
- local log_output = output
- if chat then
- local title = mattata.escape_html(chat.result.title)
- title = 'from ' .. title .. ' <code>[' .. chat.result.id .. ']</code> '
- log_output = string.format(log_output, title, timeout)
- log_output = log_output .. '\n#chat' .. tostring(chat.result.id):gsub('^%-100', '') .. ' #user' .. user_id
- else
- log_output = string.format(log_output, '')
- end
- mattata.send_message(mattata.get_log_chat(chat_id), log_output, 'html')
- else
- output = string.format(output, '', timeout)
- mattata.send_message(chat_id, output, 'html')
- end
- mattata.wipe_redis_captcha(chat_id, user_id)
- end
- end
- end
-end
-
-function join_captcha.on_callback_query(_, callback_query, message)
- if not callback_query.data:match('^.-:.-:.-$') then
- return false
- end
- local chat_id, user_id, guess = callback_query.data:match('^(.-):(.-):(.-)$')
- if callback_query.from.id ~= tonumber(user_id) then
- return mattata.answer_callback_query(callback_query.id, 'This isn\'t your CAPTCHA!')
- end
- local correct = mattata.get_captcha_text(chat_id, callback_query.from.id)
- if not correct then
- return mattata.answer_callback_query(callback_query.id, 'An error occurred. Please contact an admin if this keeps happening!', true)
- end
- local message_id = mattata.get_captcha_id(chat_id, callback_query.from.id)
- local default_permissions = mattata.get_chat(message.chat.id, true)
- if guess:lower() == correct:lower() then
- local success
- if not default_permissions then
- success = mattata.restrict_chat_member(chat_id, callback_query.from.id, 'forever', true, true, true, true, true, false, false, false)
- else
- success = mattata.restrict_chat_member(chat_id, callback_query.from.id, 'forever', default_permissions.result.permissions)
- end
- if not success then
- return mattata.send_message(message.chat.id, 'I could not give a user their permissions. You may have to do this manually!')
- end
- mattata.wipe_redis_captcha(chat_id, callback_query.from.id)
- mattata.answer_callback_query(callback_query.id, 'Success! You may now speak!')
- return mattata.delete_message(chat_id, message_id)
- else
- if mattata.get_setting(chat_id, 'log administrative actions') then
- local failed_username = mattata.get_formatted_user(callback_query.from.id, callback_query.from.first_name, 'html')
- local chat_title = mattata.escape_html(message.chat.title)
- local output = '%s <code>[%s]</code> failed the CAPTCHA in %s <code>[%s]</code>. They guessed <code>%s</code> but the correct answer was <code>%s</code>.\n#chat%s #user%s'
- output = string.format(output, failed_username, user_id, chat_title, chat_id, guess, correct, tostring(chat_id):gsub('^%-100', ''), user_id)
- local log_chat = mattata.get_log_chat(chat_id)
- mattata.send_message(log_chat, output, 'html')
- end
- mattata.wipe_redis_captcha(chat_id, callback_query.from.id)
- mattata.answer_callback_query(callback_query.id, 'You got it wrong! Re-join the group and try again, or consult an admin if you wish to be unmuted!')
- return mattata.delete_message(chat_id, message_id)
- end
-end
-
-function join_captcha.on_member_join(_, message, configuration)
- if not mattata.get_setting(message.chat.id, 'require captcha') or message.new_chat_participant.is_bot then
- return false
- elseif mattata.get_captcha_id(message.chat.id, message.new_chat_participant.id) then
- return mattata.send_reply(message, 'You still need to complete your CAPTCHA in order to speak!')
- end
- local chat_member = mattata.get_chat_member(message.chat.id, message.new_chat_participant.id)
- if not chat_member then -- we can't even get info about the user? abort! abort!
- return false
- end
- local download_location = configuration.download_location
- if download_location:match('/$') then
- download_location = download_location:match('^(.-)/$')
- end
- local new_captcha = captcha_lib.new()
- local size = mattata.get_setting(message.chat.id, 'captcha size') or configuration.administration.captcha.size.default
- size = math.floor(size)
- local length = mattata.get_setting(message.chat.id, 'captcha length') or configuration.administration.captcha.length.default
- length = math.floor(length)
- local captchas = configuration.administration.captcha.files
- local current = mattata.get_setting(message.chat.id, 'captcha font') or 1
- current = math.floor(current)
- local font = captchas[current] or captchas[1]
- local timeout = mattata.get_setting(message.chat.id, 'captcha timeout') or configuration.administration.captcha.timeout.default
- new_captcha:setlength(length)
- new_captcha:setfontsize(size)
- new_captcha:setpath(download_location)
- new_captcha:setformat('jpg')
- new_captcha:setfontsfolder(configuration.fonts_directory .. '/' .. font)
- local generated_captcha, correct = new_captcha:generate()
- local username = mattata.get_formatted_user(message.new_chat_participant.id, message.new_chat_participant.first_name)
- local msg = string.format('Hey, %s! Please enter the above CAPTCHA using the buttons below before you can speak! You will be removed in 5 minutes if you don\'t do this.\n_Click to expand the image on Android devices!_', username)
- captchas = mattata.random_string(length, 5)
- table.insert(captchas, correct)
- table.sort(captchas)
- local callback_data = string.format('join_captcha:%s:%s', message.chat.id, message.new_chat_participant.id)
- local keyboard = mattata.inline_keyboard():row(
- mattata.row()
- :callback_data_button(captchas[1], callback_data .. ':' .. captchas[1])
- :callback_data_button(captchas[2], callback_data .. ':' .. captchas[2])
- :callback_data_button(captchas[3], callback_data .. ':' .. captchas[3])
- ):row(
- mattata.row()
- :callback_data_button(captchas[4], callback_data .. ':' .. captchas[4])
- :callback_data_button(captchas[5], callback_data .. ':' .. captchas[5])
- :callback_data_button(captchas[6], callback_data .. ':' .. captchas[6])
- )
- local success = mattata.send_photo(message.chat.id, generated_captcha, msg, 'markdown', false, nil, keyboard)
- if not success then
- error('No success!')
- os.execute('rm ' .. generated_captcha)
- return false
- end
- os.execute('rm ' .. generated_captcha)
- local restrict = mattata.restrict_chat_member(message.chat.id, message.new_chat_participant.id, 'forever', false, false, false, false, false, false, false, false)
- if restrict then
- mattata.set_captcha(message.chat.id, message.new_chat_participant.id, correct, success.result.message_id, math.floor(timeout * 60))
- mattata.delete_message(message.chat.id, message.message_id)
- else
- error('Could not restrict ChatMember!')
- end
- return
-end
-
-return join_captcha
\ No newline at end of file
diff --git a/plugins/administration/joinfed.lua b/plugins/administration/joinfed.lua
deleted file mode 100644
index 336da97..0000000
--- a/plugins/administration/joinfed.lua
+++ /dev/null
@@ -1,53 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local joinfed = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function joinfed:init(configuration)
- joinfed.commands = mattata.commands(self.info.username):command('joinfed').table
- joinfed.help = '/joinfed <fed UUID> - Allows a group admin to join the current group to the specified Fed.'
- joinfed.limit = configuration.administration.feds.group_limit
- joinfed.groups = configuration.administration.feds.shortened_feds
-end
-
-function joinfed:on_message(message, configuration, language)
- if message.chat.type == 'private' then
- return mattata.send_reply(message, 'Please use this command in the group you would like to join to the Fed!')
- elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
- return mattata.send_reply(message, language.errors.admin)
- end
- local input = mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, 'Please specify the fed\'s UUID!')
- end
- for name, fed in pairs(joinfed.groups) do
- if input:lower() == name then
- input = fed
- end
- end
- if not input:match('^%w+%-%w+%-%w+%-%w+%-%w+$') then
- return mattata.send_reply(message, 'That\'s an invalid UUID format')
- end
- local feds = redis:smembers('chat:' .. message.chat.id .. ':feds')
- if redis:sismember('chat:' .. message.chat.id .. ':feds', input) then
- return mattata.send_reply(message, 'This group is already part of that Fed!')
- elseif #feds >= joinfed.limit then
- return mattata.send_reply(message, 'You can only join a maximum of ' .. joinfed.limit .. ' Feds per group!')
- end
- local fed_title = redis:hget('fed:' .. input, 'title')
- if not fed_title then
- return mattata.send_reply(message, 'The Fed you specified doesn\'t exist!')
- end
- local output = 'Joined the Fed <b>%s</b> in this group <code>[%s]</code>!'
- redis:sadd('chat:' .. message.chat.id .. ':feds', input)
- redis:sadd('fedmembers:' .. input, message.chat.id)
- fed_title = mattata.escape_html(fed_title)
- output = string.format(output, fed_title, message.chat.id)
- return mattata.send_reply(message, output, 'html')
-end
-
-return joinfed
\ No newline at end of file
diff --git a/plugins/administration/jsondump.lua b/plugins/administration/jsondump.lua
deleted file mode 100644
index 5567ffb..0000000
--- a/plugins/administration/jsondump.lua
+++ /dev/null
@@ -1,41 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local jsondump = {}
-local mattata = require('mattata')
-local json = require('serpent')
-
-function jsondump:init()
- jsondump.commands = mattata.commands(self.info.username)
- :command('jsondump')
- :command('json').table
- jsondump.help = '/jsondump - Returns the raw JSON of your message. Alias: /json.'
- json = require('dkjson')
- jsondump.serialise = function(input)
- return json.encode(
- input,
- {
- indent = true
- }
- )
- end
-end
-
-function jsondump:on_message(message)
- local output = jsondump.serialise(message)
- if output:len() > 4096
- then
- return
- end
- return mattata.send_message(
- message.chat.id,
- '<pre>' .. mattata.escape_html(
- tostring(output)
- ) .. '</pre>',
- 'html'
- )
-end
-
-return jsondump
\ No newline at end of file
diff --git a/plugins/administration/kick.lua b/plugins/administration/kick.lua
deleted file mode 100644
index 791018d..0000000
--- a/plugins/administration/kick.lua
+++ /dev/null
@@ -1,95 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local kick = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function kick:init()
- kick.commands = mattata.commands(self.info.username):command('kick').table
- kick.help = '/kick [user] - Kicks a user from the current chat. This command can only be used by moderators and administrators of a supergroup.'
-end
-
-function kick:on_message(message, _, language)
- if message.chat.type ~= 'supergroup' then
- mattata.send_reply(message, language['errors']['supergroup'])
- return false, 'The chat is not a supergroup!'
- elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
- mattata.send_reply(message, language['errors']['admin'])
- return false, 'That user is not an admin/mod in this chat!'
- end
- local reason = false
- local user = false
- local input = mattata.input(message)
- -- Check the message object for any users this command
- -- is intended to be executed on.
- if message.reply then
- user = message.reply.from.id
- reason = input
- elseif input and input:match(' ') then
- user, reason = input:match('^(.-) (.-)$')
- elseif input then
- user = input
- end
- if not user then
- local success = mattata.send_force_reply(message, language['kick']['1'])
- if success then
- redis:set('action:' .. message.chat.id .. ':' .. success.result.message_id, '/kick')
- end
- return
- end
- if reason and type(reason) == 'string' and reason:match('^[Ff][Oo][Rr] ') then
- reason = reason:match('^[Ff][Oo][Rr] (.-)$')
- end
- if tonumber(user) == nil and not user:match('^%@') then
- user = '@' .. user
- end
- local user_object = mattata.get_user(user) -- Resolve the username/ID to a user object.
- if not user_object then
- mattata.send_reply(message, language['errors']['unknown'])
- return false, 'No user object was found!'
- elseif user_object.result.id == self.info.id then
- return false, 'The user given was the bot!'
- end
- user_object = user_object.result
- local status, error_message = mattata.get_chat_member(message.chat.id, user_object.id)
- if not status then
- mattata.send_reply(message, language['errors']['generic'])
- return false, error_message
- elseif mattata.is_group_admin(message.chat.id, user_object.id) then
- -- We won't try and kick moderators and administrators.
- mattata.send_reply(message, language['kick']['2'])
- return false, 'That user is an admin/mod in this chat!'
- elseif status.result.status == 'left' or status.result.status == 'kicked' then -- Check if the user is in the group or not.
- local output = status.result.status == 'left' and language['kick']['3'] or language['kick']['4']
- mattata.send_reply(message, output)
- return false, output
- end
- local success = mattata.kick_chat_member(message.chat.id, user_object.id) -- Attempt to kick the user from the group.
- if not success then -- Since we've ruled everything else out, it's safe to say if it wasn't a success
- -- then the bot isn't an administrator in the group.
- return mattata.send_reply(message, language['kick']['5'])
- end
- mattata.increase_administrative_action(message.chat.id, user_object.id, 'kicks')
- reason = reason and '\nReason: ' .. reason or ''
- local admin_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
- local kicked_username = mattata.get_formatted_user(user_object.id, user_object.first_name, 'html')
- if mattata.get_setting(message.chat.id, 'log administrative actions') then
- local log_chat = mattata.get_log_chat(message.chat.id)
- local output = '%s <code>[%s]</code> has kicked %s <code>[%s]</code> from %s <code>[%s]</code>%s.\n%s %s'
- output = string.format(output, admin_username, message.from.id, kicked_username, user_object.id, mattata.escape_html(message.chat.title), message.chat.id, reason, '#chat' .. tostring(message.chat.id):gsub('^-100', ''), '#user' .. user_object.id)
- mattata.send_message(log_chat, output, 'html')
- else
- local output = '%s has kicked %s%s.'
- output = string.format(output, admin_username, kicked_username, reason)
- mattata.send_message(message.chat.id, output, 'html')
- end
- if message.reply and mattata.get_setting(message.chat.id, 'delete reply on action') then
- mattata.delete_message(message.chat.id, message.reply.message_id)
- end
- return mattata.delete_message(message.chat.id, message.message_id)
-end
-
-return kick
\ No newline at end of file
diff --git a/plugins/administration/leavefed.lua b/plugins/administration/leavefed.lua
deleted file mode 100644
index 99b2a5f..0000000
--- a/plugins/administration/leavefed.lua
+++ /dev/null
@@ -1,45 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local leavefed = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function leavefed:init()
- leavefed.commands = mattata.commands(self.info.username):command('leavefed').table
- leavefed.help = '/leavefed <fed UUID> - Allows the group creator to leave one of the group\'s current Feds.'
-end
-
-function leavefed:on_message(message, configuration, language)
- local input = mattata.input(message.text)
- if message.chat.type ~= 'supergroup' then
- return mattata.send_reply(message, language.errors.supergroup)
- elseif not mattata.is_user_group_creator(message.chat.id, message.from.id) then
- return mattata.send_reply(message, 'Only the group creator can use this command!')
- end
- local feds = redis:smembers('chat:' .. message.chat.id .. ':feds')
- if #feds > 1 and not input then
- return mattata.send_reply(message, 'You must specify the Fed you\'d like to leave, by it\'s UUID!')
- elseif #feds == 0 then
- return mattata.send_reply(message, 'This group isn\'t part of any Feds!')
- end
- local is_member = false
- for _, fed in pairs(feds) do
- if fed == input then
- is_member = true
- end
- end
- if not is_member then
- return mattata.send_reply(message, 'This group isn\'t part of that Fed!')
- end
- redis:srem('chat:' .. message.chat.id .. ':feds', input)
- redis:srem('fedmembers:' .. input, message.chat.id)
- local title = redis:hget('fed:' .. input, 'title')
- local output = 'Successfully left the Fed "<b>%s</b>" <code>[%s]</code>! To join a new Fed, use <code>/joinfed &lt;fed UUID&gt;</code>, or to create a new Fed, use <code>/newfed &lt;fed name&gt;</code>!'
- output = string.format(output, mattata.escape_html(title), input)
- return mattata.send_reply(message, output, 'html')
-end
-
-return leavefed
\ No newline at end of file
diff --git a/plugins/administration/link.lua b/plugins/administration/link.lua
deleted file mode 100644
index f4d7cf1..0000000
--- a/plugins/administration/link.lua
+++ /dev/null
@@ -1,35 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local link = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function link:init()
- link.commands = mattata.commands(self.info.username):command('link').table
- link.help = '/link - Returns the chat\'s invite link.'
-end
-
-function link.on_message(_, message, _, language)
- if message.chat.type == 'private' then
- return mattata.send_reply(message, language.errors.supergroup)
- end
- local success = message.chat.username and {
- ['result'] = 'https://t.me/' .. message.chat.username:lower()
- } or redis:get('chat:' .. message.chat.id .. ':link') or mattata.export_chat_invite_link(message.chat.id)
- if not success then
- return mattata.send_reply(message, 'I need to be an administrator of this chat in order to retrieve the invite link.')
- elseif type(success) ~= 'table' then
- success = {
- ['result'] = success
- }
- end
- redis:set('chat:' .. message.chat.id .. ':link', success.result)
- redis:expire('chat:' .. message.chat.id .. ':link', 86400)
- success = string.format('<a href="%s">%s</a>', success.result, mattata.escape_html(message.chat.title))
- return mattata.send_message(message.chat.id, success, 'html')
-end
-
-return link
\ No newline at end of file
diff --git a/plugins/administration/logchat.lua b/plugins/administration/logchat.lua
deleted file mode 100644
index f59acae..0000000
--- a/plugins/administration/logchat.lua
+++ /dev/null
@@ -1,135 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local logchat = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function logchat:init()
- logchat.commands = mattata.commands(self.info.username):command('logchat').table
- logchat.help = '/logchat [chat] - Specify the chat that you wish to log all of this chat\'s administrative actions into.'
-end
-
-function logchat:on_message(message, configuration, language)
- if message.chat.type ~= 'supergroup'
- then
- return mattata.send_reply(
- message,
- language['errors']['supergroup']
- )
- elseif not mattata.is_group_admin(
- message.chat.id,
- message.from.id
- )
- then
- return mattata.send_reply(
- message,
- language['errors']['admin']
- )
- end
- local input = mattata.input(message.text)
- if not input
- then
- local success = mattata.send_force_reply(
- message,
- language['logchat']['1']
- )
- if success
- then
- redis:set(
- string.format(
- 'action:%s:%s',
- message.chat.id,
- success.result.message_id
- ),
- '/logchat'
- )
- end
- return
- end
- local res = mattata.send_message(
- message.chat.id,
- language['logchat']['2']
- )
- if not res
- then
- return
- elseif tonumber(input) == nil
- and not input:match('^@')
- then
- input = '@' .. input
- end
- local valid = mattata.get_chat(input)
- or mattata.get_user(input)
- if not valid
- or not valid.result
- then
- return mattata.edit_message_text(
- message.chat.id,
- res.result.message_id,
- language['logchat']['3']
- )
- elseif valid.result.type == 'private'
- then
- return mattata.edit_message_text(
- message.chat.id,
- res.result.message_id,
- language['logchat']['4']
- )
- elseif not mattata.is_group_admin(
- valid.result.id,
- message.from.id
- )
- then
- return mattata.edit_message_text(
- message.chat.id,
- res.result.message_id,
- language['logchat']['5']
- )
- elseif redis:hget(
- 'chat:' .. message.chat.id .. ':settings',
- 'log chat'
- )
- and redis:hget(
- 'chat:' .. message.chat.id .. ':settings',
- 'log chat'
- ) == valid.result.id
- then
- return mattata.edit_message_text(
- message.chat.id,
- res.result.message_id,
- language['logchat']['6']
- )
- end
- mattata.edit_message_text(
- message.chat.id,
- res.result.message_id,
- language['logchat']['7']
- )
- local permission = mattata.send_message(valid.result.id, language['logchat']['8'])
- if not permission then
- return mattata.edit_message_text(
- message.chat.id,
- res.result.message_id,
- 'It appears I don\'t have permission to post to that chat. Please ensure it\'s still a valid chat and that I have administrative rights!'
- )
- end
- mattata.delete_message(valid.result.id, permission.result.message_id)
- redis:hset(
- 'chat:' .. message.chat.id .. ':settings',
- 'log chat',
- valid.result.id
- )
- return mattata.edit_message_text(
- message.chat.id,
- res.result.message_id,
- string.format(
- language['logchat']['9'],
- input
- )
- )
-end
-
-return logchat
\ No newline at end of file
diff --git a/plugins/administration/mute.lua b/plugins/administration/mute.lua
deleted file mode 100644
index b1706c5..0000000
--- a/plugins/administration/mute.lua
+++ /dev/null
@@ -1,92 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local mute = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function mute:init()
- mute.commands = mattata.commands(self.info.username):command('mute').table
- mute.help = '/mute [user] - Mutes a user in the current chat. This command can only be used by group admins.'
-end
-
-function mute:on_message(message, _, language)
- if message.chat.type ~= 'supergroup' then
- local output = language['errors']['supergroup']
- return mattata.send_reply(message, output)
- end
- local reason = false
- local user = false
- local input = mattata.input(message)
- -- check the message object for any users this command
- -- is intended to be executed on
- if message.reply then
- user = message.reply.from.id
- if input then
- reason = input
- end
- elseif input and input:match(' ') then
- user, reason = input:match('^(.-) (.-)$')
- elseif input then
- user = input
- end
- if not user then
- local output = 'You need to specify the user you\'d like to mute, either by username/ID or in reply.'
- local success = mattata.send_force_reply(message, output)
- if success then
- mattata.set_command_action(message.chat.id, success.result.message_id, '/mute')
- end
- return
- end
- if reason and type(reason) == 'string' and reason:match('^[Ff][Oo][Rr] ') then
- reason = reason:match('^[Ff][Oo][Rr] (.-)$')
- end
- if tonumber(user) == nil and not user:match('^%@') then
- user = '@' .. user
- end
- local user_object = mattata.get_user(user) or mattata.get_chat(user) -- resolve the username/ID to a user object
- if not user_object then
- local output = language['errors']['unknown']
- return mattata.send_reply(message, output)
- elseif user_object.result.id == self.info.id then
- return false -- don't let the bot mute itself
- end
- local bot_status = mattata.get_chat_member(message.chat.id, self.info.id)
- if not bot_status then
- return false
- elseif not bot_status.result.can_restrict_members then
- return mattata.send_reply(message, 'It appears I don\'t have the required permissions required in order to mute that user. Please amend this and try again!')
- end
- user_object = user_object.result
- local status = mattata.get_chat_member(message.chat.id, user_object.id)
- local is_admin = mattata.is_group_admin(message.chat.id, user_object.id)
- if not status then
- return mattata.send_reply(message, 'I couldn\'t retrieve any information about that user!')
- elseif is_admin then -- we won't try and mute moderators and administrators.
- return mattata.send_reply(message, 'I can\'t mute that user because they\'re an admin in this chat!')
- end
- local success = mattata.restrict_chat_member(message.chat.id, user_object.id, os.time(), false, false, false, false, false, false, false, false) -- attempt to mute the user in the group
- if not success then
- return mattata.send_reply(message, 'I couldn\'t mute that user in this group, because it appears I don\'t have permission to!')
- end
- reason = reason and ', for ' .. reason or ''
- local admin_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
- local muted_username = mattata.get_formatted_user(user_object.id, user_object.first_name, 'html')
- redis:hincrby('chat:' .. message.chat.id .. ':' .. user_object.id, 'mutes', 1)
- if mattata.get_setting(message.chat.id, 'log administrative actions') then
- local log_chat = mattata.get_log_chat(message.chat.id)
- local output = '%s <code>[%s]</code> has muted %s <code>[%s]</code> in %s <code>[%s]</code>%s.\n%s %s'
- output = string.format(output, admin_username, message.from.id, muted_username, user_object.id, mattata.escape_html(message.chat.title), message.chat.id, reason, '#chat' .. tostring(message.chat.id):gsub('^-100', ''), '#user' .. user_object.id)
- mattata.send_message(log_chat, output, 'html')
- end
- if message.reply and mattata.get_setting(message.chat.id, 'delete reply on action') then
- mattata.delete_message(message.chat.id, message.reply.message_id)
- end
- local output = '%s has muted %s%s.'
- output = string.format(output, admin_username, muted_username, reason)
- return mattata.send_message(message.chat.id, output, 'html')
-end
-
-return mute
\ No newline at end of file
diff --git a/plugins/administration/myfeds.lua b/plugins/administration/myfeds.lua
deleted file mode 100644
index ac12228..0000000
--- a/plugins/administration/myfeds.lua
+++ /dev/null
@@ -1,52 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local myfeds = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function myfeds:init()
- myfeds.commands = mattata.commands(self.info.username):command('myfeds'):command('mf').table
- myfeds.help = '/myfeds - View a list of Feds you own/administrate. Alias: /mf.'
-end
-
-function myfeds.on_message(_, message)
- local feds = redis:keys('fed:*')
- local admins = redis:keys('fedadmins:*')
- local owned = {}
- local administrate = {}
- local output = { '<b>You currently own the following Feds:</b>\n' }
- for _, fed in pairs(feds) do
- if redis:hget(fed, 'creator') == tostring(message.from.id) then
- table.insert(owned, fed:match('^fed:(.-)$'))
- end
- end
- if #owned == 0 then
- table.insert(output, '<em>None</em>')
- else
- for _, fed in pairs(owned) do
- local title = redis:hget('fed:' .. fed, 'title')
- table.insert(output, '<em>' .. mattata.escape_html(title) .. '</em> <code>[' .. fed .. ']</code>')
- end
- end
- for _, fed in pairs(admins) do
- if redis:sismember(fed, message.from.id) and not mattata.is_fed_creator(fed:match('^fedadmins:(.-)$'), message.from.id) then
- table.insert(administrate, fed:match('^fedadmins:(.-)$'))
- end
- end
- table.insert(output, '\n<b>You currently administrate the following Feds:</b>\n')
- if #administrate == 0 then
- table.insert(output, '<em>None</em>')
- else
- for _, fed in pairs(administrate) do
- local title = redis:hget('fed:' .. fed, 'title')
- table.insert(output, '<em>' .. mattata.escape_html(title) .. '</em> <code>[' .. fed .. ']</code>')
- end
- end
- output = table.concat(output, '\n')
- return mattata.send_reply(message, output, 'html')
-end
-
-return myfeds
\ No newline at end of file
diff --git a/plugins/administration/newfed.lua b/plugins/administration/newfed.lua
deleted file mode 100644
index 2778c56..0000000
--- a/plugins/administration/newfed.lua
+++ /dev/null
@@ -1,55 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local newfed = {}
-local mattata = require('mattata')
-local uuid = require('uuid')
-local redis = require('libs.redis')
-
-function newfed:init(configuration)
- newfed.commands = mattata.commands(self.info.username):command('newfed').table
- newfed.help = '/newfed <fed name> - Allows a group admin to create a new Fed, and return its UUID.'
- newfed.limit = configuration.administration.feds.group_limit
-end
-
-function newfed.on_message(_, message, _, language)
- if message.chat.type ~= 'private' and not mattata.is_group_admin(message.chat.id, message.from.id) then
- return mattata.send_reply(message, language.errors.admin)
- end
- local input = mattata.input(message.text)
- if not input then
- local success = mattata.send_force_reply(message, 'Please specify a name for the Fed!')
- if success then
- mattata.set_command_action(message.chat.id, success.result.message_id, '/newfed')
- end
- return success
- elseif input:len() > 128 then
- return mattata.send_reply(message, 'Fed names cannot be longer than 128 characters in length!')
- end
- uuid.seed()
- local fed_uuid = uuid.new()
- local feds = redis:smembers('chat:' .. message.chat.id .. ':feds')
- if message.chat.type ~= 'private' and #feds >= newfed.limit then
- return mattata.send_reply(message, 'This group is already part of ' .. newfed.limit .. ' or more Feds. To leave one of these Feds and create a new one (starting with this chat in it), please send /leavefed <fed UUID> and then try this command again! Alternatively, to create a Fed but not have this group join it, use this command in private message!')
- elseif redis:exists('fedmembers:' .. fed_uuid) then -- EXTREMELY unlikely it would generate the same UUID but I know my luck
- fed_uuid = uuid.new()
- end
- redis:hset('fed:' .. fed_uuid, 'creator', message.from.id)
- redis:hset('fed:' .. fed_uuid, 'date_created', os.time())
- redis:hset('fed:' .. fed_uuid, 'title', input)
- redis:sadd('fedadmins:' .. fed_uuid, message.from.id)
- redis:sadd('feds:' .. message.from.id, fed_uuid)
- local output = 'Created the Fed <b>%s</b>\nTo join this Fed in a group, send <code>/joinfed %s</code> in the group.'
- if message.chat.type ~= 'private' then
- redis:sadd('chat:' .. message.chat.id .. ':feds', fed_uuid)
- redis:sadd('fedmembers:' .. fed_uuid, message.chat.id)
- output = 'Created the Fed <b>%s</b>, and added this group <code>[%s]</code> to it!\nTo join this Fed in another group, send <code>/joinfed %s</code>'
- end
- input = mattata.escape_html(input)
- output = message.chat.type == 'private' and string.format(output, input, fed_uuid) or string.format(output, input, message.chat.id, fed_uuid)
- return mattata.send_reply(message, output, 'html')
-end
-
-return newfed
\ No newline at end of file
diff --git a/plugins/administration/nodelete.lua b/plugins/administration/nodelete.lua
deleted file mode 100644
index 5d82d9c..0000000
--- a/plugins/administration/nodelete.lua
+++ /dev/null
@@ -1,59 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local nodelete = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function nodelete:init()
- nodelete.commands = mattata.commands(self.info.username):command('nodelete').table
- nodelete.help = '/nodelete [add | del] <plugins> - Allows the given plugins to retain the commands they were executed with by allowlisting them from the "delete commands" administrative setting. Multiple plugins can be specified.'
-end
-
-function nodelete:on_message(message, configuration, language)
- local input = mattata.input(message.text)
- if message.chat.type ~= 'supergroup' then
- return mattata.send_reply(
- message,
- language['errors']['supergroup']
- )
- elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
- return mattata.send_reply(
- message,
- language['errors']['admin']
- )
- elseif not input or not input:match('^add .-$') and not input:match('^del .-$') then
- return mattata.send_reply(message, nodelete.help)
- end
- local plugins = {}
- local process_type, input = input:match('([ad][de][dl]) (.-)$')
- for plugin in input:gmatch('[%w_]+') do
- for k, v in pairs(configuration.plugins) do
- if v:lower() == plugin:lower()then
- table.insert(plugins, plugin)
- end
- end
- end
- if #plugins < 1 then
- return mattata.send_reply(message, 'No matching plugins were found!')
- end
- local total = #plugins
- local success = {}
- for k, v in pairs(plugins) do
- if process_type == 'add' and not redis:sismember('chat:' .. message.chat.id .. ':no_delete', v) then -- Check to make sure the plugin isn't already allowlisted from having
- -- its commands deleted.
- redis:sadd('chat:' .. message.chat.id .. ':no_delete', v)
- table.insert(success, v)
- elseif process_type == 'del' and redis:sismember('chat:' .. message.chat.id .. ':no_delete', v) then -- Check to make sure the plugin has already been allowlisted from having
- -- its commands deleted.
- redis:srem('chat:' .. message.chat.id .. ':no_delete', v)
- table.insert(success, v)
- end
- end
- local output = process_type == 'del' and 'Commands will now be deleted for ' .. total .. ' plugins!' or 'Commands will no longer be deleted for ' .. total .. ' plugins!'
- return mattata.send_reply(message, output)
-end
-
-return nodelete
\ No newline at end of file
diff --git a/plugins/administration/pictrigger.lua b/plugins/administration/pictrigger.lua
deleted file mode 100644
index e06f974..0000000
--- a/plugins/administration/pictrigger.lua
+++ /dev/null
@@ -1,88 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local pictriggers = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function pictriggers:init()
- pictriggers.commands = mattata.commands(self.info.username):command('pictriggers'):command('addpictrigger'):command('delpictrigger').table
- pictriggers.help = '/pictriggers - Allows admins to view existing picture triggers. Use /addpictrigger <trigger> <URL> to add one, and /delpictrigger <trigger> to delete one. Each chat is allowed 8 picture triggers, with a maximum of 16 characters per word trigger. Trigger words can be alpha-numerical.'
-end
-
-function pictriggers:on_new_message(message)
- if message.command or message.is_media or self.is_ai then
- return false
- end
- local matches = redis:hgetall('pictriggers:' .. message.chat.id)
- if not next(matches) == 0 then
- return false
- end
- for trigger, value in pairs(matches) do
- if message.text:match(trigger) then
- return mattata.send_photo(message.chat.id, value)
- end
- end
- return
-end
-
-function pictriggers:on_message(message, configuration)
- self.is_done = true
- if message.chat.type == 'private' or not mattata.is_group_admin(message.chat.id, message.from.id) then
- return false
- elseif message.command == 'pictriggers' then
- local matches = redis:hgetall('pictriggers:' .. message.chat.id)
- if not next(matches) then
- return mattata.send_reply(message, 'This chat doesn\'t have any picture triggers set up. To add one, use /addpictrigger <trigger> <URL>.')
- end
- local output = 'Picture triggers for <b>%s</b>\n\n%s'
- local all = {}
- for trigger, value in pairs(matches) do
- local line = '<code>%s</code>: %s'
- line = string.format(line, mattata.escape_html(trigger), mattata.escape_html(value))
- table.insert(all, line)
- end
- all = table.concat(all, '\n')
- output = string.format(output, mattata.escape_html(message.chat.title), all)
- return mattata.send_reply(message, output, 'html')
- elseif message.command == 'addpictrigger' then
- local input = mattata.input(message.text)
- if not input or not input:match('^%w+ .-$') then
- return mattata.send_reply(message, pictriggers.help)
- end
- local count = 0
- local all = redis:hgetall('pictriggers:' .. message.chat.id)
- for _, v in pairs(all) do
- count = count + 1
- end
- if count >= 8 then
- return mattata.send_reply(message, 'You can\'t have more than 8 picture triggers! Please delete one using /delpictrigger <trigger>. To view a list of this chat\'t picture triggers, use /pictriggers.')
- end
- local trigger, value = input:match('^(%w+) (.-)$')
- if trigger:len() > 16 then
- return mattata.send_reply(message, 'The trigger needs to be 1-16 characters long, and alpha-numerical.')
- end
- local success = mattata.send_photo(configuration.log_chat, value)
- if not success then
- return mattata.send_reply(message, 'That appears to be an invalid URL, because I couldn\'t send it! Please make sure it\'s a format Telegram bot API supports.')
- end
- mattata.delete_message(configuration.log_chat, success.result.message_id)
- redis:hset('pictriggers:' .. message.chat.id, trigger, value)
- return mattata.send_reply(message, 'Successfully added that picture trigger! To view a list of picture triggers, send /pictriggers.')
- elseif message.command == 'delpictrigger' then
- local input = mattata.input(message.text)
- if not input or not input:match('^%w+$') then
- return mattata.send_reply(message, 'Please specify the picture trigger you\'d like to delete! To view your existing picture triggers, send /pictriggers.')
- end
- local deleted = redis:hdel('pictriggers:' .. message.chat.id, input)
- if deleted == 0 then
- return mattata.send_reply(message, 'That trigger does not exist! Use /pictriggers to view a list of existing picture triggers for this chat.')
- end
- return mattata.send_reply(message, 'Successfully deleted that picture trigger!')
- end
- return false
-end
-
-return pictriggers
\ No newline at end of file
diff --git a/plugins/administration/pin.lua b/plugins/administration/pin.lua
deleted file mode 100644
index ad8255b..0000000
--- a/plugins/administration/pin.lua
+++ /dev/null
@@ -1,66 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local pin = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function pin:init()
- pin.commands = mattata.commands(self.info.username):command('pin').table
- pin.help = '/pin <text> - Pins the given text, with Markdown formatting enabled. To update the pin, send the command again with the new pin content.'
-end
-
-function pin:on_service_message(service_type, message, configuration, language)
- if service_type == 'pinned message' then
- local current = tonumber(redis:hget('chat:' .. message.chat.id .. ':info', 'pin'))
- if mattata.get_setting(message.chat.id, 'remove channel pins') and message.from.id == 777000 then
- if current then
- return mattata.pin_chat_message(message.chat.id, current, true)
- end
- return mattata.unpin_chat_message(message.chat.id)
- elseif mattata.get_setting(message.chat.id, 'remove other pins') then
- if current and message.pinned_message.message_id ~= current then
- return mattata.pin_chat_message(message.chat.id, current, true)
- end
- end
- if message.from.id == self.info.id then
- return mattata.delete_message(message.chat.id, message.message_id)
- end
- end
-end
-
-function pin:on_message(message, configuration, language)
- if not mattata.is_group_admin(message.chat.id, message.from.id) then
- return mattata.send_reply(message, language['errors']['admin'])
- end
- local input = mattata.input(message.text)
- local last_pin = redis:hget('chat:' .. message.chat.id .. ':info', 'pin')
- if not input then
- if not last_pin then
- return mattata.send_reply(message, language['pin']['1'])
- end
- local success = mattata.send_message(message, language['pin']['2'], nil, true, false, last_pin)
- if not success then
- return mattata.send_reply(message, language['pin']['3'])
- end
- return
- end
- local success = mattata.edit_message_text(message.chat.id, last_pin, input, true, true)
- if not success then
- if not redis:hget('chat:' .. message.chat.id .. ':info', 'pin') then
- mattata.send_reply(message, language['pin']['4'])
- end
- local new_pin = mattata.send_message(message, input, 'markdown', true, false)
- if not new_pin then
- return mattata.send_reply(message, language['pin']['5'])
- end
- mattata.pin_chat_message(message.chat.id, new_pin.result.message_id, true)
- redis:hset('chat:' .. message.chat.id .. ':info', 'pin', new_pin.result.message_id)
- last_pin = new_pin.result.message_id
- end
- return mattata.pin_chat_message(message.chat.id, last_pin)
-end
-
-return pin
\ No newline at end of file
diff --git a/plugins/administration/promote.lua b/plugins/administration/promote.lua
deleted file mode 100644
index cc9fb57..0000000
--- a/plugins/administration/promote.lua
+++ /dev/null
@@ -1,151 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local promote = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function promote:init()
- promote.commands = mattata.commands(self.info.username)
- :command('promote')
- :command('mod').table
- promote.help = '/promote [user] - Promotes a user to a moderator of the current chat. This command can only be used by administrators of a supergroup. Alias: /mod.'
-end
-
-function promote:on_message(message, configuration, language)
- if message.chat.type ~= 'supergroup'
- then
- return mattata.send_reply(
- message,
- language['errors']['supergroup']
- )
- elseif not mattata.is_group_admin(
- message.chat.id,
- message.from.id,
- true
- )
- then
- return mattata.send_reply(
- message,
- language['errors']['admin']
- )
- end
- local input = message.reply
- and tostring(message.reply.from.id)
- or mattata.input(message.text)
- if not input
- then
- return mattata.send_reply(
- message,
- promote.help
- )
- end
- if tonumber(input) == nil
- and not input:match('^%@')
- then
- input = '@' .. input
- end
- local user = mattata.get_user(input)
- or mattata.get_chat(input) -- Resolve the username/ID to a user object.
- if not user
- then
- return mattata.send_reply(
- message,
- language['errors']['unknown']
- )
- elseif user.result.id == self.info.id
- then
- return
- end
- user = user.result
- local status = mattata.get_chat_member(
- message.chat.id,
- user.id
- )
- if not status
- then
- return mattata.send_reply(
- message,
- language['errors']['generic']
- )
- elseif mattata.is_group_admin(
- message.chat.id,
- user.id
- )
- or status.result.status == 'creator'
- or status.result.status == 'administrator'
- then -- We won't try and promote moderators and administrators.
- return mattata.send_reply(
- message,
- language['promote']['1']
- )
- elseif status.result.status == 'left'
- or status.result.status == 'kicked'
- then -- Check if the user is in the group or not.
- return mattata.send_reply(
- message,
- status.result.status == 'left'
- and language['promote']['2']
- or language['promote']['3']
- )
- end
- redis:sadd(
- 'administration:' .. message.chat.id .. ':mods',
- user.id
- )
- if redis:hget(
- string.format(
- 'chat:%s:settings',
- message.chat.id
- ),
- 'log administrative actions'
- )
- then
- mattata.send_message(
- mattata.get_log_chat(message.chat.id),
- string.format(
- '<pre>%s%s [%s] has promoted %s%s [%s] in %s%s [%s].</pre>',
- message.from.username
- and '@'
- or '',
- message.from.username
- or mattata.escape_html(message.from.first_name),
- message.from.id,
- user.username
- and '@'
- or '',
- user.username
- or mattata.escape_html(user.first_name),
- user.id,
- message.chat.username
- and '@'
- or '',
- message.chat.username
- or mattata.escape_html(message.chat.title),
- message.chat.id
- ),
- 'html'
- )
- end
- return mattata.send_message(
- message.chat.id,
- string.format(
- '<pre>%s%s has promoted %s%s.</pre>',
- message.from.username
- and '@'
- or '',
- message.from.username
- or mattata.escape_html(message.from.first_name),
- user.username
- and '@'
- or '',
- user.username
- or mattata.escape_html(user.first_name)
- ),
- 'html'
- )
-end
-
-return promote
\ No newline at end of file
diff --git a/plugins/administration/purge.lua b/plugins/administration/purge.lua
deleted file mode 100644
index e73c24a..0000000
--- a/plugins/administration/purge.lua
+++ /dev/null
@@ -1,103 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local purge = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function purge:init()
- purge.commands = mattata.commands(self.info.username):command('purge'):command('delmessages'):command('clear').table
- purge.help = '/purge [1-25] - Deletes the previous X messages (by message ID), where X is the number specified between 1 and 25 inclusive. Alternatively, a message can be replied to (within the past 25 messages), and those messages will be deleted. If messages have already been purged in between the replied-to message and the command, less will be deleted. Aliases: /delmessages, /clear.'
-end
-
-function purge:on_message(message, configuration, language)
- if message.chat.type ~= 'supergroup' then
- return mattata.send_reply(
- message,
- language['errors']['supergroup']
- )
- elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
- return mattata.send_reply(message, language['errors']['admin'])
- end
- if redis:get('purge:' .. message.chat.id) then
- return mattata.send_reply(message, 'You can only use this command once every 2 minutes. Please wait for it to cooldown!')
- end
- redis:set('purge:' .. message.chat.id, message.from.id)
- redis:expire('purge:' .. message.chat.id, 120)
- local input = mattata.input(message.text)
- if not input and not message.reply then
- redis:del('purge:' .. message.chat.id)
- return mattata.send_reply(message, purge.help)
- elseif message.reply then
- local amount = message.message_id - message.reply.message_id
- if amount > 25 then
- amount = 25
- end
- if tonumber(input) ~= nil and tonumber(input) <= 25 then
- amount = tonumber(input)
- elseif tonumber(input) ~= nil then
- redis:del('purge:' .. message.chat.id)
- return mattata.send_reply(message, 'You cannot purge more than 25 messages at a time!')
- end
- local progress = message.reply.message_id
- local deleted = 0
- for i = 1, amount do
- if deleted == amount then
- return mattata.send_message(message.chat.id, 'Successfully deleted ' .. deleted .. ' message(s)!')
- end
- local done = mattata.delete_message(message.chat.id, progress)
- if done then
- deleted = deleted + 1
- end
- progress = progress + 1
- end
- return mattata.send_message(message.chat.id, 'Successfully deleted ' .. deleted .. ' message(s)!')
- elseif tonumber(input) == nil then
- redis:del('purge:' .. message.chat.id)
- return mattata.send_reply(message, 'Please specify a numeric value, between 1 and 25 inclusive.')
- elseif tonumber(input) < 1 then
- redis:del('purge:' .. message.chat.id)
- return mattata.send_reply(message, 'That number is too small! You must specify a number between 1 and 25 inclusive.')
- elseif tonumber(input) > 25 then
- redis:del('purge:' .. message.chat.id)
- return mattata.send_reply(message, 'That number is too large! You must specify a number between 1 and 25 inclusive.')
- end
- local current = 0
- if not message.reply then
- current = mattata.send_message(message.chat.id, 'Attempting to purge the previous ' .. input .. ' message(s)...')
- if not current then
- redis:del('purge:' .. message.chat.id)
- return false
- end
- else
- current = message
- current.result = current.reply
- end
- current = current.result.message_id
- if tonumber(current) - tonumber(input) <= 1 then
- redis:del('purge:' .. message.chat.id)
- return mattata.edit_message_text(
- message.chat.id,
- current,
- 'There are not ' .. input .. ' message(s) available to be deleted! Please specify a number between 1 and ' .. tonumber(current) - tonumber(input) - 1 .. ' inclusive.'
- )
- end
- local progress = tonumber(current) - 1
- local deleted = 0
- for i = 1, tonumber(input) do
- local done = mattata.delete_message(message.chat.id, progress)
- if done then
- deleted = deleted + 1
- end
- progress = progress - 1
- end
- local success = mattata.edit_message_text(message.chat.id, current, 'Successfully deleted ' .. deleted .. ' message(s)!')
- if not success then
- return mattata.send_message(message.chat.id, 'Successfully deleted ' .. deleted .. ' message(s)!')
- end
- return success
-end
-
-return purge
\ No newline at end of file
diff --git a/plugins/administration/report.lua b/plugins/administration/report.lua
deleted file mode 100644
index 2eea20c..0000000
--- a/plugins/administration/report.lua
+++ /dev/null
@@ -1,91 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local report = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function report:init()
- report.commands = mattata.commands(self.info.username, { '^@[Aa][Dd][Mm][Ii][Nn][Ss]?$'}):command('report'):command('ops').table
- report.help = '/report - Reports the replied-to message to the first 10 administrators of the group, via private message. This command may also be triggered by sending @admin. Alias: /ops.'
-end
-
-function report.on_callback_query(_, callback_query, message)
- local chat_id, user_id, message_id = callback_query.data:match('^(%-?%d+):(%d+):(%d*)$')
- if not chat_id or not user_id or not message_id then
- return false
- elseif user_id ~= tostring(callback_query.from.id) then
- return false
- elseif not mattata.is_group_admin(chat_id, callback_query.from.id) then
- return false
- end
- local all = redis:smembers('report:' .. callback_query.data)
- if #all == 0 then
- return false
- end
- local ban_not_kick = mattata.get_setting(chat_id, 'ban not kick')
- local action = ban_not_kick and mattata.ban_chat_member or mattata.kick_chat_member
- local success = action(chat_id, user_id)
- if not success then
- return mattata.edit_message_text(message.chat.id, message.message_id, 'An unknown error occurred and I couldn\'t ban that user! Maybe they\'ve tried to leave already?')
- end
- local admin_username = mattata.get_formatted_user(callback_query.from.id, callback_query.from.first_name, 'html')
- for _, payload in pairs(all) do
- local admin_id, report_id, forward_id = payload:match('^(%d+):(%d*):(%d*)$')
- mattata.delete_message(tonumber(admin_id), tonumber(forward_id))
- local output = string.format('This report has been dealt with by %s!', admin_username)
- if tonumber(admin_id) == callback_query.from.id then
- output = 'All done! They\'re gone now, and the message was cleared up!'
- end
- mattata.edit_message_text(tonumber(admin_id), tonumber(report_id), output, 'html')
- end
- redis:del('report:' .. callback_query.data)
- mattata.delete_message(tonumber(chat_id), tonumber(message_id))
- if mattata.get_setting(chat_id, 'log administrative actions') then
- local punishment = ban_not_kick and 'banned' or 'kicked'
- local reported = mattata.get_user(user_id).result
- local reported_username = mattata.get_formatted_user(reported.id, reported.first_name, 'html')
- local title = mattata.escape_html(mattata.get_chat(chat_id).result.title)
- local output = string.format('%s <code>[%s]</code> was %s by %s <code>[%s]</code> for their reported message in %s <code>[%s]</code>\n#chat%s #user%s', reported_username, user_id, punishment, admin_username, callback_query.from.id, title, chat_id, chat_id:gsub('^%-100', ''), user_id)
- mattata.send_message(mattata.get_log_chat(chat_id), output, 'html')
- end
- return
-end
-
-
-function report:on_message(message, _, language)
- if not message.reply then
- return mattata.send_message(message.chat.id, language['report']['1'])
- elseif message.reply.from.id == message.from.id then
- return mattata.send_message(message.chat.id, language['report']['2'])
- end
- local admins = mattata.get_chat_administrators(message.chat.id)
- local notified = 0
- for n in pairs(admins.result) do
- if admins.result[n].user.id ~= self.info.id then
- if notified >= 10 then
- break
- end
- local old_language = language
- local current_time = os.time()
- language = require('languages.' .. mattata.get_user_language(admins.result[n].user.id))
- local output = string.format(language['report']['3'], mattata.escape_html(message.from.first_name), mattata.escape_html(message.chat.title))
- output = output .. '\n<a href="https://t.me/c/' .. tostring(message.chat.id):gsub('^%-100', '') .. '/' .. message.reply.message_id .. '">' .. language['report']['4'] .. '</a>'
- local punishment = mattata.get_setting(message.chat.id, 'ban not kick') and 'Ban' or 'Kick'
- local keyboard = mattata.inline_keyboard():row(mattata.row():callback_data_button(punishment .. ' and get rid of it!', 'report:' .. message.chat.id .. ':' .. message.reply.from.id .. ':' .. message.reply.message_id .. ':' .. current_time))
- local forward = mattata.forward_message(admins.result[n].user.id, message.chat.id, false, message.reply.message_id)
- if forward then
- local success = mattata.send_message(admins.result[n].user.id, output, 'html', true, false, forward.result.message_id, keyboard)
- notified = notified + 1
- redis:sadd('report:' .. message.chat.id .. ':' .. message.reply.from.id .. ':' .. message.reply.message_id, admins.result[n].user.id .. ':' .. success.result.message_id .. ':' .. forward.result.message_id)
- end
- language = old_language
- end
- end
- local output = string.format(language['report']['5'], notified)
- return mattata.send_reply(message, output)
-end
-
-return report
\ No newline at end of file
diff --git a/plugins/administration/rules.lua b/plugins/administration/rules.lua
deleted file mode 100644
index 3372f6a..0000000
--- a/plugins/administration/rules.lua
+++ /dev/null
@@ -1,32 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local rules = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function rules:init()
- rules.commands = mattata.commands(self.info.username):command('rules').table
- rules.help = '/rules - View the group\'s rules.'
-end
-
-function rules:on_message(message, configuration, language)
- local input = mattata.input(message.text)
- local chat_id = message.chat.id
- if not input and message.chat.type ~= 'supergroup' then
- return false
- elseif input and input:match('^%-?%d+$') then
- chat_id = input
- end
- local output = mattata.get_value(chat_id, 'rules') or 'There are no rules set for this chat!'
- if mattata.get_setting(message.chat.id, 'send rules in group') or (input and message.chat.type == 'private') then
- return mattata.send_message(message.chat.id, output, 'markdown', true, false)
- end
- local success = mattata.send_message(message.from.id, output, 'markdown', true, false)
- output = success and 'I have sent you the rules via private chat!' or string.format('You need to speak to me in private chat before I can send you the rules! Just click [here](https://t.me/%s?start=rules_%s), press the "START" button, and try again!', self.info.username, message.chat.id)
- return mattata.send_reply(message, output, 'markdown', true)
-end
-
-return rules
\ No newline at end of file
diff --git a/plugins/administration/save.lua b/plugins/administration/save.lua
deleted file mode 100644
index 41d0412..0000000
--- a/plugins/administration/save.lua
+++ /dev/null
@@ -1,34 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local save = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function save:init()
- save.commands = mattata.commands(self.info.username):command('save'):command('s').table
- save.help = '/save - Stores the replied-to message in ' .. self.info.first_name .. '\'s database - of which a randomly-selected, saved message from the said user can be retrieved using /quote. Alias: /s.'
-end
-
-function save.on_message(_, message, _, language)
- if not message.reply or (not message.reply.text and not message.reply.voice) then
- return mattata.send_reply(message, save.help)
- elseif message.reply.forward_from then
- message.reply.from = message.reply.forward_from
- end
- if redis:get('user:' .. message.reply.from.id .. ':opt_out') then
- redis:del('user:' .. message.reply.from.id .. ':quotes')
- return mattata.send_reply(message, language['save']['1'])
- end
- if message.reply.voice then
- message.reply.text = '$voice:' .. message.reply.voice.file_id
- end
- redis:sadd('user:' .. message.reply.from.id .. ':quotes', message.reply.text)
- local user = mattata.get_formatted_user(message.reply.from.id, message.reply.from.name, 'html')
- local output = string.format(language['save']['2'], user)
- return mattata.send_reply(message, output, 'html')
-end
-
-return save
\ No newline at end of file
diff --git a/plugins/administration/setcaptcha.lua b/plugins/administration/setcaptcha.lua
deleted file mode 100644
index 321191f..0000000
--- a/plugins/administration/setcaptcha.lua
+++ /dev/null
@@ -1,224 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local setcaptcha = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function setcaptcha:init()
- setcaptcha.commands = mattata.commands(self.info.username):command('setcaptcha').table
- setcaptcha.help = '/setcaptcha - Allows admins to configure CAPTCHA settings.'
-end
-
-function setcaptcha.on_callback_query(_, callback_query, message, configuration, language)
- local action, new, chat_id = callback_query.data:match('^(.-):(.-):(.-)$')
- if not action or not new or not chat_id then
- return mattata.answer_callback_query(callback_query.id)
- elseif not mattata.is_group_admin(chat_id, callback_query.from.id) then
- return mattata.answer_callback_query(callback_query.id, language.errors.admin)
- end
- new = tonumber(new)
- local captchas = configuration.administration.captcha.files
- local length = mattata.get_setting(chat_id, 'captcha length') or configuration.administration.captcha.length.default
- length = math.floor(length)
- local next_length = length + 1
- local prev_length = length - 1
- local size = mattata.get_setting(chat_id, 'captcha size') or configuration.administration.captcha.size.default
- size = math.floor(size)
- local next_size = size + 1
- local prev_size = size - 1
- local current = mattata.get_setting(chat_id, 'captcha font') or 1
- current = math.floor(current)
- local font_name = captchas[current] or captchas[1]
- local next_font_pos = current + 1
- local prev_font_pos = current - 1
- local timeout = mattata.get_setting(chat_id, 'captcha timeout') or configuration.administration.captcha.timeout.default
- timeout = math.floor(timeout)
- local next_timeout = timeout + 1
- local prev_timeout = timeout - 1
- if action == 'font' then
- if tonumber(new) < 1 then
- new = #captchas
- elseif tonumber(new) > #captchas then
- new = 1
- end
- font_name = captchas[new]
- if not font_name then
- return mattata.answer_callback_query(callback_query.from.id, 'This font is no longer available!')
- end
- redis:hset('chat:' .. chat_id .. ':settings', 'captcha font', new)
- if next_font_pos > #captchas then
- next_font_pos = 1
- end
- prev_font_pos = new - 1
- if prev_font_pos < 1 then
- prev_font_pos = #captchas
- end
- elseif action == 'length' then
- if tonumber(new) < configuration.administration.captcha.length.min then
- new = configuration.administration.captcha.length.max
- elseif tonumber(new) > configuration.administration.captcha.length.max then
- new = configuration.administration.captcha.length.min
- end
- redis:hset('chat:' .. chat_id .. ':settings', 'captcha length', new)
- length = new
- next_length = new + 1
- if next_length > configuration.administration.captcha.length.max then
- next_length = configuration.administration.captcha.length.min
- end
- prev_length = new - 1
- if prev_length < configuration.administration.captcha.length.min then
- prev_length = configuration.administration.captcha.length.max
- end
- elseif action == 'size' then
- if tonumber(new) < configuration.administration.captcha.size.min then
- new = configuration.administration.captcha.size.max
- elseif tonumber(new) > configuration.administration.captcha.size.max then
- new = configuration.administration.captcha.size.min
- end
- redis:hset('chat:' .. chat_id .. ':settings', 'captcha size', new)
- size = new
- next_size = new + 1
- if next_size > configuration.administration.captcha.size.max then
- next_size = configuration.administration.captcha.size.min
- end
- prev_size = new - 1
- if prev_size < configuration.administration.captcha.size.min then
- prev_size = configuration.administration.captcha.size.max
- end
- elseif action == 'timeout' then
- if tonumber(new) < configuration.administration.captcha.timeout.min then
- new = configuration.administration.captcha.timeout.max
- elseif tonumber(new) > configuration.administration.captcha.timeout.max then
- new = configuration.administration.captcha.timeout.min
- end
- redis:hset('chat:' .. chat_id .. ':settings', 'captcha timeout', new)
- timeout = new
- next_timeout = new + 1
- if next_timeout > configuration.administration.captcha.timeout.max then
- next_timeout = configuration.administration.captcha.timeout.min
- end
- prev_timeout = new - 1
- if prev_timeout < configuration.administration.captcha.timeout.min then
- prev_timeout = configuration.administration.captcha.timeout.max
- end
- end
- font_name = font_name:gsub('^%l', string.upper):gsub('%.[to]tf$', '')
- local keyboard = mattata.inline_keyboard():row(
- mattata.row():callback_data_button('CAPTCHA Length', 'setcaptcha')
- ):row(
- mattata.row()
- :callback_data_button(mattata.symbols.back, 'setcaptcha:length:' .. prev_length .. ':' .. chat_id)
- :callback_data_button(length, 'setcaptcha')
- :callback_data_button(mattata.symbols.next, 'setcaptcha:length:' .. next_length .. ':' .. chat_id)
- ):row(
- mattata.row():callback_data_button('Font Size', 'setcaptcha')
- ):row(
- mattata.row()
- :callback_data_button(mattata.symbols.back, 'setcaptcha:size:' .. prev_size .. ':' .. chat_id)
- :callback_data_button(size, 'setcaptcha')
- :callback_data_button(mattata.symbols.next, 'setcaptcha:size:' .. next_size .. ':' .. chat_id)
- ):row(
- mattata.row():callback_data_button('Font Family', 'setcaptcha')
- ):row(
- mattata.row()
- :callback_data_button(mattata.symbols.back, 'setcaptcha:font:' .. prev_font_pos .. ':' .. chat_id)
- :callback_data_button(font_name, 'setcaptcha')
- :callback_data_button(mattata.symbols.next, 'setcaptcha:font:' .. next_font_pos .. ':' .. chat_id)
- ):row(
- mattata.row():callback_data_button('CAPTCHA Timeout (Minutes)', 'setcaptcha')
- ):row(
- mattata.row()
- :callback_data_button(mattata.symbols.back, 'setcaptcha:timeout:' .. prev_timeout .. ':' .. chat_id)
- :callback_data_button(timeout, 'setcaptcha')
- :callback_data_button(mattata.symbols.next, 'setcaptcha:timeout:' .. next_timeout .. ':' .. chat_id)
- ):row(
- mattata.row():callback_data_button('Done', 'dismiss')
- )
- return mattata.edit_message_reply_markup(message.chat.id, message.message_id, nil, keyboard)
-end
-
-function setcaptcha:on_message(message, configuration, language)
- if message.chat.type ~= 'supergroup' then
- return mattata.send_reply(message, language.errors.supergroup)
- elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
- return mattata.send_reply(message, language.errors.admin)
- end
- local captcha = configuration.administration.captcha
- local length = mattata.get_setting(message.chat.id, 'captcha length') or configuration.administration.captcha.length.default
- length = math.floor(length)
- local next_length = length + 1
- local prev_length = length - 1
- local size = mattata.get_setting(message.chat.id, 'captcha size') or configuration.administration.captcha.size.default
- size = math.floor(size)
- local next_size = size + 1
- local prev_size = size - 1
- local font_file = mattata.get_setting(message.chat.id, 'captcha font') or 1
- font_file = math.floor(font_file)
- local font_name = configuration.administration.captcha.files[tonumber(font_file)]
- font_name = font_name:gsub('^%l', string.upper):gsub('%.[to]tf$', '')
- local timeout = mattata.get_setting(message.chat.id, 'captcha timeout') or configuration.administration.captcha.timeout.default
- timeout = math.floor(timeout)
- local next_timeout = timeout + 1
- local prev_timeout = timeout - 1
- local font_pos = 1
- for pos, font in pairs(captcha.files) do
- if font == font_file then
- font_pos = pos
- end
- end
- local next_font_pos = font_pos + 1
- if next_font_pos > #captcha.files then
- next_font_pos = 1
- end
- local prev_font_pos = font_pos - 1
- if prev_font_pos < 1 then
- prev_font_pos = #captcha.files
- end
- local keyboard = mattata.inline_keyboard():row(
- mattata.row():callback_data_button('CAPTCHA Length', 'setcaptcha')
- ):row(
- mattata.row()
- :callback_data_button(mattata.symbols.back, 'setcaptcha:length:' .. prev_length .. ':' .. message.chat.id)
- :callback_data_button(length, 'setcaptcha')
- :callback_data_button(mattata.symbols.next, 'setcaptcha:length:' .. next_length .. ':' .. message.chat.id)
- ):row(
- mattata.row():callback_data_button('Font Size', 'setcaptcha')
- ):row(
- mattata.row()
- :callback_data_button(mattata.symbols.back, 'setcaptcha:size:' .. prev_size .. ':' .. message.chat.id)
- :callback_data_button(size, 'setcaptcha')
- :callback_data_button(mattata.symbols.next, 'setcaptcha:size:' .. next_size .. ':' .. message.chat.id)
- ):row(
- mattata.row():callback_data_button('Font Family', 'setcaptcha')
- ):row(
- mattata.row()
- :callback_data_button(mattata.symbols.back, 'setcaptcha:font:' .. prev_font_pos .. ':' .. message.chat.id)
- :callback_data_button(font_name, 'setcaptcha')
- :callback_data_button(mattata.symbols.next, 'setcaptcha:font:' .. next_font_pos .. ':' .. message.chat.id)
- ):row(
- mattata.row():callback_data_button('CAPTCHA Timeout (Minutes)', 'setcaptcha')
- ):row(
- mattata.row()
- :callback_data_button(mattata.symbols.back, 'setcaptcha:timeout:' .. prev_timeout .. ':' .. message.chat.id)
- :callback_data_button(timeout, 'setcaptcha')
- :callback_data_button(mattata.symbols.next, 'setcaptcha:timeout:' .. next_timeout .. ':' .. message.chat.id)
- ):row(
- mattata.row():callback_data_button('Done', 'dismiss')
- )
- local output = 'Use the keyboard below to adjust the CAPTCHA settings in <b>%s</b>:'
- output = string.format(output, mattata.escape_html(message.chat.title))
- if mattata.get_setting(message.chat.id, 'settings in group') then
- return mattata.send_message(message.chat.id, output, 'html', true, false, nil, keyboard)
- else
- local success = mattata.send_message(message.from.id, output, 'html', true, false, nil, keyboard)
- if not success then
- return mattata.send_reply(message, 'You need to [private message me](https://t.me/' .. self.info.username:lower() .. ') before I can send you this!', true, true)
- end
- return mattata.send_reply(message, 'I\'ve sent you the CAPTCHA configuration panel [via private message](https://t.me/' .. self.info.username:lower() .. ')!', true, true)
- end
-end
-
-return setcaptcha
\ No newline at end of file
diff --git a/plugins/administration/setchattitle.lua b/plugins/administration/setchattitle.lua
deleted file mode 100644
index fdd69ef..0000000
--- a/plugins/administration/setchattitle.lua
+++ /dev/null
@@ -1,40 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local setchattitle = {}
-local mattata = require('mattata')
-
-function setchattitle:init()
- setchattitle.commands = mattata.commands(self.info.username):command('setchattitle'):command('sct').table
- setchattitle.help = '/setchattitle <title> - Sets the replied-to admin\'s title to the given text. The given text must be between 1 and 16 characters in length. Alias: /sct.'
-end
-
-function setchattitle:on_message(message, configuration, language)
- if message.chat.type == 'private' then
- return false
- elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
- return false
- elseif not message.reply then
- return mattata.send_reply(message, 'Please use this command in reply to the admin you want to give the title to!')
- elseif not mattata.is_group_admin(message.chat.id, message.reply.from.id) then
- return mattata.send_reply(message, 'The replied-to user isn\'t an admin in this group!')
- end
- local input = mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, setchattitle.help)
- elseif input:len() > 16 then
- return mattata.send_reply(message, 'The title must be between 1 and 16 characters long!')
- end
- local success = mattata.set_chat_administrator_custom_title(message.chat.id, message.reply.from.id, input)
- if not success then
- return mattata.send_reply(
- message,
- 'An error occured whilst trying to set that admin\'s title. Please ensure I have the required administrative permissions to perform this action, then try again.'
- )
- end
- return
-end
-
-return setchattitle
\ No newline at end of file
diff --git a/plugins/administration/setdescription.lua b/plugins/administration/setdescription.lua
deleted file mode 100644
index bad84cc..0000000
--- a/plugins/administration/setdescription.lua
+++ /dev/null
@@ -1,55 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local setdescription = {}
-local mattata = require('mattata')
-
-function setdescription:init()
- setdescription.commands = mattata.commands(self.info.username):command('setdescription').table
- setdescription.help = '/setdescription <text> - Sets the group\'s description to the given text. The given text must be between 1 and 255 characters in length.'
-end
-
-function setdescription:on_message(message, configuration, language)
- if message.chat.type == 'private'
- then
- return mattata.send_reply(
- message,
- 'You can\'t use this command in private chat.'
- )
- elseif not mattata.is_group_admin(
- message.chat.id,
- message.from.id
- )
- then
- return mattata.send_reply(
- message,
- language['errors']['admin']
- )
- end
- local input = mattata.input(message.text)
- if not input
- or input:len() < 1
- or input:len() > 255
- then
- return mattata.send_reply(
- message,
- setdescription.help
- )
- end
- local success = mattata.set_chat_description(
- message.chat.id,
- input
- )
- if not success
- then
- return mattata.send_reply(
- message,
- 'An error occured whilst trying to set the chat\'s description. Please ensure I have the required administrative permissions to perform this action, then try again.'
- )
- end
- return
-end
-
-return setdescription
\ No newline at end of file
diff --git a/plugins/administration/setgrouplang.lua b/plugins/administration/setgrouplang.lua
deleted file mode 100644
index 6c54429..0000000
--- a/plugins/administration/setgrouplang.lua
+++ /dev/null
@@ -1,229 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local setgrouplang = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-local json = require('dkjson')
-
-function setgrouplang:init()
- setgrouplang.commands = mattata.commands(self.info.username):command('setgrouplang').table
- setgrouplang.help = '/setgrouplang - Allows you to force mattata to respond to all members of the current chat in the selected language.'
-end
-
-setgrouplang.languages = {
- ['ar_ar'] = 'Arabic 🇸🇦',
- ['en_gb'] = 'British English 🇬🇧',
- ['en_us'] = 'American English 🇺🇸',
- ['de_de'] = 'Deutsch 🇩🇪',
- ['scottish'] = 'Scottish 🏴󠁧󠁢󠁳󠁣󠁴󠁿',
- ['pl_pl'] = 'Polski 🇵🇱',
- ['pt_br'] = 'Português do Brasil 🇧🇷',
- ['pt_pt'] = 'Português 🇵🇹',
- ['tr_tr'] = 'Türkçe 🇹🇷'
-}
-
-setgrouplang.languages_short = {
- ['ar_ar'] = '🇸🇦',
- ['en_gb'] = '🇬🇧',
- ['en_us'] = '🇺🇸',
- ['de_de'] = '🇩🇪',
- ['scottish'] = '🏴',
- ['pl_pl'] = '🇵🇱',
- ['pt_br'] = '🇧🇷',
- ['pt_pt'] = '🇵🇹',
- ['tr_tr'] = '🇹🇷'
-}
-
-function setgrouplang.get_keyboard(chat_id, language)
- local keyboard = {
- ['inline_keyboard'] = {
- {}
- }
- }
- local total = 0
- for _, v in pairs(setgrouplang.languages_short)
- do
- total = total + 1
- end
- local count = 0
- local rows = math.floor(total / 2)
- if rows ~= total
- then
- rows = rows + 1
- end
- local row = 1
- for k, v in pairs(setgrouplang.languages_short)
- do
- count = count + 1
- if count == rows * row
- then
- row = row + 1
- table.insert(
- keyboard.inline_keyboard,
- {}
- )
- end
- table.insert(
- keyboard.inline_keyboard[row],
- {
- ['text'] = v,
- ['callback_data'] = 'setgrouplang:' .. chat_id .. ':' .. k
- }
- )
- end
- table.insert(
- keyboard.inline_keyboard,
- {
- {
- ['text'] = language['setgrouplang']['5'],
- ['callback_data'] = 'administration:' .. chat_id .. ':force_group_language'
- }
- }
- )
- return keyboard
-end
-
-function setgrouplang.set_lang(chat_id, locale, lang, language)
- redis:hset(
- 'chat:' .. chat_id .. ':info',
- 'group language',
- locale
- )
- return string.format(
- language['setgrouplang']['1'],
- lang
- )
-end
-
-function setgrouplang.get_lang(chat_id, language)
- local lang = mattata.get_value(
- chat_id,
- 'group language'
- )
- or 'en_gb'
- for k, v in pairs(setgrouplang.languages)
- do
- if k == lang
- then
- lang = v
- break
- end
- end
- return string.format(
- language['setgrouplang']['2'],
- lang
- )
-end
-
-function setgrouplang:on_callback_query(callback_query, message, configuration, language)
- if not message
- or (
- message
- and message.date <= 1493668000
- )
- then
- return -- We don't want to process requests from messages before the language
- -- functionality was re-implemented, it could cause issues!
- elseif not mattata.is_group_admin(
- message.chat.id,
- callback_query.from.id
- )
- then
- return mattata.answer_callback_query(
- callback_query.id,
- language['errors']['admin']
- )
- end
- local chat_id, new_language = callback_query.data:match('^(.-)%:(.-)$')
- if not chat_id
- or not new_language
- or tostring(message.chat.id) ~= chat_id
- then
- return
- elseif not mattata.get_setting(
- message.chat.id,
- 'force group language'
- )
- then
- redis:hset(
- 'chat:' .. message.chat.id .. ':settings',
- 'force group language',
- true
- )
- end
- return mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- setgrouplang.set_lang(
- chat_id,
- new_language,
- setgrouplang.languages[new_language],
- language
- ),
- nil,
- true,
- setgrouplang.get_keyboard(
- chat_id,
- language
- )
- )
-end
-
-function setgrouplang:on_message(message, configuration, language)
- if not mattata.is_group_admin(
- message.chat.id,
- message.from.id
- )
- then
- return mattata.send_reply(
- message,
- language['errors']['admin']
- )
- elseif message.chat.type ~= 'supergroup'
- then
- return mattata.send_reply(
- message,
- language['errors']['supergroup']
- )
- end
- if not mattata.get_setting(
- message.chat.id,
- 'force group language'
- )
- then
- return mattata.send_message(
- message.chat.id,
- language['setgrouplang']['3'],
- nil,
- true,
- false,
- nil,
- mattata.inline_keyboard():row(
- mattata.row():callback_data_button(
- language['setgrouplang']['4'],
- 'administration:' .. message.chat.id .. ':force_group_language'
- )
- )
- )
- end
- return mattata.send_message(
- message.chat.id,
- setgrouplang.get_lang(
- message.chat.id,
- language
- ),
- nil,
- true,
- false,
- nil,
- setgrouplang.get_keyboard(
- message.chat.id,
- language
- )
- )
-end
-
-return setgrouplang
\ No newline at end of file
diff --git a/plugins/administration/setrules.lua b/plugins/administration/setrules.lua
deleted file mode 100644
index 67fa93a..0000000
--- a/plugins/administration/setrules.lua
+++ /dev/null
@@ -1,58 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local setrules = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function setrules:init()
- setrules.commands = mattata.commands(self.info.username):command('setrules').table
- setrules.help = '/setrules <text> - Sets the group\'s rules to the give text. Markdown formatting is supported.'
-end
-
-function setrules:on_message(message, configuration, language)
- if not mattata.is_group_admin(
- message.chat.id,
- message.from.id
- )
- then
- return mattata.send_reply(
- message,
- language['errors']['admin']
- )
- end
- local input = mattata.input(message.text)
- if not input
- then
- return mattata.send_reply(
- message,
- setrules.help
- )
- end
- redis:hset(
- 'chat:' .. message.chat.id .. ':info',
- 'rules',
- input
- )
- local success = mattata.send_message(
- message,
- input,
- 'markdown'
- )
- if not success
- then
- return mattata.send_reply(
- message,
- language['setrules']['1']
- )
- end
- return mattata.edit_message_text(
- message.chat.id,
- success.result.message_id,
- language['setrules']['2']
- )
-end
-
-return setrules
\ No newline at end of file
diff --git a/plugins/administration/settitle.lua b/plugins/administration/settitle.lua
deleted file mode 100644
index 053cfcf..0000000
--- a/plugins/administration/settitle.lua
+++ /dev/null
@@ -1,55 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local settitle = {}
-local mattata = require('mattata')
-
-function settitle:init()
- settitle.commands = mattata.commands(self.info.username):command('settitle').table
- settitle.help = '/settitle <text> - Sets the group\'s title to the given text. The given text must be between 1 and 255 characters in length.'
-end
-
-function settitle:on_message(message, configuration, language)
- if message.chat.type == 'private'
- then
- return mattata.send_reply(
- message,
- 'You can\'t use this command in private chat.'
- )
- elseif not mattata.is_group_admin(
- message.chat.id,
- message.from.id
- )
- then
- return mattata.send_reply(
- message,
- language['errors']['admin']
- )
- end
- local input = mattata.input(message.text)
- if not input
- or input:len() < 1
- or input:len() > 255
- then
- return mattata.send_reply(
- message,
- settitle.help
- )
- end
- local success = mattata.set_chat_title(
- message.chat.id,
- input
- )
- if not success
- then
- return mattata.send_reply(
- message,
- 'An error occured whilst trying to set the chat\'s title. Please ensure I have the required administrative permissions to perform this action, then try again.'
- )
- end
- return
-end
-
-return settitle
\ No newline at end of file
diff --git a/plugins/administration/setwelcome.lua b/plugins/administration/setwelcome.lua
deleted file mode 100644
index 425c2e1..0000000
--- a/plugins/administration/setwelcome.lua
+++ /dev/null
@@ -1,76 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local setwelcome = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function setwelcome:init()
- setwelcome.commands = mattata.commands(self.info.username):command('setwelcome').table
- setwelcome.help = '/setwelcome <text> - Sets the group\'s welcome message to the given, Markdown-formatted text. You can use placeholders to automatically customise the welcome message for each user. Use $user_id to insert the user\'s numerical ID, $chat_id to insert the chat\'s numerical ID, $name to insert the user\'s name, $title to insert the chat\'s title and $username to insert the user\'s username (if the user doesn\'t have an @username, their name will be used instead, so it is best to avoid using this in conjunction with $name).'
-end
-
-function setwelcome:on_message(message, configuration, language)
- if not mattata.is_group_admin(
- message.chat.id,
- message.from.id
- )
- then
- return mattata.send_reply(
- message,
- language['errors']['admin']
- )
- end
- local input = mattata.input(message.text)
- if not input
- then
- local success = mattata.send_force_reply(
- message,
- language['setwelcome']['1']
- )
- if success
- then
- redis:set(
- string.format(
- 'action:%s:%s',
- message.chat.id,
- success.result.message_id
- ),
- '/setwelcome'
- )
- end
- return
- end
- local validate = mattata.send_message(
- configuration.log_chat,
- input,
- 'markdown'
- )
- if not validate
- then
- return mattata.send_reply(
- message,
- language['setwelcome']['2']
- )
- end
- mattata.delete_message(
- configuration.log_chat,
- validate.result.message_id
- )
- redis:hset(
- 'chat:' .. message.chat.id .. ':info',
- 'welcome message',
- input
- )
- return mattata.send_message(
- message.chat.id,
- string.format(
- language['setwelcome']['3'],
- message.chat.title
- )
- )
-end
-
-return setwelcome
\ No newline at end of file
diff --git a/plugins/administration/staff.lua b/plugins/administration/staff.lua
deleted file mode 100644
index 3029f28..0000000
--- a/plugins/administration/staff.lua
+++ /dev/null
@@ -1,90 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local staff = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function staff:init()
- staff.commands = mattata.commands(self.info.username):command('staff'):command('admins').table
- staff.help = '/staff - Displays the staff members in the current chat. Alias: /admins.'
-end
-
-function staff.format_admin_list(output, chat_id)
- local creator = ''
- local admin_count = 1
- local admins = ''
- for _, admin in pairs(output.result) do
- local user
- local branch = ' ├ '
- if admin.status == 'creator' then
- creator = mattata.get_formatted_user(admin.user.id, admin.user.first_name, 'html')
- elseif admin.status == 'administrator' then
- user = mattata.get_formatted_user(admin.user.id, admin.user.first_name, 'html')
- admin_count = admin_count + 1
- if admin_count == #output.result then
- branch = ' └ '
- end
- admins = admins .. branch .. user .. '\n'
- end
- end
- local mod_list = redis:smembers('administration:' .. chat_id .. ':mods')
- local mod_count = 0
- local mods = ''
- if next(mod_list) then
- local branch = ' ├ '
- local user
- for i = 1, #mod_list do
- user = mattata.get_linked_name(mod_list[i])
- if user then
- if i == #mod_list then
- branch = ' └ '
- end
- mods = mods .. branch .. user .. '\n'
- mod_count = mod_count + 1
- end
- end
- end
- if creator == '' then
- creator = '-'
- end
- if admins == '' then
- admins = '-'
- end
- if mods == '' then
- mods = '-'
- end
- return string.format(
- '<b>👤 Creator</b>\n└ %s\n\n<b>👥 Admins</b> (%d)\n%s\n<b>👥 Moderators</b> (%d)\n%s',
- creator,
- admin_count - 1,
- admins,
- mod_count,
- mods
- )
-end
-
-function staff.on_message(_, message)
- local input = mattata.input(message.text)
- local chat_id = message.chat.id
- local success
- if input then
- local chat = mattata.get_chat(input)
- if not chat then
- return mattata.send_reply(message, 'That\'s not a valid chat.')
- end
- chat_id = chat.result.id
- success = mattata.get_chat_administrators(chat_id)
- else
- success = mattata.get_chat_administrators(message.chat.id)
- end
- if not success then
- local output = input and 'I wasn\'t able to get information about that chat\'s administrators.' or 'I couldn\'t get a list of administrators in this chat.'
- return mattata.send_reply(message, output)
- end
- return mattata.send_message(message.chat.id, staff.format_admin_list(success, chat_id), 'html')
-end
-
-return staff
\ No newline at end of file
diff --git a/plugins/administration/tempban.lua b/plugins/administration/tempban.lua
deleted file mode 100644
index 3a5b797..0000000
--- a/plugins/administration/tempban.lua
+++ /dev/null
@@ -1,79 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local tempban = {}
-local mattata = require('mattata')
-
-function tempban:init()
- tempban.commands = mattata.commands(self.info.username):command('tempban').table
- tempban.help = '/tempban [user] <length> - Temporarily bans a user from the current chat for the given length. The length should be in the format 1y2mo3w4d5h6m7s. Some natural language is supported too. Temp-bans must be a minimum of 60 seconds in length. This command can only be used by moderators and administrators of a supergroup.'
-end
-
-function tempban:on_message(message, configuration, language)
- if message.chat.type ~= 'supergroup' then
- local output = language['errors']['supergroup']
- return mattata.send_reply(message, output)
- elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
- local output = language['errors']['admin']
- return mattata.send_reply(message, output)
- end
- local user, until_date = false, false
- local input = mattata.input(message)
- if input:match('^@?[%w_]+ .-$') then
- user, until_date = input:match('^(@?[%w_]+) (.-)$')
- elseif input then
- until_date = input
- if message.reply then
- user = message.reply.from.id
- end
- end
- until_date = mattata.string_to_time(until_date, true)
- if until_date == false then
- return mattata.send_reply(message, 'You must specify a length when using this command! This should be in the format 1y2mo3w4d5h6m7s. Some natural language is supported too. Temp-ban must be a minimum of 60 seconds in length.')
- elseif not user then
- return mattata.send_reply(message, 'You must specify a user to temp-ban. This can be done by mention, reply or ID.')
- end
- until_date = os.time() + until_date
- local user_object = mattata.get_user(user) -- resolve the username/ID to a user object
- if not user_object then
- return mattata.send_reply(message, language.errors.unknown)
- elseif user_object.result.id == self.info.id then
- return false -- don't let the bot temp-ban itself
- end
- user_object = user_object.result
- local status = mattata.get_chat_member(message.chat.id, user_object.id)
- local is_admin = mattata.is_group_admin(message.chat.id, user_object.id)
- if not status then
- return mattata.send_reply(message, language.errors.generic)
- elseif is_admin then -- we won't try and tempban moderators and administrators.
- return mattata.send_reply(message, 'I can\'t temp-ban that user as they\'re an admin in this group!')
- elseif status.result.status == 'kicked' then -- check if the user has already been kicked
- return mattata.send_reply(message, 'I can\'t temp-ban that user as they\'re already been banned from this chat!')
- end
- local success = mattata.ban_chat_member(message.chat.id, user_object.id, until_date) -- attempt to temp-ban the user from the group
- if not success then
- return mattata.send_reply(message, 'I couldn\'t temp-ban that user! Please ensure I have the required permissions and try again!')
- end
- mattata.increase_administrative_action(message.chat.id, user_object.id, 'tempbans')
- local until_formatted = os.date('%c', until_date):gsub(' ', ' ') .. ' GMT +0'
- local admin_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
- local tempbanned_username = mattata.get_formatted_user(user_object.id, user_object.first_name, 'html')
- if mattata.get_setting(message.chat.id, 'log administrative actions') then
- local log_chat = mattata.get_log_chat(message.chat.id)
- local output = '%s <code>[%s]</code> has temp-banned %s <code>[%s]</code> from %s <code>[%s]</code> until %s.\n%s %s'
- output = string.format(output, admin_username, message.from.id, tempbanned_username, user_object.id, mattata.escape_html(message.chat.title), message.chat.id, until_formatted, '#chat' .. tostring(message.chat.id):gsub('^-100', ''), '#user' .. user_object.id)
- mattata.send_message(log_chat, output, 'html')
- else
- local output = '%s has temp-banned %s until %s.'
- output = string.format(output, admin_username, tempbanned_username, until_formatted)
- mattata.send_message(message.chat.id, output, 'html')
- end
- if message.reply and mattata.get_setting(message.chat.id, 'delete reply on action') then
- mattata.delete_message(message.chat.id, message.reply.message_id)
- end
- return
-end
-
-return tempban
\ No newline at end of file
diff --git a/plugins/administration/tempmute.lua b/plugins/administration/tempmute.lua
deleted file mode 100644
index 2dde0f7..0000000
--- a/plugins/administration/tempmute.lua
+++ /dev/null
@@ -1,85 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local tempmute = {}
-local mattata = require('mattata')
-
-function tempmute:init()
- tempmute.commands = mattata.commands(self.info.username):command('tempmute').table
- tempmute.help = '/tempmute [user] <length> - Temporarily mutes a user in the current chat for the given length. The length should be in the format 1y2mo3w4d5h6m7s. Some natural language is supported too. Temp-mutes must be a minimum of 60 seconds in length. This command can only be used by moderators and administrators of a supergroup.'
-end
-
-function tempmute:on_message(message, configuration, language)
- if message.chat.type ~= 'supergroup' then
- local output = language['errors']['supergroup']
- return mattata.send_reply(message, output)
- elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
- local output = language['errors']['admin']
- return mattata.send_reply(message, output)
- end
- local user, until_date = false, false
- local input = mattata.input(message)
- if input:match('^@?[%w_]+ .-$') then
- user, until_date = input:match('^(@?[%w_]+) (.-)$')
- elseif input then
- until_date = input
- if message.reply then
- user = message.reply.from.id
- end
- end
- until_date = mattata.string_to_time(until_date, true)
- if until_date == false then
- return mattata.send_reply(message, 'You must specify a length when using this command! This should be in the format 1y2mo3w4d5h6m7s. Some natural language is supported too. temp-mute must be a minimum of 60 seconds in length.')
- elseif not user then
- return mattata.send_reply(message, 'You must specify a user to temp-mute. This can be done by mention, reply or ID.')
- end
- until_date = os.time() + until_date
- local user_object = mattata.get_user(user) -- resolve the username/ID to a user object
- if not user_object then
- return mattata.send_reply(message, language.errors.unknown)
- elseif user_object.result.id == self.info.id then
- return false -- don't let the bot temp-mute itself
- end
- user_object = user_object.result
- local status = mattata.get_chat_member(message.chat.id, user_object.id)
- local is_admin = mattata.is_group_admin(message.chat.id, user_object.id)
- if not status then
- return mattata.send_reply(message, language.errors.generic)
- elseif is_admin then -- we won't try and tempmute moderators and administrators.
- return mattata.send_reply(message, 'I can\'t temp-mute that user as they\'re an admin in this group!')
- elseif status.result.status == 'kicked' then -- check if the user has already been kicked
- return mattata.send_reply(message, 'I can\'t temp-mute that user as they\'re already been banned from this chat!')
- end
- local bot_status = mattata.get_chat_member(message.chat.id, self.info.id)
- if not bot_status then
- return false
- elseif not bot_status.result.can_restrict_members then
- return mattata.send_reply(message, 'It appears I don\'t have the required permissions required in order to temp-mute that user. Please amend this and try again!')
- end
- local success = mattata.restrict_chat_member(message.chat.id, user_object.id, until_date, false, false, false, false, false, false, false, false) -- attempt to temp-mute the user in the group
- if not success then
- return mattata.send_reply(message, 'I couldn\'t temp-mute that user! Please ensure I have the required permissions and try again!')
- end
- mattata.increase_administrative_action(message.chat.id, user_object.id, 'tempmutes')
- local until_formatted = os.date('%c', until_date):gsub(' ', ' ') .. ' GMT +0'
- local admin_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
- local tempmuted_username = mattata.get_formatted_user(user_object.id, user_object.first_name, 'html')
- if mattata.get_setting(message.chat.id, 'log administrative actions') then
- local log_chat = mattata.get_log_chat(message.chat.id)
- local output = '%s <code>[%s]</code> has temp-muted %s <code>[%s]</code> from %s <code>[%s]</code> until %s.\n%s %s'
- output = string.format(output, admin_username, message.from.id, tempmuted_username, user_object.id, mattata.escape_html(message.chat.title), message.chat.id, until_formatted, '#chat' .. tostring(message.chat.id):gsub('^-100', ''), '#user' .. user_object.id)
- mattata.send_message(log_chat, output, 'html')
- else
- local output = '%s has temp-muted %s until %s.'
- output = string.format(output, admin_username, tempmuted_username, until_formatted)
- mattata.send_message(message.chat.id, output, 'html')
- end
- if message.reply and mattata.get_setting(message.chat.id, 'delete reply on action') then
- mattata.delete_message(message.chat.id, message.reply.message_id)
- end
- return
-end
-
-return tempmute
\ No newline at end of file
diff --git a/plugins/administration/triggers.lua b/plugins/administration/triggers.lua
deleted file mode 100644
index 98e1c37..0000000
--- a/plugins/administration/triggers.lua
+++ /dev/null
@@ -1,281 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local triggers = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function triggers:init()
- triggers.commands = mattata.commands(self.info.username):command('triggers'):command('trigger'):command('custom').table
- triggers.help = '/triggers - Allows admins to view and delete existing word triggers. Aliases: /trigger, /custom.'
-end
-
-function triggers:on_new_message(message)
- if message.command or message.is_media or self.is_ai then
- return false
- end
- local matches = redis:hgetall('triggers:' .. message.chat.id)
- if not next(matches) == 0 then
- return false
- end
- for trigger, value in pairs(matches) do
- if message.text:lower():match(trigger:lower()) then
- local trail
- if trigger:lower() == 'ayy' and value:lower() == 'lmao' then
- trail = message.text:lower():match('(ayy+)'):gsub('^ay', '')
- value = 'lma' .. string.rep('o', trail:len())
- elseif trigger:lower() == 'lmao' and value:lower() == 'ayy' then
- trail = message.text:lower():match('(lmao+)'):gsub('^lma', '')
- value = 'ay' .. string.rep('y', trail:len())
- end
- if value:len() > 4096 then
- value = value:sub(1, 4093) .. '...'
- end
- if value:match('%b{}') then
- for k, v in pairs(message.from) do
- if type(v) == 'string' then
- message.from[k] = v:gsub('%%', '%%%%')
- end
- end
- for k, v in pairs(message.chat) do
- if type(v) == 'string' then
- message.chat[k] = v:gsub('%%', '%%%%')
- end
- end
- local last_name = message.from.last_name or ''
- local username = message.from.username and '@' .. message.from.username or ''
- value = value:gsub('{name}', message.from.name):gsub('{firstname}', message.from.first_name):gsub('{userid}', message.from.id):gsub('{lastname}', last_name):gsub('{username}', username)
- if message.chat.type == 'supergroup' then
- value = value:gsub('{title}', message.chat.title):gsub('{chatid}', message.chat.id)
- local user_count = ''
- if value:match('{usercount}') then
- user_count = mattata.get_chat_members_count(message.chat.id).result
- end
- local invite_link = redis:hget('chat:' .. message.chat.id .. ':info', 'link') or ''
- local chat_username = message.chat.username and '@' .. message.chat.username or ''
- value = value:gsub('{usercount}', user_count):gsub('{invitelink}', invite_link):gsub('{chatusername}', chat_username)
- end
- end
- if not message.is_edited then
- local success = mattata.send_message(message.chat.id, value)
- if success then
- redis:set('bot:' .. message.chat.id .. ':' .. message.message_id, success.result.message_id)
- end
- return success
- else
- local message_id = redis:get('bot:' .. message.chat.id .. ':' .. message.message_id)
- if message_id then
- return mattata.edit_message_text(message.chat.id, message_id, value)
- end
- end
- end
- end
- return
-end
-
-function triggers.get_trigger(chat_id, trigger)
- local get = redis:hget('triggers:' .. chat_id, trigger)
- if not get then
- return 'This trigger doesn\'t exist!'
- end
- return get
-end
-
-function triggers.get_confirmation_keyboard(chat_id, trigger, page)
- if not redis:hget('triggers:' .. chat_id, trigger) then
- return false
- end
- return mattata.inline_keyboard():row(
- mattata.row()
- :callback_data_button(
- mattata.symbols.back .. ' Back',
- 'triggers:' .. chat_id .. ':back:' .. page
- )
- :callback_data_button(
- 'Delete',
- 'triggers:' .. chat_id .. ':delete:' .. trigger
- )
- )
-end
-
-function triggers.get_triggers(chat_id)
- local all = redis:hgetall('triggers:' .. chat_id)
- if not next(all) then
- return false
- end
- local output = {}
- for trigger, _ in pairs(all) do
- table.insert(output, trigger)
- end
- return output
-end
-
-function triggers.get_keyboard(chat_id, page, columns, per_page)
- page = page or 1
- local toggleable = triggers.get_triggers(chat_id)
- if not toggleable then
- return false
- end
- local page_count = math.floor(#toggleable / per_page)
- if page_count < #toggleable / per_page then
- page_count = page_count + 1
- end
- if page < 1 then
- page = page_count
- elseif page > page_count then
- page = 1
- end
- local start_res = (page * per_page) - (per_page - 1)
- local end_res = start_res + (per_page - 1)
- if end_res > #toggleable then
- end_res = #toggleable
- end
- local trigger_pos = 0
- local output = {}
- for _, v in pairs(toggleable) do
- trigger_pos = trigger_pos + 1
- if trigger_pos >= start_res and trigger_pos <= end_res then
- table.insert(output, v)
- end
- end
- local keyboard = {
- ['inline_keyboard'] = {
- {}
- }
- }
- local columns_per_page = math.floor(#output / columns)
- if columns_per_page < (#output / columns) then
- columns_per_page = columns_per_page + 1
- end
- local rows_per_page = math.floor(#output / columns_per_page)
- if rows_per_page < (#output / columns_per_page) then
- rows_per_page = rows_per_page + 1
- end
- local current_row = 1
- local count = 0
- for n in pairs(output) do
- count = count + 1
- if count == (rows_per_page * current_row) + 1 then
- current_row = current_row + 1
- table.insert(keyboard.inline_keyboard, {})
- end
- table.insert(keyboard.inline_keyboard[current_row], {
- ['text'] = output[n],
- ['callback_data'] = string.format(
- 'triggers:%s:%s:%s', chat_id,
- output[n], page
- )
- })
- end
- if page_count > 1 then
- table.insert(keyboard.inline_keyboard, {{
- ['text'] = mattata.symbols.back .. ' Previous',
- ['callback_data'] = string.format(
- 'triggers:%s:page:%s',
- chat_id,
- page - 1
- )
- }, {
- ['text'] = string.format(
- '%s/%s',
- page,
- page_count
- ),
- ['callback_data'] = 'triggers:nil'
- }, {
- ['text'] = 'Next ' .. mattata.symbols.next,
- ['callback_data'] = string.format(
- 'triggers:%s:page:%s',
- chat_id,
- page + 1
- )
- }})
- end
- if count <= 0 then
- return false
- end
- return keyboard
-end
-
-function triggers.on_callback_query(_, callback_query, message)
- if not callback_query.data:match('^.-:.-:.-$') then
- return
- end
- local chat_id, callback_type, page = callback_query.data:match('^(.-):(.-):(.-)$')
- if not mattata.is_group_admin(chat_id, callback_query.from.id) then
- return mattata.answer_callback_query(callback_query.id, 'You are not allowed to use this!')
- end
- if callback_type == 'back' or callback_type == 'page' then
- local success = mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- 'Please select a trigger:',
- nil, false,
- triggers.get_keyboard(
- chat_id,
- tonumber(page), 2, 10
- )
- )
- if not success then
- return mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- 'All triggers saved for this chat have already been deleted!'
- )
- end
- return mattata.answer_callback_query(callback_query.id)
- elseif callback_type == 'delete' then
- local all = redis:hgetall('triggers:' .. chat_id)
- if not next(all) then
- return mattata.answer_callback_query(callback_query.id, 'All triggers saved for this chat have already been deleted!')
- end
- local selected = all[page]
- if not selected then
- return mattata.answer_callback_query(callback_query.id, 'This trigger no longer exists!')
- end
- redis:hdel('triggers:' .. chat_id, page)
- return mattata.answer_callback_query(callback_query.id, 'That trigger has been deleted from my database!')
- elseif callback_type == 'back' then
- return mattata.edit_message_reply_markup(
- message.chat.id,
- message.message_id,
- nil,
- triggers.get_keyboard(
- chat_id,
- tonumber(page), 2, 10
- )
- )
- end
- local keyboard = triggers.get_confirmation_keyboard(
- chat_id,
- callback_type,
- page
- )
- local value = triggers.get_trigger(chat_id, callback_type)
- value = mattata.escape_html(value)
- local success = mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- '<b>' .. callback_type .. '</b> is set to trigger <em>' .. value .. '</em>', 'html', false,
- keyboard
- )
- if not success then
- return mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- 'All triggers saved for this chat have already been deleted!'
- )
- end
-end
-
-function triggers.on_message(_, message)
- local keyboard = triggers.get_keyboard(message.chat.id, 1, 2, 10)
- if not keyboard then
- return mattata.send_reply(message, 'This chat does\'t have any triggers saved in my database! Use /addtrigger <trigger> <value> to add one!')
- end
- return mattata.send_message(message.chat.id, 'Please select a trigger:', nil, true, false, nil, keyboard)
-end
-
-return triggers
\ No newline at end of file
diff --git a/plugins/administration/trust.lua b/plugins/administration/trust.lua
deleted file mode 100644
index db5065b..0000000
--- a/plugins/administration/trust.lua
+++ /dev/null
@@ -1,149 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local trust = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function trust:init()
- trust.commands = mattata.commands(self.info.username):command('trust').table
- trust.help = '/trust [user] - Promotes a user to a trusted user of the current chat. This command can only be used by administrators of a supergroup.'
-end
-
-function trust:on_message(message, configuration, language)
- if message.chat.type ~= 'supergroup'
- then
- return mattata.send_reply(
- message,
- language['errors']['supergroup']
- )
- elseif not mattata.is_group_admin(
- message.chat.id,
- message.from.id,
- true
- )
- then
- return mattata.send_reply(
- message,
- language['errors']['admin']
- )
- end
- local input = message.reply
- and tostring(message.reply.from.id)
- or mattata.input(message)
- if not input
- then
- return mattata.send_reply(
- message,
- trust.help
- )
- end
- if tonumber(input) == nil
- and not input:match('^%@')
- then
- input = '@' .. input
- end
- local user = mattata.get_user(input)
- or mattata.get_chat(input) -- Resolve the username/ID to a user object.
- if not user
- then
- return mattata.send_reply(
- message,
- language['errors']['unknown']
- )
- elseif user.result.id == self.info.id
- then
- return
- end
- user = user.result
- local status = mattata.get_chat_member(
- message.chat.id,
- user.id
- )
- if not status
- then
- return mattata.send_reply(
- message,
- language['errors']['generic']
- )
- elseif mattata.is_group_admin(
- message.chat.id,
- user.id
- )
- or status.result.status == 'creator'
- or status.result.status == 'administrator'
- then -- We won't try and trust moderators and administrators.
- return mattata.send_reply(
- message,
- language['trust']['1']
- )
- elseif status.result.status == 'left'
- or status.result.status == 'kicked'
- then -- Check if the user is in the group or not.
- return mattata.send_reply(
- message,
- status.result.status == 'left'
- and language['trust']['2']
- or language['trust']['3']
- )
- end
- redis:sadd(
- 'administration:' .. message.chat.id .. ':trusted',
- user.id
- )
- if redis:hget(
- string.format(
- 'chat:%s:settings',
- message.chat.id
- ),
- 'log administrative actions'
- )
- then
- mattata.send_message(
- mattata.get_log_chat(message.chat.id),
- string.format(
- '<pre>%s%s [%s] has trusted %s%s [%s] in %s%s [%s].</pre>',
- message.from.username
- and '@'
- or '',
- message.from.username
- or mattata.escape_html(message.from.first_name),
- message.from.id,
- user.username
- and '@'
- or '',
- user.username
- or mattata.escape_html(user.first_name),
- user.id,
- message.chat.username
- and '@'
- or '',
- message.chat.username
- or mattata.escape_html(message.chat.title),
- message.chat.id
- ),
- 'html'
- )
- end
- return mattata.send_message(
- message.chat.id,
- string.format(
- '<pre>%s%s has trusted %s%s.</pre>',
- message.from.username
- and '@'
- or '',
- message.from.username
- or mattata.escape_html(message.from.first_name),
- user.username
- and '@'
- or '',
- user.username
- or mattata.escape_html(user.first_name)
- ),
- 'html'
- )
-end
-
-return trust
\ No newline at end of file
diff --git a/plugins/administration/unban.lua b/plugins/administration/unban.lua
deleted file mode 100644
index de383be..0000000
--- a/plugins/administration/unban.lua
+++ /dev/null
@@ -1,88 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local unban = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function unban:init()
- unban.commands = mattata.commands(self.info.username):command('unban').table
- unban.help = '/unban [user] - Unbans a user from the current chat. This command can only be used by moderators and administrators of a supergroup.'
-end
-
-function unban:on_message(message, _, language)
- if message.chat.type ~= 'supergroup' then
- return mattata.send_reply(message, language['errors']['supergroup'])
- elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
- return mattata.send_reply(message, language['errors']['admin'])
- end
- local reason = false
- local user = false
- local input = mattata.input(message)
- -- Check the message object for any users this command
- -- is intended to be executed on.
- if message.reply then
- user = message.reply.from.id
- if input then
- reason = input
- end
- elseif input and input:match(' ') then
- user, reason = input:match('^(.-) (.-)$')
- elseif input then
- user = input
- end
- if not user then
- local output = 'Which user would you like me to unban? You can specify this user by their @username or numerical ID.'
- local success = mattata.send_force_reply(message, output)
- if success then
- redis:set('action:' .. message.chat.id .. ':' .. success.result.message_id, '/unban')
- end
- return
- end
- if tonumber(user) == nil and not user:match('^%@') then
- user = '@' .. user
- end
- user = mattata.get_user(user) -- Resolve the username/ID to a user object.
- if not user then
- return mattata.send_reply(message, language['errors']['unknown'])
- elseif user.result.id == self.info.id then
- return
- end
- user = user.result
- local status = mattata.get_chat_member(message.chat.id, user.id)
- if not status then
- return mattata.send_reply(message, language['errors']['generic'])
- elseif status.result.status == 'creator' or status.result.status == 'administrator' then -- We won't try and unban administrators.
- return mattata.send_reply(message, 'I cannot unban this user because they are a moderator or an administrator in this chat.')
- elseif status.result.status == 'member' then -- Check if the user is in the group or not.
- return mattata.send_reply(message, 'I cannot unban this user because they are still in this chat.')
- end
- local success = mattata.unban_chat_member(message.chat.id, user.id) -- Attempt to unban the user from the group.
- if not success then -- Since we've ruled everything else out, it's safe to say if it wasn't a success then the bot isn't
- -- an administrator in the group.
- local output = 'I need to have administrative permissions in order to unban this user. Please amend this issue, and try again.'
- return mattata.send_reply(message, output)
- end
- mattata.increase_administrative_action(message.chat.id, user.id, 'unbans')
- reason = reason and ', for ' .. reason or ''
- local admin_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
- local unbanned_username = mattata.get_formatted_user(user.id, user.first_name, 'html')
- if mattata.get_setting(message.chat.id, 'log administrative actions') then
- local log_chat = mattata.get_log_chat(message.chat.id)
- local output = '%s <code>[%s]</code> has unbanned %s <code>[%s]</code> from %s <code>[%s]</code>%s.\n%s %s'
- output = string.format(output, admin_username, message.from.id, unbanned_username, user.id, mattata.escape_html(message.chat.title), message.chat.id, reason, '#chat' .. tostring(message.chat.id):gsub('^-100', ''), '#user' .. user.id)
- mattata.send_message(log_chat, output, 'html')
- else
- local output = '%s has unbanned %s%s.'
- output = string.format(output, admin_username, unbanned_username, reason)
- mattata.send_message(message.chat.id, output, 'html')
- end
- if message.reply and mattata.get_setting(message.chat.id, 'delete reply on action') then
- mattata.delete_message(message.chat.id, message.reply.message_id)
- end
- return mattata.delete_message(message.chat.id, message.message_id)
-end
-
-return unban
\ No newline at end of file
diff --git a/plugins/administration/unbanpack.lua b/plugins/administration/unbanpack.lua
deleted file mode 100644
index 0f3f216..0000000
--- a/plugins/administration/unbanpack.lua
+++ /dev/null
@@ -1,43 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local unbanpack = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function unbanpack:init()
- unbanpack.commands = mattata.commands(self.info.username):command('unbanpack'):command('ubp').table
- unbanpack.help = '/unbanpack - Unbans the replied-to sticker\'s pack. This command can only be used by moderators and administrators of a supergroup. Alias: /ubp.'
-end
-
-
-function unbanpack:on_message(message, _, language)
- if message.chat.type ~= 'supergroup' then
- return mattata.send_reply(message, language.errors.supergroup)
- elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
- return mattata.send_reply(message, language.errors.admin)
- elseif not message.reply then
- return mattata.send_reply(message, 'Please reply to a sticker from the sticker set you\'d like to unban.')
- elseif not message.reply.sticker then
- return mattata.send_reply(message, 'You must use this command in reply to a sticker!')
- elseif not message.reply.sticker.set_name then
- return mattata.send_reply(message, 'That sticker isn\'t from a set, it\'s just a file - I\'m afraid I can\'t unban that!')
- end
- local set_name = message.reply.sticker.set_name
- if not redis:sismember('banned_sticker_packs:' .. message.chat.id, set_name) then
- mattata.send_reply(message, 'That [sticker pack](https://t.me/addstickers/' .. set_name .. ') isn\'t currently banned in this chat! To ban it, send /banpack in reply to one of the stickers from it!', true, true)
- end
- redis:srem('banned_sticker_packs:' .. message.chat.id, set_name)
- if mattata.get_setting(message.chat.id, 'log administrative actions') then
- local log_chat = mattata.get_log_chat(message.chat.id)
- local output = '%s <code>[%s]</code> has unbanned the sticker pack <a href="https://t.me/addstickers/%s">%s</a> in %s <code>[%s]</code>.\n#chat%s #user%s'
- local admin = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
- output = string.format(output, admin, message.from.id, set_name, set_name, mattata.escape_html(message.chat.title), message.chat.id, tostring(message.chat.id):gsub('^%-100', ''), message.from.id)
- mattata.send_message(log_chat, output, 'html')
- end
- return mattata.send_reply(message, 'I\'ve successfully unbanned [that sticker pack](https://t.me/addstickers/' .. set_name .. ') in this chat!', true, true)
-end
-
-return unbanpack
\ No newline at end of file
diff --git a/plugins/administration/unfban.lua b/plugins/administration/unfban.lua
deleted file mode 100644
index 434430b..0000000
--- a/plugins/administration/unfban.lua
+++ /dev/null
@@ -1,119 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local unfban = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function unfban:init()
- unfban.commands = mattata.commands(self.info.username):command('unfban'):command('unfedban'):command('ufb').table
- unfban.help = '/unfban [user] - Unbans a user from the current chat and the Fed the group is part of. This command can only be used by Fed admins. Aliases: /unfedban, /ufb.'
-end
-
-function unfban:on_message(message, configuration, language)
- if message.chat.type ~= 'supergroup' then
- local output = language['errors']['supergroup']
- return mattata.send_reply(message, output)
- end
- local fed_ids = mattata.get_feds(message.chat.id)
- if #fed_ids == 0 then
- return mattata.send_reply(message, 'This group isn\'t part of a fed. Ask a group admin to join one!')
- end
- local is_admin_feds = {}
- for _, fed in pairs(fed_ids) do
- if mattata.is_fed_admin(fed, message.from.id) then
- table.insert(is_admin_feds, fed)
- end
- end
- if #is_admin_feds == 0 then
- return mattata.send_reply(message, 'You need to be a Fed admin in at least one of this group\'s Feds in order to be able to use this command!')
- end
- local reason = false
- local user = false
- local input = mattata.input(message)
- -- check the message object for any users this command
- -- is intended to be executed on
- if message.reply then
- user = message.reply.from.id
- if input then
- reason = input
- end
- elseif input and input:match(' ') then
- user, reason = input:match('^(.-) (.-)$')
- elseif input then
- user = input
- end
- if not user then
- local output = language['fban']['1']
- local success = mattata.send_force_reply(message, output)
- if success then
- mattata.set_command_action(message.chat.id, success.result.message_id, '/unfban')
- end
- return
- end
- if reason and type(reason) == 'string' and reason:match('^[Ff][Oo][Rr] ') then
- reason = reason:match('^[Ff][Oo][Rr] (.-)$')
- end
- if tonumber(user) == nil and not user:match('^%@') then
- user = '@' .. user
- end
- local user_object = mattata.get_user(user) or mattata.get_chat(user) -- resolve the username/ID to a user object
- if not user_object then
- local output = language['errors']['unknown']
- return mattata.send_reply(message, output)
- elseif user_object.result.id == self.info.id then
- return false -- don't let the bot Fed-ban itself
- end
- user_object = user_object.result
- local status = mattata.get_chat_member(message.chat.id, user_object.id)
- local is_admin = mattata.is_group_admin(message.chat.id, user_object.id)
- if not status then
- local output = language['errors']['generic']
- return mattata.send_reply(message, output)
- elseif is_admin then -- we won't try and Fed-ban moderators and administrators.
- local output = 'I can\'t unban that user from the Fed because they\'re an admin in one of the groups!'
- return mattata.send_reply(message, output)
- end
- local success = mattata.fed_unban_chat_member(message.chat.id, user_object.id, is_admin_feds) -- attempt to Fed-ban the user from the group
- if not success then
- mattata.send_reply(message, 'I couldn\'t unban that user in this group, because it appears I don\'t have permission to! I have still removed them from the Fed-ban list(s) though!')
- end
- for _, fed in pairs(is_admin_feds) do
- mattata.increase_administrative_action(message.chat.id, user_object.id, 'unfbans')
- redis:hdel('fedban:' .. fed .. ':' .. user_object.id, 'banned_by')
- redis:hdel('fedban:' .. fed .. ':' .. user_object.id, 'time')
- redis:hdel('fedban:' .. fed .. ':' .. user_object.id, 'reason')
- redis:srem('fedbans:' ..fed, tonumber(user_object.id))
- end
- reason = reason and ', for ' .. reason or ''
- local admin_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
- local unbanned_username = mattata.get_formatted_user(user_object.id, user_object.first_name, 'html')
- if mattata.get_setting(message.chat.id, 'log administrative actions') then
- local log_chat = mattata.get_log_chat(message.chat.id)
- local output = '%s <code>[%s]</code> has Fed-unbanned %s <code>[%s]</code> from %s <code>[%s]</code>%s.\n%s %s'
- if #is_admin_feds > 1 then
- output = '%s <code>[%s]</code> has Fed-unbanned %s <code>[%s]</code> from %s in the following Feds:<pre>%s</pre>\n%s %s'
- output = string.format(output, admin_username, message.from.id, unbanned_username, user_object.id, mattata.escape_html(message.chat.title), table.concat(is_admin_feds, '\n'), '#chat' .. tostring(message.chat.id):gsub('^-100', ''), '#user' .. user_object.id)
- else
- output = string.format(output, admin_username, message.from.id, unbanned_username, user_object.id, mattata.escape_html(message.chat.title), message.chat.id, reason, '#chat' .. tostring(message.chat.id):gsub('^-100', ''), '#user' .. user_object.id)
- end
- mattata.send_message(log_chat, output, 'html')
- else
- local output = '%s has Fed-unbanned %s%s.'
- if #is_admin_feds > 1 then
- output = '%s has Fed-unbanned %s%s; in the following Feds:<pre>%s</pre>'
- output = string.format(output, admin_username, unbanned_username, reason, table.concat(is_admin_feds, '\n'))
- else
- output = string.format(output, admin_username, unbanned_username, reason)
- end
- mattata.send_message(message.chat.id, output, 'html')
- end
- if message.reply and mattata.get_setting(message.chat.id, 'delete reply on action') then
- mattata.delete_message(message.chat.id, message.reply.message_id)
- end
- return mattata.delete_message(message.chat.id, message.message_id)
-end
-
-return unfban
\ No newline at end of file
diff --git a/plugins/administration/unfilter.lua b/plugins/administration/unfilter.lua
deleted file mode 100644
index 8c57032..0000000
--- a/plugins/administration/unfilter.lua
+++ /dev/null
@@ -1,79 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local unfilter = {}
-local mattata = require('mattata')
-local json = require('dkjson')
-local redis = require('libs.redis')
-
-function unfilter:init()
- unfilter.commands = mattata.commands(self.info.username):command('unfilter').table
- unfilter.help = '/unfilter <words> - Remove words from this chat\'s word filter.'
-end
-
-function unfilter:on_message(message, configuration, language)
- if message.chat.type ~= 'supergroup'
- then
- return mattata.send_reply(
- message,
- language['errors']['supergroup']
- )
- elseif not mattata.is_group_admin(
- message.chat.id,
- message.from.id
- )
- then
- return mattata.send_reply(
- message,
- language['errors']['admin']
- )
- end
- local input = mattata.input(message.text)
- if not input
- or not input:match('%w+')
- then
- return mattata.send_reply(
- message,
- unfilter.help
- )
- end
- local words = {}
- for word in input:gmatch('%w+')
- do
- table.insert(
- words,
- word
- )
- end
- local total = redis:smembers('word_filter:' .. message.chat.id)
- local removed = {}
- for n, word in pairs(words)
- do
- if redis:sismember(
- 'word_filter:' .. message.chat.id,
- word
- )
- then
- local success = redis:srem(
- 'word_filter:' .. message.chat.id,
- word
- )
- if success == 1
- then
- table.insert(
- removed,
- word
- )
- end
- end
- end
- local new_total = #total - #removed
- return mattata.send_message(
- message.chat.id,
- tostring(#removed) .. ' word(s) have been removed from this chat\'s word filter. There is now a total of ' .. tostring(new_total) .. ' word(s) filtered in this chat. Use /filter <words> to add words to this filter.'
- )
-end
-
-return unfilter
\ No newline at end of file
diff --git a/plugins/administration/unmute.lua b/plugins/administration/unmute.lua
deleted file mode 100644
index 4f6fc07..0000000
--- a/plugins/administration/unmute.lua
+++ /dev/null
@@ -1,102 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local unmute = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function unmute:init()
- unmute.commands = mattata.commands(self.info.username):command('unmute').table
- unmute.help = '/unmute [user] - Unmutes a user in the current chat. This command can only be used by group admins.'
-end
-
-function unmute:on_message(message, _, language)
- if message.chat.type ~= 'supergroup' then
- local output = language['errors']['supergroup']
- return mattata.send_reply(message, output)
- end
- local reason = false
- local user = false
- local input = mattata.input(message)
- -- check the message object for any users this command
- -- is intended to be executed on
- if message.reply then
- user = message.reply.from.id
- if input then
- reason = input
- end
- elseif input and input:match(' ') then
- user, reason = input:match('^(.-) (.-)$')
- elseif input then
- user = input
- end
- if not user then
- local output = 'You need to specify the user you\'d like to unmute, either by username/ID or in reply.'
- local success = mattata.send_force_reply(message, output)
- if success then
- mattata.set_command_action(message.chat.id, success.result.message_id, '/unmute')
- end
- return
- end
- if reason and type(reason) == 'string' and reason:match('^[Ff][Oo][Rr] ') then
- reason = reason:match('^[Ff][Oo][Rr] (.-)$')
- end
- if tonumber(user) == nil and not user:match('^%@') then
- user = '@' .. user
- end
- local user_object = mattata.get_user(user) or mattata.get_chat(user) -- resolve the username/ID to a user object
- if not user_object then
- local output = language['errors']['unknown']
- return mattata.send_reply(message, output)
- elseif user_object.result.id == self.info.id then
- return false -- we don't want to use this on ourselves
- end
- local bot_status = mattata.get_chat_member(message.chat.id, self.info.id)
- if not bot_status then
- return false
- elseif not bot_status.result.can_restrict_members then
- return mattata.send_reply(message, 'It appears I don\'t have the required permissions required in order to unmute that user. Please amend this and try again!')
- end
- user_object = user_object.result
- local status = mattata.get_chat_member(message.chat.id, user_object.id)
- local is_admin = mattata.is_group_admin(message.chat.id, user_object.id)
- if not status then
- return mattata.send_reply(message, 'I couldn\'t retrieve any information about that user!')
- elseif is_admin then -- we won't try and unmute moderators and administrators.
- return mattata.send_reply(message, 'I can\'t unmute that user because they\'re an admin in this chat!')
- end
- local default_permissions = mattata.get_chat(message.chat.id)
- if not default_permissions then
- return mattata.send_reply(message, 'I couldn\'t get the default permissions for this group!')
- end
- default_permissions = default_permissions.result.permissions or {
- ['can_send_messages'] = true,
- ['can_send_media_messages'] = true,
- ['can_send_other_messages'] = true,
- ['can_send_web_page_previews'] = true
- }
- local success = mattata.restrict_chat_member(message.chat.id, user_object.id, os.time(), default_permissions) -- attempt to unmute the user in the group, restoring the user to the original group permissions
- if not success then
- return mattata.send_reply(message, 'I couldn\'t unmute that user in this group, because it appears I don\'t have permission to!')
- end
- reason = reason and ', for ' .. reason or ''
- local admin_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
- local unmuted_username = mattata.get_formatted_user(user_object.id, user_object.first_name, 'html')
- redis:hincrby('chat:' .. message.chat.id .. ':' .. user_object.id, 'unmutes', 1)
- if mattata.get_setting(message.chat.id, 'log administrative actions') then
- local log_chat = mattata.get_log_chat(message.chat.id)
- local output = '%s <code>[%s]</code> has unmuted %s <code>[%s]</code> in %s <code>[%s]</code>%s.'
- output = string.format(output, admin_username, message.from.id, unmuted_username, user_object.id, mattata.escape_html(message.chat.title), message.chat.id, reason)
- mattata.send_message(log_chat, output, 'html')
- end
- if message.reply and mattata.get_setting(message.chat.id, 'delete reply on action') then
- mattata.delete_message(message.chat.id, message.reply.message_id)
- end
- local output = '%s has unmuted %s%s.'
- output = string.format(output, admin_username, unmuted_username, reason)
- return mattata.send_message(message.chat.id, output, 'html')
-end
-
-return unmute
\ No newline at end of file
diff --git a/plugins/administration/untrust.lua b/plugins/administration/untrust.lua
deleted file mode 100644
index fc7a655..0000000
--- a/plugins/administration/untrust.lua
+++ /dev/null
@@ -1,160 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local untrust = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function untrust:init()
- untrust.commands = mattata.commands(self.info.username):command('untrust').table
- untrust.help = '/untrust [user] - Untrusts a user to a standard user of the current chat. This command can only be used by administrators of a supergroup.'
-end
-
-function untrust:on_message(message, configuration, language)
- if message.chat.type ~= 'supergroup'
- then
- return mattata.send_reply(
- message,
- language['errors']['supergroup']
- )
- elseif not mattata.is_group_admin(
- message.chat.id,
- message.from.id,
- true
- )
- then
- return mattata.send_reply(
- message,
- language['errors']['admin']
- )
- end
- local input = message.reply
- and tostring(message.reply.from.id)
- or mattata.input(message)
- if not input
- then
- local success = mattata.send_force_reply(
- message,
- language['untrust']['1']
- )
- if success
- then
- redis:set(
- string.format(
- 'action:%s:%s',
- message.chat.id,
- success.result.message_id
- ),
- '/untrust'
- )
- end
- return
- elseif tonumber(input) == nil
- and not input:match('^%@')
- then
- input = '@' .. input
- end
- local user = mattata.get_user(input)
- or mattata.get_chat(input) -- Resolve the username/ID to a user object.
- if not user
- then
- return mattata.send_reply(
- message,
- language['errors']['unknown']
- )
- elseif user.result.id == self.info.id
- then
- return
- end
- user = user.result
- local status = mattata.get_chat_member(
- message.chat.id,
- user.id
- )
- if not status
- then
- return mattata.send_reply(
- message,
- language['errors']['generic']
- )
- elseif mattata.is_group_admin(
- message.chat.id,
- user.id
- )
- then -- We won't try and untrust users who are moderators/administrators.
- return mattata.send_reply(
- message,
- language['untrust']['2']
- )
- elseif status.result.status == 'left'
- or status.result.status == 'kicked'
- then -- Check if the user is in the group or not.
- return mattata.send_reply(
- message,
- string.format(
- status.result.status == 'left'
- and language['untrust']['3']
- or language['untrust']['4']
- )
- )
- end
- redis:srem(
- 'administration:' .. message.chat.id .. ':trusted',
- user.id
- )
- if redis:hget(
- string.format(
- 'chat:%s:settings',
- message.chat.id
- ),
- 'log administrative actions'
- )
- then
- mattata.send_message(
- mattata.get_log_chat(message.chat.id),
- string.format(
- '<pre>%s%s [%s] has untrusted %s%s [%s] in %s%s [%s].</pre>',
- message.from.username
- and '@'
- or '',
- message.from.username
- or mattata.escape_html(message.from.first_name),
- message.from.id,
- user.username
- and '@'
- or '',
- user.username
- or mattata.escape_html(user.first_name),
- user.id,
- message.chat.username
- and '@'
- or '',
- message.chat.username
- or mattata.escape_html(message.chat.title),
- message.chat.id
- ),
- 'html'
- )
- end
- return mattata.send_message(
- message.chat.id,
- string.format(
- '<pre>%s%s has untrusted %s%s.</pre>',
- message.from.username
- and '@'
- or '',
- message.from.username
- or mattata.escape_html(message.from.first_name),
- user.username
- and '@'
- or '',
- user.username
- or mattata.escape_html(user.first_name)
- ),
- 'html'
- )
-end
-
-return untrust
\ No newline at end of file
diff --git a/plugins/administration/warn.lua b/plugins/administration/warn.lua
deleted file mode 100644
index a1ce846..0000000
--- a/plugins/administration/warn.lua
+++ /dev/null
@@ -1,270 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local warn = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function warn:init()
- warn.commands = mattata.commands(self.info.username):command('warn').table
- warn.help = '/warn [user] - Warns a user in the current chat. This command can only be used by moderators and administrators of a supergroup. Once a user has reached the maximum allowed number of warnings allowed in the chat, the configured action for the chat is performed on them.'
-end
-
-function warn.on_callback_query(_, callback_query, message, configuration)
- if not callback_query
- or not callback_query.data
- or not callback_query.data:match('^%a+%:%-%d+%:%d+$')
- then
- return
- elseif not mattata.is_group_admin(
- callback_query.data:match('^%a+%:(%-%d+)%:%d+$'),
- callback_query.from.id
- )
- then
- return mattata.answer_callback_query(
- callback_query.id,
- configuration.errors.admin
- )
- elseif callback_query.data:match('^reset%:%-%d+%:%d+$')
- then
- local chat_id, user_id = callback_query.data:match('^reset%:(%-%d+)%:(%d+)$')
- redis:hdel(
- string.format(
- 'chat:%s:%s',
- chat_id,
- user_id
- ),
- 'warnings'
- )
- return mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- string.format(
- '<pre>Warnings reset by %s%s!</pre>',
- callback_query.from.username
- and '@'
- or '',
- callback_query.from.username
- or mattata.escape_html(callback_query.from.first_name)
- ),
- 'html'
- )
- elseif callback_query.data:match('^remove%:%-%d+%:%d+$')
- then
- local chat_id, user_id = callback_query.data:match('^remove%:(%-%d+)%:(%d+)$')
- local amount = redis:hincrby(
- string.format(
- 'chat:%s:%s',
- chat_id,
- user_id
- ),
- 'warnings',
- -1
- )
- if tonumber(amount) < 0
- then
- redis:hincrby(
- string.format(
- 'chat:%s:%s',
- chat_id,
- user_id
- ),
- 'warnings',
- 1
- )
- return mattata.answer_callback_query(
- callback_query.id,
- 'This user hasn\'t got any warnings to be removed!'
- )
- end
- return mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- string.format(
- '<pre>Warning removed by %s%s! [%s/%s]</pre>',
- callback_query.from.username
- and '@'
- or '',
- callback_query.from.username
- or mattata.escape_html(callback_query.from.first_name),
- redis:hget(
- string.format(
- 'chat:%s:%s',
- chat_id,
- user_id
- ),
- 'warnings'
- ),
- redis:hget(
- string.format(
- 'chat:%s:settings',
- chat_id
- ),
- 'max warnings'
- )
- or 3
- ),
- 'html'
- )
- end
-end
-
-function warn:on_message(message, _, language)
- if message.chat.type ~= 'supergroup'
- then
- return mattata.send_reply(
- message,
- language['errors']['supergroup']
- )
- elseif not mattata.is_group_admin(
- message.chat.id,
- message.from.id
- )
- then
- return mattata.send_reply(
- message,
- language['errors']['admin']
- )
- end
- local reason = false
- local input = message.reply
- and tostring(message.reply.from.id)
- or mattata.input(message)
- if not input
- then
- return mattata.send_reply(
- message,
- warn.help
- )
- elseif not message.reply
- and input:match('^%@?%w+ ')
- then
- input, reason = input:match('^(%@?%w+) (.-)$')
- elseif mattata.input(message.text)
- then
- reason = mattata.input(message.text)
- end
- if tonumber(input) == nil
- and not input:match('^%@')
- then
- input = '@' .. input
- end
- local user = mattata.get_user(input)
- or mattata.get_chat(input) -- Resolve the username/ID to a user object.
- if not user
- then
- return mattata.send_reply(
- message,
- language['errors']['unknown']
- )
- elseif user.result.id == self.info.id
- then
- return
- end
- user = user.result
- local status = mattata.get_chat_member(
- message.chat.id,
- user.id
- )
- if not status
- then
- return mattata.send_reply(
- message,
- language['errors']['generic']
- )
- elseif mattata.is_group_admin(
- message.chat.id,
- user.id
- ) or status.result.status == 'creator'
- or status.result.status == 'administrator'
- then -- We won't try and warn moderators and administrators.
- return mattata.send_reply(
- message,
- 'I cannot warn this user because they are a moderator or an administrator in this chat.'
- )
- elseif status.result.status == 'left'
- or status.result.status == 'kicked'
- then -- Check if the user is in the group or not.
- return mattata.send_reply(
- message,
- string.format(
- 'I cannot warn this user because they have already %s this chat.',
- (
- status.result.status == 'left'
- and 'left'
- )
- or 'been kicked from'
- )
- )
- end
- local amount = redis:hincrby(
- string.format(
- 'chat:%s:%s',
- message.chat.id,
- user.id
- ),
- 'warnings',
- 1
- )
- local maximum = redis:hget(
- string.format(
- 'chat:%s:settings',
- message.chat.id
- ),
- 'max warnings'
- )
- or 3
- if tonumber(amount) >= tonumber(maximum)
- then
- local success = mattata.ban_chat_member(
- message.chat.id,
- user.id
- )
- if not success
- then -- Since we've ruled everything else out, it's safe to say if it wasn't a
- -- success then the bot isn't an administrator in the group.
- return mattata.send_reply(
- message,
- 'I need to have administrative permissions in order to ban this user. Please amend this issue, and try again.'
- )
- end
- end
- mattata.increase_administrative_action(message.chat.id, user.id, 'warns')
- reason = reason and ', for ' .. reason:gsub('^for ', '') or ''
- local admin_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
- local warned_username = mattata.get_formatted_user(user.id, user.first_name, 'html')
- if mattata.get_setting(message.chat.id, 'log administrative actions') then
- local log_chat = mattata.get_log_chat(message.chat.id)
- local output = '%s <code>[%s]</code> has warned %s <code>[%s]</code> in %s <code>[%s]</code>%s.\n%s %s'
- output = string.format(output, admin_username, message.from.id, warned_username, user.id, mattata.escape_html(message.chat.title), message.chat.id, reason, '#chat' .. tostring(message.chat.id):gsub('^-100', ''), '#user' .. user.id)
- mattata.send_message(log_chat, output, 'html')
- end
- if message.reply and mattata.get_setting(message.chat.id, 'delete reply on action') then
- mattata.delete_message(message.chat.id, message.reply.message_id)
- mattata.delete_message(message.chat.id, message.message_id)
- end
- local output = '%s has warned %s%s.'
- output = string.format(output, admin_username, warned_username, reason)
- local keyboard = mattata.inline_keyboard():row(
- mattata.row():callback_data_button(
- 'Reset Warnings',
- string.format(
- 'warn:reset:%s:%s',
- message.chat.id,
- user.id
- )
- ):callback_data_button(
- 'Remove 1 Warning',
- string.format(
- 'warn:remove:%s:%s',
- message.chat.id,
- user.id
- )
- )
- )
- return mattata.send_message(message.chat.id, output, 'html', true, false, nil, keyboard)
-end
-
-return warn
\ No newline at end of file
diff --git a/plugins/administration/wordfilter.lua b/plugins/administration/wordfilter.lua
deleted file mode 100644
index b85d774..0000000
--- a/plugins/administration/wordfilter.lua
+++ /dev/null
@@ -1,87 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local wordfilter = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function wordfilter:init()
- wordfilter.commands = mattata.commands(self.info.username):command('wordfilter').table
- wordfilter.help = '/wordfilter - View a list of words which have been added to the chat\'s word filter.'
- wordfilter.bytes = {
- ['a'] = { 197, 229, 506, 507, 7680, 7681, 7834, 258, 259, 7862, 7863, 7854, 7855, 7856, 7857, 7858, 7859, 7860, 7861, 514, 515, 194, 226, 7852, 7853, 7844, 7845, 7846, 7847, 7850, 7851, 7848, 7849, 7842, 7843, 461, 462, 570, 11365, 550, 551, 480, 481, 7840, 7841, 196, 228, 478, 479, 192, 224, 512, 513, 193, 225, 256, 257, 256, 257, 195, 227, 260, 261, 260, 261, 260, 261, 7567, 65313, 65345 },
- ['b'] = { 7682, 7683, 7684, 7685, 7686, 7687, 579, 384, 7532, 7552, 385, 595, 386, 387, 65314, 65346 },
- ['c'] = { 231, 199, 231, 231, 269, 268, 269, 269, 265, 264, 263, 262, 7689, 7688, 267, 266, 572, 571, 42899, 42898, 65315, 65347 },
- ['d'] = { 271, 270, 273, 272, 396, 545, 7691, 7690, 7693, 7695, 7697, 7699, 598, 393, 599, 394, 240, 208, 240, 65316, 65348 },
- ['e'] = { 275, 274, 233, 201, 233, 283, 282, 283, 232, 200, 232, 517, 234, 202, 281, 280, 281, 235, 203, 279, 278, 7865, 7864, 7869, 7868, 277, 519, 553, 281, 7701, 7703, 7702, 7705, 7707, 7709, 279, 234, 234, 7867, 7866, 7875, 7874, 7873, 7877, 7876, 7871, 7870, 7879, 7878, 7865, 7864, 7865, 7864, 65317, 65349 },
- ['f'] = { 402, 401, 7711, 7710, 64256, 64257, 64258, 64259, 64260, 65318, 65350 },
- ['g'] = { 501, 500, 289, 288, 285, 284, 487, 486, 287, 286, 291, 290, 485, 484, 8513, 8370, 8458, 65319, 65351 },
- ['h'] = { 543, 542, 293, 292, 295, 294, 7721, 7720, 7723, 7722, 7830, 7715, 7714, 7717, 7716, 7718, 7719, 405, 502, 11368, 11367, 11382, 11381, 65320, 65352 },
- ['i'] = { 305, 299, 298, 237, 205, 464, 463, 301, 300, 236, 204, 238, 206, 304, 303, 302, 239, 207, 7726, 7727, 237, 205, 236, 204, 297, 296, 7881, 7880, 7883, 7882, 65321, 65353 },
- ['j'] = { 308, 309, 65322, 65354 },
- ['k'] = { 1050, 1082, 1036, 1116, 1178, 1179, 1180, 1181, 1082, 11277, 11325, 922, 954, 954, 922, 1008, 65323, 65355 },
- ['l'] = { 314, 313, 317, 7737, 7736, 7735, 7734, 318, 321, 322, 573, 410, 42825, 65324, 65356 },
- ['m'] = { 7743, 7745, 7747, 7535, 65325, 65357 },
- ['n'] = { 241, 209, 324, 326, 328, 626, 331, 414, 505, 565, 627, 7749, 7751, 7753, 7755, 65326, 65358 },
- ['o'] = { 9386, 9438, 9412, 65327, 65359, 8338, 7439, 7441, 7484, 7506, 333, 332, 333, 332, 7763, 7762, 699, 243, 211, 243, 466, 465, 242, 210, 244, 212, 246, 214, 245, 213, 337, 336, 7763, 248, 216, 42827, 42826, 491, 490, 491, 490, 561, 560, 7759, 7758, 559, 558, 42829, 42828, 7887, 7886, 244, 212, 7891, 7890, 7893, 7892, 7895, 7894, 7889, 7888, 7897, 7896, 417, 416, 7901, 7900, 7903, 7902, 7905, 7904, 7899, 7898, 7907, 7906, 7885, 7884, 7885, 7884, 7885, 7884, 42805, 42804, 7444, 339, 338, 630, 42831, 42830, 546, 547, 7445, 65327, 65359 },
- ['p'] = { 421, 7765, 7767, 65328, 65360 },
- ['q'] = { 672, 586, 587, 1306, 1307, 42840, 42841, 984, 985, 120110, 120214, 8474, 1382, 491, 65329, 65361 },
- ['r'] = { 174, 341, 344, 345, 529, 531, 636, 637, 638, 7769, 7771, 7773, 7775, 65330, 65362 },
- ['s'] = { 350, 351, 348, 349, 537, 7784, 7785, 7780, 7781, 7776, 7777, 7782, 7783, 352, 353, 346, 347, 7779, 65331, 65363 },
- ['t'] = { 427, 538, 539, 354, 355, 430, 648, 358, 359, 356, 357, 7786, 7787, 7788, 7789, 772, 7831, 7790, 7791, 65332, 65364 },
- ['u'] = { 363, 362, 250, 218, 468, 467, 249, 217, 365, 364, 251, 219, 252, 220, 367, 366, 371, 370, 361, 360, 369, 368, 533, 532, 7795, 7794, 7797, 7796, 7799, 7798, 7801, 7800, 7803, 7802, 470, 469, 472, 471, 474, 473, 476, 475, 7911, 7910, 361, 360, 7909, 7908, 432, 431, 7915, 7914, 7917, 7916, 7919, 7918, 7913, 7912, 7921, 7920, 7531, 65333, 65365 },
- ['v'] = { 7805, 7804, 7807, 7806, 42846, 65334, 65366 },
- ['w'] = { 7810, 7811, 7808, 7809, 372, 373, 7832, 7812, 7813, 7814, 7815, 7816, 7817, 653, 684, 65335, 65367 },
- ['x'] = { 1093, 1203, 1277, 1279, 926, 958, 935, 967, 885, 885, 967, 935, 967, 739, 215, 9587, 10005, 10006, 10799, 10007, 10008, 128500, 128502, 9746, 128501, 128503, 9747, 128937, 10060, 10062, 10761, 128473, 120091, 120117, 12584, 12490, 12513, 1488, 20034, 13317, 5815, 5816, 1604, 7821, 7820, 7819, 7818, 7565, 65336, 65368 },
- ['y'] = { 11433, 11432, 1091, 1059, 1118, 1038, 1091, 1091, 1141, 1140, 933, 910, 910, 8029, 8025, 8027, 8031, 8170, 8168, 8169, 65337, 65369 },
- ['z'] = { 11405, 11404, 918, 950, 918, 382, 381, 380, 379, 7826, 7827, 378, 7828, 7829, 7824, 7825, 377, 656, 657, 549, 437, 438, 20057, 20043, 8484, 65338, 65370 }
- }
-end
-
-function wordfilter:on_new_message(message)
- if message.chat.type == 'supergroup' and mattata.get_setting(message.chat.id, 'word filter') and not mattata.is_group_admin(message.chat.id, message.from.id) then
- local base = message.text:lower()
- for char, variations in pairs(wordfilter.bytes) do
- for _, variation in pairs(variations) do
- base = base:gsub(utf8.char(variation), char)
- end
- end
- base = base:gsub('[^%w \n\t\r]', '') -- Trim everything apart from alpha-numerical characters and spaces.
- local words = redis:smembers('word_filter:' .. message.chat.id)
- if words and #words > 0 then
- for _, v in pairs(words) do
- if base:match('^' .. v:lower() .. '$') or base:match('^' .. v:lower() .. ' ') or base:match(' ' .. v:lower() .. ' ') or base:match(' ' .. v:lower() .. '$') then
- mattata.delete_message(message.chat.id, message.message_id)
- local action = mattata.get_setting(message.chat.id, 'ban not kick') and mattata.ban_chat_member or mattata.kick_chat_member
- local success = action(message.chat.id, message.from.id)
- if success then
- if mattata.get_setting(message.chat.id, 'log administrative actions') then
- local log_chat = mattata.get_log_chat(message.chat.id)
- mattata.send_message(log_chat, string.format('<pre>%s [%s] has kicked %s [%s] from %s [%s] for sending one or more prohibited words.</pre>', mattata.escape_html(self.info.first_name), self.info.id, mattata.escape_html(message.from.first_name), message.from.id, mattata.escape_html(message.chat.title), message.chat.id), 'html')
- end
- mattata.send_message(message.chat.id, string.format('Kicked %s for sending one or more prohibited words.', message.from.username and '@' .. message.from.username or message.from.first_name))
- self.is_command_done = true
- break
- end
- end
- end
- end
- end
-end
-
-function wordfilter:on_message(message, configuration, language)
- if message.chat.type ~= 'supergroup' then
- mattata.send_reply(message, language.errors.supergroup)
- elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
- return mattata.send_reply(message, language.errors.admin)
- end
- local words = redis:smembers('word_filter:' .. message.chat.id)
- if #words < 1 then
- return mattata.send_reply(message, 'There are no words filtered in this chat. To add words to the filter, use /filter <word(s)>.')
- end
- return mattata.send_message(message.chat.id, 'Filtered words: ' .. table.concat(words, ', '))
-end
-
-return wordfilter
\ No newline at end of file
diff --git a/plugins/aesthetic.lua b/plugins/aesthetic.lua
deleted file mode 100644
index 2382939..0000000
--- a/plugins/aesthetic.lua
+++ /dev/null
@@ -1,24 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local aesthetic = {}
-local mattata = require('mattata')
-local copypasta = require('plugins.copypasta')
-
-function aesthetic:init()
- aesthetic.commands = mattata.commands(self.info.username):command('aesthetic'):command('fullwidth'):command('fw').table
- aesthetic.help = '/aesthetic [text] - Aestheticises the given/replied-to text! Aliases: /fullwidth, /fw.'
-end
-
-function aesthetic.on_message(_, message)
- local input = message.reply and message.reply.text or mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, aesthetic.help)
- end
- local output = copypasta.aestheticise(input)
- return mattata.send_message(message.chat.id, output)
-end
-
-return aesthetic
\ No newline at end of file
diff --git a/plugins/afk.lua b/plugins/afk.lua
deleted file mode 100644
index e701f71..0000000
--- a/plugins/afk.lua
+++ /dev/null
@@ -1,49 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local afk = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function afk:init()
- afk.commands = mattata.commands(self.info.username):command('[Aa][Ff][Kk]').table
- afk.help = '/afk [note] - Mark yourself as away from keyboard, with an optional note that will be displayed to users who mention you whilst you\'re away. You must have an @username for this feature to work.'
-end
-
-function afk.on_message(_, message, _, language)
- if not message.from.username then
- return mattata.send_reply(message, language['afk']['1']) -- Since this feature relies on detecting username
- -- mentions, this feature is currently only available to users who have a public @username.
- elseif redis:hget('afk:' .. message.from.id, 'since') then -- Check if the user is
- -- already marked as AFK.
- local since = redis:hget('afk:' .. message.from.id, 'since')
- -- Un-mark the user as AFK in the database.
- redis:hdel('afk:' .. message.from.id, 'since')
- redis:hdel('afk:' .. message.from.id, 'note')
- local keys = redis:keys('afk:' .. message.from.id .. ':replied:*')
- if #keys > 0 then
- for _, key in pairs(keys) do
- redis:del(key)
- end
- end
- local time = mattata.format_time(os.time() - tonumber(since))
- local output = string.format(language['afk']['2'], message.from.first_name, time)
- output = output:gsub('AFK', '/AFK') -- temporary solution until i update language strings
- mattata.delete_message(message.chat.id, message.message_id) -- attempt to delete their message to reduce chat clutter
- return mattata.send_message(message.chat.id, output) -- Inform the chat of the user's return, and include the
- -- time they spent marked as AFK.
- end
- local input = mattata.input(message.text) and '\n' .. language['afk']['3'] .. ': ' .. mattata.input(message.text) or ''
- redis:hset('afk:' .. message.from.id, 'since', os.time())
- redis:hset('afk:' .. message.from.id, 'note', input)
- local output = string.format(language['afk']['4'], message.from.first_name, input)
- local success = mattata.send_message(message.chat.id, output)
- if success then -- if the afk message sent, we'll attempt to delete their original message to clear up the chat a bit
- return mattata.delete_message(message.chat.id, message.message_id)
- end
- return false
-end
-
-return afk
\ No newline at end of file
diff --git a/plugins/ai.lua b/plugins/ai.lua
deleted file mode 100644
index b17a22a..0000000
--- a/plugins/ai.lua
+++ /dev/null
@@ -1,46 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local ai = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function ai:on_new_message(message)
- if not message.text or message.text:match('^[/!#]') then
- return false
- elseif redis:get('chatroulette:' .. message.from.id) then
- return false
- elseif message.text and message.reply and message.reply.text and message.reply.from.id == self.info.id and not message.reply.entities then
- return ai.on_message(self, message)
- end
- local triggers = {
- '^' .. self.info.first_name:lower() .. ',? ',
- '^@?' .. self.info.username:lower() .. ',? '
- }
- for _, trigger in pairs(triggers) do
- if message.text:lower():match(trigger) then
- return ai.on_message(self, message)
- end
- end
- if message.chat.type == 'private' and message.text then
- return ai.on_message(self, message)
- end
- return
-end
-
-function ai:on_message(message)
- self.is_ai = true
- local text = message.text:gsub('^' .. self.info.first_name:lower() .. ',? ', ''):gsub('^@?' .. self.info.username:lower() .. ',? ', '')
- text = text:gsub(self.info.first_name:lower(), 'you'):gsub('@?' .. self.info.username:lower(), 'you')
- local language = mattata.get_setting(message.chat.id, 'force group language') and 'en' or mattata.get_user_language(message.from.id):match('^(..)')
- if message.reply and message.reply.text and message.reply.from.id == self.info.id and not message.reply.entities then
- redis:hset('ai:' .. message.chat.id .. ':' .. message.message_id, 'reply', message.reply.text)
- end
- redis:hset('ai:' .. message.chat.id .. ':' .. message.message_id, 'text', text)
- redis:hset('ai:' .. message.chat.id .. ':' .. message.message_id, 'language', language)
- return
-end
-
-return ai
\ No newline at end of file
diff --git a/plugins/answer.lua b/plugins/answer.lua
deleted file mode 100644
index 2d8acb5..0000000
--- a/plugins/answer.lua
+++ /dev/null
@@ -1,57 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local answer = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local json = require('dkjson')
-local redis = require('libs.redis')
-
-function answer:init()
- answer.commands = mattata.commands(self.info.username):command('answer').table
- answer.help = '/answer <query> - Provides a quick answer to the given query. Results provided by DuckDuckGo.'
- answer.url = 'https://api.duckduckgo.com/?format=json&pretty=0&q='
-end
-
-function answer:on_message(message, _, language)
- local input = mattata.input(message.text)
- if not input then
- return false
- elseif input:match('%d* ?[%+*%-/]') then
- message.text = '/calc ' .. input
- return mattata.on_message(self, message)
- end
- input = input:gsub('[%?!,]', '')
- local jstr, res = https.request(answer.url .. url.escape(input))
- if res ~= 200 then
- return mattata.send_reply(message, language.errors.connection)
- end
- local jdat = json.decode(jstr)
- if not jdat.meta and jdat.Heading == '' and not jdat.RelatedTopics[1] then
- redis:hset('ai:' .. message.chat.id .. ':' .. message.message_id, 'text', input)
- redis:hset('ai:' .. message.chat.id .. ':' .. message.message_id, 'language', language)
- return true
- end
- local output = '<b>%s</b>\n<em>%s</em>\n%s'
- local heading = jdat.Heading
- local body = jdat.AbstractText ~= '' and jdat.AbstractText or jdat.RelatedTopics[1].Text or 'Couldn\'t find a description, try sending /wiki ' .. jdat.Heading
- local via = jdat.AbstractSource ~= '' and jdat.AbstractSource or jdat.RelatedTopics[1].FirstURL
- local image = jdat.Image ~= '' and jdat.Image or jdat.RelatedTopics[1] and jdat.RelatedTopics[1].Icon.URL
- if via:lower() == 'wikipedia' then
- via = '<a href="https://en.wikipedia.org">Wikipedia</a>'
- end
- via = 'Via ' .. via .. '.'
- if body:find(' /wiki ') then -- If we're re-directing them to the Wikipedia command, we don't want to give them a via message.
- return mattata.send_reply(message, 'I couldn\'t find an answer for that, try /wiki ' .. heading .. '.')
- end
- output = string.format(output, mattata.escape_html(heading), mattata.escape_html(body), via)
- if image and image ~= '' then
- return mattata.send_photo(message.chat.id, image, output, 'html', false, message.message_id)
- end
- return mattata.send_reply(message, output, 'html', true)
-end
-
-return answer
\ No newline at end of file
diff --git a/plugins/appstore.lua b/plugins/appstore.lua
deleted file mode 100644
index 1f3cbb9..0000000
--- a/plugins/appstore.lua
+++ /dev/null
@@ -1,67 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local appstore = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local json = require('dkjson')
-
-function appstore:init()
- appstore.commands = mattata.commands(self.info.username):command('appstore'):command('app'):command('as').table
- appstore.help = '/appstore <query> - Displays information about the first app returned by iTunes for the given search query. Aliases: /app, /as.'
- appstore.url = 'https://itunes.apple.com/search?lang=en&entity=software&term='
-end
-
-function appstore.get_app_info(jdat, language)
- local categories = {}
- for n in pairs(jdat.results[1].genres) do
- table.insert(categories, jdat.results[1].genres[n])
- end
- local rating = tonumber(jdat.results[1].userRatingCount)
- if rating ~= nil then
- if rating == 1 then
- rating = string.format('%s 1 %s', utf8.char(11088), language['appstore']['2'])
- elseif rating > 0 then
- rating = string.format('%s %s %s (%s)', utf8.char(11088), mattata.comma_value(tostring(rating)), language['appstore']['3'], jdat.results[1].averageUserRating)
- else
- rating = string.format('%s %s %s', utf8.char(11088), mattata.comma_value(tostring(rating)), language['appstore']['3'])
- end
- else rating = 'N/A' end
- if jdat.results[1].description:len() > 250 then
- jdat.results[1].description = jdat.results[1].description:sub(1, 250) .. '...'
- end
- return string.format(
- '<b>%s</b> - v%s, %s/%s/%s\n\n<i>%s</i>\n\n%s\n%s <b>|</b> iOS %s+',
- mattata.escape_html(jdat.results[1].trackName),
- jdat.results[1].version,
- jdat.results[1].currentVersionReleaseDate:sub(9, 10),
- jdat.results[1].currentVersionReleaseDate:sub(6, 7),
- jdat.results[1].currentVersionReleaseDate:sub(1, 4),
- mattata.escape_html(jdat.results[1].description),
- table.concat(categories, ' <b>|</b> '), rating,
- jdat.results[1].minimumOsVersion
- )
-end
-
-function appstore.on_message(_, message, _, language)
- local input = mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, appstore.help)
- end
- local jstr, res = https.request(appstore.url .. url.escape(input))
- if res ~= 200 then
- return mattata.send_reply(message, language.errors.connection)
- end
- local jdat = json.decode(jstr)
- if jdat.resultCount == 0 then
- return mattata.send_reply(message, language.errors.results)
- end
- local keyboard = mattata.inline_keyboard():row(mattata.row():url_button(language['appstore']['1'], jdat.results[1].trackViewUrl))
- local output = appstore.get_app_info(jdat, language)
- return mattata.send_message(message.chat.id, output, 'html', true, false, nil, keyboard)
-end
-
-return appstore
\ No newline at end of file
diff --git a/plugins/authspotify.lua b/plugins/authspotify.lua
deleted file mode 100644
index 2ebc5c5..0000000
--- a/plugins/authspotify.lua
+++ /dev/null
@@ -1,54 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local authspotify = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local json = require('dkjson')
-local ltn12 = require('ltn12')
-local redis = require('libs.redis')
-
-function authspotify:init(configuration)
- authspotify.commands = mattata.commands(self.info.username):command('authspotify').table
- authspotify.help = '/authspotify <token> - Authorises your Spotify account for use with mattata.'
- authspotify.redirect_uri = configuration.keys.spotify.redirect_uri
- authspotify.client_id = configuration.keys.spotify.client_id
- authspotify.client_secret = configuration.keys.spotify.client_secret
-end
-
-function authspotify.on_message(_, message, _, language)
- local input = mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, authspotify.help)
- elseif redis:get('spotify:' .. message.from.id .. ':access_token') then
- return mattata.send_reply(message, language['authspotify']['1'])
- end
- input = input:match('[%?&]code=(.-)$') or input
- local query = string.format('grant_type=authorization_code&code=%s&redirect_uri=%s&client_id=%s&client_secret=%s', url.escape(input), url.escape(authspotify.redirect_uri), authspotify.client_id, authspotify.client_secret)
- local wait_message = mattata.send_message(message.chat.id, language['authspotify']['2'])
- local response = {}
- local _, res = https.request({
- ['url'] = 'https://accounts.spotify.com/api/token',
- ['method'] = 'POST',
- ['headers'] = {
- ['Content-Type'] = 'application/x-www-form-urlencoded',
- ['Content-Length'] = query:len()
- },
- ['source'] = ltn12.source.string(query),
- ['sink'] = ltn12.sink.table(response)
- })
- local jdat = json.decode(table.concat(response))
- if res ~= 200 or not jdat or jdat.error then
- local output = string.format('%s `%s?code=...`', language['authspotify']['3'], authspotify.redirect_uri)
- return mattata.edit_message_text(message.chat.id, wait_message.result.message_id, output, true)
- end
- redis:set('spotify:' .. message.from.id .. ':access_token', jdat.access_token)
- redis:expire('spotify:' .. message.from.id .. ':access_token', 3600)
- redis:set('spotify:' .. message.from.id .. ':refresh_token', jdat.refresh_token)
- return mattata.edit_message_text(message.chat.id, wait_message.result.message_id, language['authspotify']['4'])
-end
-
-return authspotify
\ No newline at end of file
diff --git a/plugins/avatar.lua b/plugins/avatar.lua
deleted file mode 100644
index ccdcc6d..0000000
--- a/plugins/avatar.lua
+++ /dev/null
@@ -1,97 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local avatar = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function avatar:init()
- avatar.commands = mattata.commands(self.info.username):command('avatar'):command('profilepic'):command('pic').table
- avatar.help = '/avatar <user> [offset] - Sends the profile photos of the given user, of which can be specified by username or numerical ID. If an offset is given after the username (which must be a numerical value), then the nth profile photo is sent (if available).'
-end
-
-function avatar:on_inline_query(inline_query, _, language)
- local input = mattata.input(inline_query.query)
- or inline_query.from.id
- local selected_photo = false
- if tostring(input):match('^.- %d*$') then
- selected_photo = tostring(input):match('^.- (%d*)$')
- input = tostring(input):match('^(.-) %d*$')
- end
- local success = true
- local old_input = input
- if tonumber(input) == nil then
- input = mattata.get_user(input)
- if not input then
- success = false
- else
- input = input.result.id
- end
- end
- if success then
- success = mattata.get_user_profile_photos(input)
- end
- if not success then
- return mattata.send_inline_article(inline_query.id, language.errors.generic, language['avatar']['1'])
- elseif success.result.total_count == 0 or redis:get('user:' .. input .. ':opt_out') then
- return false
- elseif selected_photo then
- if tonumber(selected_photo) < 1 or tonumber(selected_photo) > success.result.total_count then
- return false
- end
- end
- local results = {}
- local count = 1
- local start = tonumber(selected_photo) or 1
- local finish = tonumber(selected_photo) or success.result.total_count
- for i = start, finish do
- table.insert(results, {
- ['type'] = 'photo',
- ['id'] = tostring(count),
- ['photo_file_id'] = success.result.photos[i][#success.result.photos[i]].file_id,
- ['caption'] = string.format(language['avatar']['5'], old_input, i, success.result.total_count, old_input, self.info.username)
- })
- count = count + 1
- end
- return mattata.answer_inline_query(inline_query.id, results)
-end
-
-function avatar.on_message(_, message, _, language)
- local input = mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, avatar.help)
- end
- local selected_photo = 1
- if input:match(' %d*$') then
- selected_photo = tonumber(input:match(' (%d*)$'))
- input = input:match('^(.-) %d*$')
- end
- local success = true
- local old_input = input
- if tonumber(input) == nil then
- input = mattata.get_user(input)
- if not input then
- success = false
- else
- input = input.result.id
- end
- end
- if success then
- success = mattata.get_user_profile_photos(input)
- end
- if not success then
- return mattata.send_reply(message, language['avatar']['1'])
- elseif success.result.total_count == 0 or redis:get('user:' .. input .. ':opt_out') then
- local output = success.result.total_count == 0 and language['avatar']['2'] or language['avatar']['4']
- return mattata.send_reply(message, output)
- elseif tonumber(selected_photo) < 1 or tonumber(selected_photo) > success.result.total_count then
- return mattata.send_reply(message, language['avatar']['3'])
- end
- local highest_res = success.result.photos[selected_photo][#success.result.photos[selected_photo]].file_id
- local caption = string.format(language['avatar']['6'], old_input, selected_photo, success.result.total_count, old_input)
- return mattata.send_photo(message.chat.id, highest_res, caption)
-end
-
-return avatar
\ No newline at end of file
diff --git a/plugins/base64.lua b/plugins/base64.lua
deleted file mode 100644
index 069b55f..0000000
--- a/plugins/base64.lua
+++ /dev/null
@@ -1,36 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local base64 = {}
-local mattata = require('mattata')
-local b64 = require('base64')
-
-function base64:init()
- base64.commands = mattata.commands(self.info.username):command('base64'):command('b64'):command('dbase64'):command('db64').table
- base64.help = '/base64 <text> - Encodes the given text in base64. Use /dbase64 or /db64 to turn base64-encoded text into plaintext. Alias: /b64.'
-end
-
-function base64.on_message(_, message)
- local input = message.reply and message.reply.text or mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, base64.help)
- end
- local output = b64.encode(input)
- if message.command == 'dbase64' or message.command == 'db64' then
- output = b64.decode(input)
- end
- if not output then
- return mattata.send_reply(message, 'That\'s not valid base64-encoded text!')
- elseif utf8.len(output) > 4096 then
- return mattata.send_reply(message, 'That\'s too much text for me to give you. But you can have a cookie instead. ' .. utf8.char(127850))
- end
- local success = mattata.send_reply(message, output)
- if not success then
- return mattata.send_reply(message, 'That\'s not valid base64-encoded text!')
- end
- return success
-end
-
-return base64
\ No newline at end of file
diff --git a/plugins/bash.lua b/plugins/bash.lua
deleted file mode 100644
index 76b832b..0000000
--- a/plugins/bash.lua
+++ /dev/null
@@ -1,28 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local bash = {}
-local mattata = require('mattata')
-
-function bash:init()
- bash.commands = mattata.commands(self.info.username):command('bash').table
-end
-
-function bash.on_message(_, message, _, language)
- if not mattata.is_global_admin(message.from.id) then
- return false
- end
- local input = mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, language['bash']['1'])
- end
- local res = io.popen(input)
- local output = res:read('*all')
- res:close()
- output = output:len() == 0 and language['bash']['2'] or string.format('<pre>%s</pre>', mattata.escape_html(output))
- return mattata.send_message(message.chat.id, output, 'html')
-end
-
-return bash
\ No newline at end of file
diff --git a/plugins/bing.lua b/plugins/bing.lua
deleted file mode 100644
index c7ea48f..0000000
--- a/plugins/bing.lua
+++ /dev/null
@@ -1,64 +0,0 @@
---[[
- Based on a plugin by topkecleon. Licensed under GNU AGPLv3
- https://github.com/topkecleon/otouto/blob/master/LICENSE.
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local bing = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local ltn12 = require('ltn12')
-local json = require('dkjson')
-
-function bing:init(configuration)
- assert(configuration.keys.bing, 'bing.lua requires an API key, and you haven\'t got one configured!')
- bing.commands = mattata.commands(self.info.username):command('bing').table
- bing.help = '/bing <query> - Searches Bing for the given search query and returns the top results.'
- bing.key = configuration.keys.bing
-end
-
-function bing.on_message(_, message, configuration, language)
- local input = mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, bing.help)
- end
- local body = {}
- local _, res = https.request({
- ['url'] = 'https://api.cognitive.microsoft.com/bing/v7.0/search?responseFilter=Webpages&safeSearch=Off&q=' .. url.escape(input),
- ['headers'] = {
- ['Ocp-Apim-Subscription-Key'] = bing.key,
- ['User-Agent'] = 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko'
- },
- ['sink'] = ltn12.sink.table(body),
- })
- if res ~= 200 then
- return mattata.send_reply(message, language.errors.connection)
- end
- local jdat = json.decode(table.concat(body))
- if not jdat.webPages then
- return mattata.send_reply(message, language.errors.results)
- end
- local limit = message.chat.type == 'private' and configuration.limits.bing.private or configuration.limits.bing.public
- if limit > #jdat.webPages.value and #jdat.webPages.value or limit == 0 then
- return mattata.send_reply(message, language.errors.results)
- end
- local results = {}
- local count = 0
- for i = 1, limit do
- if jdat.webPages.value[i].snippet:len() > 100 then
- jdat.webPages.value[i].snippet = jdat.webPages.value[i].snippet:sub(1, 100) .. '...'
- end
- if count > limit - 4 then
- table.insert(results, string.format('%s <a href="%s">%s</a>', mattata.symbols.bullet, jdat.webPages.value[i].url, mattata.escape_html(jdat.webPages.value[i].name)))
- else
- table.insert(results, string.format('%s <a href="%s">%s</a> <em>%s</em>', mattata.symbols.bullet, jdat.webPages.value[i].url, mattata.escape_html(jdat.webPages.value[i].name), mattata.escape_html(jdat.webPages.value[i].snippet)))
- end
- count = count + 1
- end
- local output = table.concat(results, '\n')
- return mattata.send_message(message.chat.id, output, 'html')
-end
-
-return bing
\ No newline at end of file
diff --git a/plugins/blocklistchat.lua b/plugins/blocklistchat.lua
deleted file mode 100644
index 9181847..0000000
--- a/plugins/blocklistchat.lua
+++ /dev/null
@@ -1,36 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local allowlistchat = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function allowlistchat:init()
- allowlistchat.commands = mattata.commands(self.info.username):command('allowlistchat').table
-end
-
-function allowlistchat.on_message(_, message, _, language)
- if not mattata.is_global_admin(message.from.id) then
- return false
- end
- local input = mattata.input(message.text)
- if not input then
- return false
- end
- input = input:match('^@(.-)$') or input
- local res = mattata.get_chat(input)
- local output
- if not res then
- output = string.format(language['allowlistchat']['3'], input)
- elseif res.result.type == 'private' then
- output = string.format(language['allowlistchat']['2'], input)
- else
- redis.set('allowlisted_chats:' .. input, true)
- output = string.format(language['allowlistchat']['1'], input)
- end
- return mattata.send_reply(message, output)
-end
-
-return allowlistchat
\ No newline at end of file
diff --git a/plugins/bugreport.lua b/plugins/bugreport.lua
deleted file mode 100644
index c180c37..0000000
--- a/plugins/bugreport.lua
+++ /dev/null
@@ -1,44 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local bugreport = {}
-local mattata = require('mattata')
-
-function bugreport:init(configuration)
- assert(configuration.bug_reports_chat, 'Please specify a chat ID to send all bug reports to!')
- bugreport.commands = mattata.commands(self.info.username):command('bugreport'):command('bug'):command('br').table
- bugreport.help = '/bugreport <text> - Reports a bug to the configured developer. Aliases: /bug, /br.'
-end
-
-function bugreport:on_new_message(message, configuration)
- if mattata.is_global_admin(message.from.id) and message.chat.id == configuration.bug_reports_chat and message.reply and message.reply.forward_from and not message.text:match('^[/!#]') and message.reply.from.id == self.info.id then
- mattata.send_message(
- message.reply.forward_from.id,
- string.format(
- 'Message from the developer regarding bug report #bug%s:\n<pre>%s</pre>',
- message.reply.forward_date .. message.reply.forward_from.id,
- mattata.escape_html(message.text)
- ),
- 'html'
- )
- end
-end
-
-function bugreport.on_message(_, message, configuration, language)
- local input = mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, bugreport.help)
- end
- if message.reply then
- mattata.forward_message(configuration.bug_reports_chat, message.chat.id, false, message.message_id)
- end
- local success = mattata.forward_message(configuration.bug_reports_chat, message.chat.id, false, message.message_id)
- if success and message.chat.id ~= configuration.bug_reports_chat then
- return mattata.send_reply(message, string.format(language['bugreport']['1'], 'bug' .. message.date .. message.from.id))
- end
- return mattata.send_reply(message, language['bugreport']['2'])
-end
-
-return bugreport
\ No newline at end of file
diff --git a/plugins/calc.lua b/plugins/calc.lua
deleted file mode 100644
index ad69cf6..0000000
--- a/plugins/calc.lua
+++ /dev/null
@@ -1,198 +0,0 @@
---[[
- Based on a plugin by topkecleon. Licensed under GNU AGPLv3
- https://github.com/topkecleon/otouto/blob/master/LICENSE.
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local calc = {}
-local mattata = require('mattata')
-local http = require('socket.http')
-local url = require('socket.url')
-
-function calc:init()
- calc.commands = mattata.commands(self.info.username):command('calc'):command('calculate'):command('calculator').table
- calc.help = '/calc <expression> - Solves the given mathematical expression using mathjs.org.'
- calc.aliases = {
- ['?'] = '/',
- ['divided by'] = '/',
- ['times by'] = '*',
- ['times'] = '*',
- ['multiplied by'] = '*',
- [' x '] = '*',
- ['minus'] = '-',
- ['subtract'] = '-',
- ['take away'] = '-',
- ['to the power of'] = '^',
- ['raised to'] = '^',
- ['π'] = math.pi,
- ['pi'] = math.pi,
- ['plus'] = '+',
- ['added to'] = '+',
- ['add'] = '+',
- ['point'] = '.',
- ['dot'] = '.',
- ['percent'] = '%%',
- ['percentage'] = '%%',
- ['²'] = '^2'
- }
- calc.numbers = {
- ['zero'] = 0,
- ['one'] = 1,
- ['two'] = 2,
- ['three'] = 3,
- ['four'] = 4,
- ['five'] = 5,
- ['six'] = 6,
- ['seven'] = 7,
- ['eight'] = 8,
- ['nine'] = 9,
- ['ten'] = 10,
- ['eleven'] = 11,
- ['twelve'] = 12,
- ['thirteen'] = 13,
- ['fourteen'] = 14,
- ['fifteen'] = 15,
- ['sixteen'] = 16,
- ['seventeen'] = 17,
- ['eighteen'] = 18,
- ['nineteen'] = 19,
- ['twenty'] = 20,
- ['thirty'] = 30,
- ['forty'] = 40,
- ['fifty'] = 50,
- ['sixty'] = 60,
- ['seventy'] = 70,
- ['eighty'] = 80,
- ['ninety'] = 90
- }
- calc.units = {
- ['hundred'] = '100',
- ['thousand'] = '1000',
- ['million'] = '1000000',
- ['billion'] = '1000000000',
- ['trillion'] = '1000000000000',
- ['quadrillion'] = '1000000000000000',
- ['quintillion'] = '1000000000000000000',
- ['sextillion'] = '1000000000000000000000',
- ['septillion'] = '1000000000000000000000000',
- ['octillion'] = '1000000000000000000000000000',
- ['nonillion'] = '1000000000000000000000000000000',
- ['decillion'] = '1000000000000000000000000000000000',
- ['undecillion'] = '1000000000000000000000000000000000000',
- ['duodecillion'] = '1000000000000000000000000000000000000000',
- ['tredecillion'] = '1000000000000000000000000000000000000000000',
- ['quattuordecillion'] = '1000000000000000000000000000000000000000000000',
- ['quindecillion'] = '1000000000000000000000000000000000000000000000000',
- ['sexdecillion'] = '1000000000000000000000000000000000000000000000000000',
- ['septendecillion'] = '1000000000000000000000000000000000000000000000000000000',
- ['octodecillion'] = '1000000000000000000000000000000000000000000000000000000000',
- ['novemdecillion'] = '1000000000000000000000000000000000000000000000000000000000000',
- ['vigintillion'] = '1000000000000000000000000000000000000000000000000000000000000000'
- }
- calc.url = 'https://api.mathjs.org/v4/?expr='
-end
-
-function calc.convert(str, language)
- str = str:lower()
- local results = {}
- local prev = nil
- for word in str:gmatch('[%w²π]+') do
- if word ~= 'and' then -- don't process "and"
- local top = #results
- local number = tonumber(word)
- if not number then
- number = calc.numbers[word]
- end
- if number then
- if prev == 'number' then
- local prev_num = table.remove(results, top)
- number = number + prev_num
- end
- table.insert(results, number)
- prev = 'number'
- else
- local unit = tonumber(calc.units[word])
- if not unit then
- return false, string.format(language['calc']['2'], word)
- end
- prev = 'unit'
- if top == 0 then
- return false, language['calc']['3']
- end
- local interim = 0
- while top > 0 and results[top] < unit do
- interim = interim + table.remove(results, top)
- top = #results
- end
- table.insert(results, interim * unit)
- end
- end
- end
- if #results == 0 then
- return false, 'No number found!'
- end
- local final = 0
- for _, res in ipairs(results) do
- final = final + res
- end
- return final
-end
-
-
-function calc.process_input(input, language)
- input = input:gsub('percent of', 'percent')
- for k, v in pairs(calc.aliases) do
- input = input:gsub(k, v)
- end
- for phrase in input:gmatch('[%w%s]+') do
- local new, err = calc.convert(phrase, language)
- if new then
- input = input:gsub(phrase, new)
- else
- return false, err
- end
- end
- return input
-end
-
-function calc.on_inline_query(_, inline_query, _, language)
- local input = mattata.input(inline_query.query)
- if not input then
- return false
- end
- input = calc.process_input(input, language)
- local str, res = http.request(calc.url .. url.escape(input))
- if res ~= 200 or not str then
- return false
- end
- local description = language['calc']['1']
- local message_content = mattata.input_text_message_content(str)
- local result = mattata.inline_result()
- :type('article')
- :id(1)
- :title(str)
- :description(description)
- :input_message_content(message_content)
- return mattata.answer_inline_query(inline_query.id, result)
-end
-
-function calc.on_message(_, message, _, language)
- local input = mattata.input(message.text)
- local err
- if not input then
- return mattata.send_reply(message, calc.help)
- end
- input, err = calc.process_input(input, language)
- if not input then
- return mattata.send_reply(message, err)
- end
- local str, res = http.request(calc.url .. url.escape(input))
- if res ~= 200 then
- local response = language['errors']['results']
- return mattata.send_reply(message, response)
- end
- return mattata.send_message(message.chat.id, str)
-end
-
-return calc
\ No newline at end of file
diff --git a/plugins/captionbotai.lua b/plugins/captionbotai.lua
deleted file mode 100644
index 5debd73..0000000
--- a/plugins/captionbotai.lua
+++ /dev/null
@@ -1,66 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local captionbotai = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local ltn12 = require('ltn12')
-
-function captionbotai:on_new_message(message, configuration, language)
- if message.photo or (message.reply and message.reply.photo) then
- if message.text:lower():match('^wh?at .- th[ia][st].-') or message.text:lower():match('^who .- th[ia][st].-') then
- return captionbotai.on_message(self, message, configuration, language)
- end
- end
-end
-
-function captionbotai.request(input, configuration)
- local body = string.format('{Type: "CaptionRequest", Content: "%s"}', input)
- local sink, response = ltn12.sink.table()
- local _, res = https.request(
- {
- ['url'] = 'http://captionbot.azurewebsites.net/api/messages',
- ['method'] = 'POST',
- ['headers'] = {
- ['Content-Length'] = body:len(),
- ['Content-Type'] = 'application/json',
- ['DNT'] = 1,
- ['Host'] = 'captionbot.azurewebsites.net',
- ['Origin'] = 'https://www.captionbot.ai',
- ['Referer'] = 'https://www.captionbot.ai/',
- ['User-Agent'] = 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Mobile Safari/537.36'
- },
- ['source'] = ltn12.source.string(body),
- ['sink'] = sink
- }
- )
- response = table.concat(response)
- if res ~= 200 then
- return false
- end
- response = response:gsub('^"', ''):gsub('"$', ''):gsub('\\"', '"'):gsub(configuration.bot_token, '')
- return response
-end
-
-function captionbotai.on_message(_, message, configuration, language)
- if message.reply and message.reply.photo then
- message.photo = message.reply.photo
- end
- local file = mattata.get_file(message.photo[#message.photo].file_id) -- Gets the highest resolution available, for the best result.
- if not file then
- return false
- end
- mattata.send_chat_action(message.chat.id)
- local request_url = string.format('https://api.telegram.org/file/bot%s/%s', configuration.bot_token, file.result.file_path)
- local output = captionbotai.request(request_url, configuration)
- if not output or output:lower():match('^https%:%/%/') then
- return mattata.send_reply(message, language['captionbotai']['1'] .. ' 😳')
- end
- output = output:match('%, but (.-)$') or output
- output = output:gsub('%.$', '')
- return mattata.send_reply(message, output)
-end
-
-return captionbotai
\ No newline at end of file
diff --git a/plugins/catfact.lua b/plugins/catfact.lua
deleted file mode 100644
index 1071473..0000000
--- a/plugins/catfact.lua
+++ /dev/null
@@ -1,26 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local catfact = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local json = require('dkjson')
-
-
-function catfact:init()
- catfact.commands = mattata.commands(self.info.username):command('catfact'):command('cfact').table
- catfact.help = '/catfact - Returns a random cat fact. Alias: /cfact.'
-end
-
-function catfact.on_message(_, message, _, language)
- local jstr, res = https.request('https://catfact.ninja/fact')
- if res ~= 200 then
- return mattata.send_reply(message, language.errors.connection)
- end
- local jdat = json.decode(jstr)
- return mattata.send_message(message.chat.id, jdat.fact)
-end
-
-return catfact
\ No newline at end of file
diff --git a/plugins/cats.lua b/plugins/cats.lua
deleted file mode 100644
index cfbdc5d..0000000
--- a/plugins/cats.lua
+++ /dev/null
@@ -1,47 +0,0 @@
---[[
- Based on a plugin by topkecleon. Licensed under GNU AGPLv3
- https://github.com/topkecleon/otouto/blob/master/LICENSE.
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local cats = {}
-local mattata = require('mattata')
-local http = require('socket.http')
-local json = require('dkjson')
-
-function cats:init(configuration)
- assert(configuration.keys.cats, 'cats.lua requires an API key, and you haven\'t got one configured!')
- cats.commands = mattata.commands(self.info.username):command('cat').table
- cats.help = '/cat - Sends a random photo of a cat.'
-end
-
-function cats.on_inline_query(_, inline_query, configuration, language)
- local str, res = http.request('http://thecatapi.com/api/images/get?format=html&type=jpg&api_key=' .. configuration.keys.cats)
- str = str:match('%<img src%=%"(.-)%"%>')
- if res ~= 200 then
- return
- end
- return mattata.answer_inline_query(inline_query.id, json.encode({{
- ['type'] = 'photo',
- ['id'] = '1',
- ['photo_url'] = tostring(str),
- ['thumb_url'] = tostring(str),
- ['caption'] = language['cats']['1']
- }}))
-end
-
-function cats.on_message(_, message, configuration, language)
- local str, res = http.request('http://thecatapi.com/api/images/get?format=html&type=jpg&api_key=' .. configuration.keys.cats)
- if res ~= 200 then
- return mattata.send_reply(message, language.errors.connection)
- end
- local photo = str:match('%<img src%=%"(.-)%"%>')
- if not photo then
- return mattata.send_reply(message, language.errors.unknown)
- end
- mattata.send_chat_action(message.chat.id, 'upload_photo')
- return mattata.send_photo(message.chat.id, photo, language['cats']['1'])
-end
-
-return cats
\ No newline at end of file
diff --git a/plugins/chatroulette.lua b/plugins/chatroulette.lua
deleted file mode 100644
index a1500d3..0000000
--- a/plugins/chatroulette.lua
+++ /dev/null
@@ -1,85 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local chatroulette = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function chatroulette:init(configuration)
- chatroulette.commands = mattata.commands(self.info.username):command('chatroulette'):command('endchat').table
- chatroulette.help = '/chatroulette - Connect yourself to another random user, and have a conversation with them! To end the chat, use /endchat.'
- chatroulette.limit = configuration.limits.chatroulette
-end
-
-function chatroulette:on_new_message(message, _, language)
- if message.chat.type ~= 'private' or message.text:match('^[/!#]') or (message.is_media and not message.text) then -- we only want to process non-command, text messages in private chat
- return false
- end
- local output
- local other_user = redis:get('chatroulette:' .. message.from.id)
- if not other_user then
- return false
- elseif message.text:len() > chatroulette.limit then -- we'll set a message length limit to stop a wall of text to the other user
- self.is_done = true
- output = string.format(language['chatroulette']['1'], chatroulette.limit)
- return mattata.send_message(message.from.id, output)
- end
- self.is_done = true
- output = string.format(language['chatroulette']['2'], mattata.escape_markdown(message.text))
- local success = mattata.send_message(other_user, output, true)
- if not success then -- if the message couldn't be sent it must mean the bot was blocked
- redis:del('chatroulette:' .. other_user)
- redis:del('chatroulette:' .. message.from.id)
- return mattata.send_message(message.from.id, language['chatroulette']['3'])
- end
- return success
-end
-
-function chatroulette.on_message(_, message, _, language)
- if message.chat.type ~= 'private' then
- return mattata.send_reply(message, language.errors.private)
- elseif message.command == 'endchat' then
- local existing = redis:get('chatroulette:' .. message.from.id)
- if existing then -- if their session hasn't ended, we'll force them to end it
- redis:del('chatroulette:' .. message.from.id)
- mattata.send_message(existing, language['chatroulette']['4']) -- send the other person a notification saying their session has ended
- redis:del('chatroulette:' .. existing)
- return mattata.send_message(message.from.id, language['chatroulette']['5'])
- elseif redis:get('chatroulette:searching:' .. message.from.id) then
- redis:del('chatroulette:searching:' .. message.from.id)
- return mattata.send_message(message.from.id, language['chatroulette']['6'])
- end
- return mattata.send_message(message.from.id, language['chatroulette']['7'])
- elseif message.command == 'chatroulette' then
- local success = mattata.send_message(message.from.id, language['chatroulette']['8'])
- if not success then
- return false
- end
- local available = redis:keys('chatroulette:searching:*')
- for pos, user in pairs(available) do
- if user:match('^chatroulette:searching:(.-)$') == tostring(message.from.id) then
- table.remove(available, pos)
- end
- end
- if #available == 0 then
- redis:set('chatroulette:searching:' .. message.from.id, true)
- return mattata.edit_message_text(message.from.id, success.result.message_id, language['chatroulette']['9'])
- end
- available = available[math.random(#available)]
- available = available:match('^chatroulette:searching:(.-)$')
- local paired = mattata.send_message(available, language['chatroulette']['10'])
- redis:del('chatroulette:searching:' .. available)
- if not paired then
- return mattata.edit_message_text(message.from.id, success.result.message_id, language['chatroulette']['11'])
- end
- redis:del('chatroulette:searching:' .. message.from.id)
- redis:set('chatroulette:' .. available, message.from.id)
- redis:set('chatroulette:' .. message.from.id, available)
- return mattata.edit_message_text(message.from.id, success.result.message_id, language['chatroulette']['12'])
- end
- return false
-end
-
-return chatroulette
\ No newline at end of file
diff --git a/plugins/commandstats.lua b/plugins/commandstats.lua
deleted file mode 100644
index b5d6ac5..0000000
--- a/plugins/commandstats.lua
+++ /dev/null
@@ -1,93 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local commandstats = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function commandstats:init()
- commandstats.commands = mattata.commands(self.info.username):command('commandstats'):command('cmdstats').table
- commandstats.help = '/commandstats - Shows statistical information about the current chat\'s top ten commands (ordered by message count). Alias: /cmdstats.'
-end
-
-function commandstats:on_new_message(message)
- if self.is_command then
- local command = message.text:match('^([!/#][%w_]+)')
- if command then
- redis:incr('commandstats:' .. message.chat.id .. ':' .. command)
- if not redis:sismember('chat:' .. message.chat.id .. ':commands', command) then
- redis:sadd('chat:' .. message.chat.id .. ':commands', command)
- end
- end
- end
-end
-
-function commandstats.reset_command_stats(chat_id)
- if not chat_id or tonumber(chat_id) == nil then
- return false
- end
- local messages = redis:keys('commandstats:' .. chat_id .. ':*')
- for _, v in pairs(messages) do
- redis:del(v)
- end
- return true
-end
-
-function commandstats.get_command_stats(chat_id, title, language)
- local commands = redis:smembers('chat:' .. chat_id .. ':commands')
- local statistics = {}
- for i = 1, #commands do
- local command = commands[i]
- local command_info = {
- ['command'] = command
- }
- command_info.count = redis:get('commandstats:' .. chat_id .. ':' .. command)
- if command_info.count and tonumber(command_info.count) ~= nil then
- table.insert(statistics, command_info)
- end
- end
- table.sort(statistics, function(a, b)
- if a.count and b.count then
- return tonumber(a.count) > tonumber(b.count)
- end
- end)
- local total = 0
- for _, v in pairs(statistics) do
- total = total + v.count
- end
- local text = ''
- local output = {}
- for i = 1, 10 do
- table.insert(output, statistics[i])
- end
- for _, v in pairs(output) do
- local percent = tostring(mattata.round((v.count / total) * 100, 1))
- text = text .. mattata.escape_html(v.command) .. ': <b>' .. mattata.comma_value(v.count) .. '</b> [' .. percent .. '%]\n'
- end
- if not text or text == '' then
- return language['commandstats']['1']
- end
- return string.format(
- language['commandstats']['2'],
- mattata.escape_html(title), text,
- mattata.comma_value(total):gsub('%..-$', '')
- )
-end
-
-function commandstats.on_message(_, message, _, language)
- if message.chat.type == 'private' then
- return mattata.send_message(message.chat.id, language.errors.supergroup)
- end
- local input = mattata.input(message.text)
- local output
- if input and input:lower() == 'reset' and mattata.is_group_admin(message.chat.id, message.from.id) then
- output = commandstats.reset_command_stats(message.chat.id) and language['commandstats']['3'] or language['commandstats']['4']
- return mattata.send_message(message.chat.id, output)
- end
- output = commandstats.get_command_stats(message.chat.id, message.chat.title, language)
- return mattata.send_message(message.chat.id, output, 'html')
-end
-
-return commandstats
\ No newline at end of file
diff --git a/plugins/copypasta.lua b/plugins/copypasta.lua
deleted file mode 100644
index 7ce76ea..0000000
--- a/plugins/copypasta.lua
+++ /dev/null
@@ -1,102 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local copypasta = {}
-local mattata = require('mattata')
-
-function copypasta:init(configuration)
- copypasta.commands = mattata.commands(self.info.username):command('copypasta'):command(utf8.char(128514)).table
- copypasta.help = '/copypasta - Riddles the replied-to message with cancerous emoji. Alias: /' .. utf8.char(128514) .. '.'
- copypasta.limit = configuration.limits.copypasta
-end
-
-function copypasta.aestheticise(input)
- if not input then
- return false
- end
- local output = {}
- for char in input:gmatch('.') do
- local success, point = pcall(function()
- return utf8.codepoint(char)
- end)
- if success and (point >= 33 and point <= 126) then
- table.insert(output, utf8.char(point + 65248))
- else
- table.insert(output, char)
- end
- end
- output = table.concat(output)
- return output
-end
-
-function copypasta.format_message(input)
- local emoji = {
- 128514, -- crying with laughter
- 128514,
- 128514,
- 128076, -- ok hand
- 128076,
- 128166, -- water drops
- 128166,
- 128064, -- eyes
- 128064,
- 9996, -- peace sign hand
- 128158, -- rotating hearts
- 128077, -- thumbs up
- 128175, -- 100//
- 127926, -- music symbol
- 128083, -- glasses
- 128079, -- clapping hands
- 128080, -- open hands
- 127829, -- pizza slice
- 128165, -- explosion
- 127860, -- knife and fork
- 127825, -- peach
- 127814, -- aubergine
- 128553, -- moaning face
- 128527, -- smirking face
- 128073, -- finger pointing to right
- 128069, -- tongue
- 128553 -- moaning face
- }
- local output = {}
- for i = 1, input:len() do
- local char = input:sub(i, i)
- math.random(os.time())
- if char == ' ' then
- local rnd_total = math.random(#emoji)
- local rnd_emoji = utf8.char(emoji[rnd_total])
- if math.random(2) == 2
- then
- rnd_total = math.random(#emoji)
- rnd_emoji = rnd_emoji .. ' ' .. utf8.char(emoji[rnd_total])
- end
- char = char .. rnd_emoji .. char
- elseif math.random(5) == 5 then
- char = char:lower()
- end
- table.insert(output, char)
- end
- output = table.concat(output)
- output = copypasta.aestheticise(output)
- return output
-end
-
-function copypasta.on_message(_, message, _, language)
- if not message.reply then
- return mattata.send_reply(message, copypasta.help)
- end
- local output
- mattata.send_chat_action(message.chat.id)
- if message.reply.text:len() > copypasta.limit then
- output = string.format(language['copypasta']['1'], copypasta.limit)
- return mattata.send_reply(message, output)
- end
- output = copypasta.format_message(message.reply.text:upper())
- message.message_id = message.reply.message_id
- return mattata.send_reply(message, output)
-end
-
-return copypasta
\ No newline at end of file
diff --git a/plugins/coronavirus.lua b/plugins/coronavirus.lua
deleted file mode 100644
index ab5c3a1..0000000
--- a/plugins/coronavirus.lua
+++ /dev/null
@@ -1,68 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local coronavirus = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local json = require('dkjson')
-
-function coronavirus:init()
- coronavirus.commands = mattata.commands(self.info.username):command('coronavirus'):command('corona'):command('covid19'):command('covid').table
- coronavirus.help = '/coronavirus [country]. Returns the global COVID-19 statistics. Optionally, a country may be specified by its country code or name. Aliases: /corona, /covid19, /covid.'
- coronavirus.url = 'https://api.covid19api.com/summary'
-end
-
-
-function coronavirus.on_message(_, message, _, language)
- local jstr, res = https.request(coronavirus.url)
- if res ~= 200 then
- return mattata.send_reply(message, language.errors.connection)
- end
- local jdat = json.decode(jstr)
- if not jdat.Global and not jdat.Countries then
- return mattata.send_reply(message, language.errors.results)
- end
- local input = mattata.input(message.text)
- local found_match, country_position, output = false
- if jdat.Global and (not input or (input:lower() == 'global' or input:lower() == 'world')) then
- output = language['coronavirus']['1']
- local country_name = 'Everywhere'
- local new_confirmed = mattata.comma_value(jdat.Global.NewConfirmed)
- local total_confirmed = mattata.comma_value(jdat.Global.TotalConfirmed)
- local new_deaths = mattata.comma_value(jdat.Global.NewDeaths)
- local total_deaths = mattata.comma_value(jdat.Global.TotalDeaths)
- local new_recovered = mattata.comma_value(jdat.Global.NewRecovered)
- local total_recovered = mattata.comma_value(jdat.Global.TotalRecovered)
- output = string.format(output, country_name, new_confirmed, total_confirmed, new_deaths, total_deaths, new_recovered, total_recovered)
- elseif input and jdat.Countries then
- for k, v in pairs(jdat.Countries) do
- if input:len() == 2 then
- input = input:lower() == 'uk' and 'gb' or input:lower()
- if input == v.CountryCode:lower() then
- found_match, country_position = true, k
- end
- else
- if v.Country:lower():match(input:lower()) then
- found_match, country_position = true, k
- end
- end
- end
- end
- if found_match then
- output = language['coronavirus']['1']
- local country_name = jdat.Countries[country_position].Country
- local new_confirmed = mattata.comma_value(jdat.Countries[country_position].NewConfirmed)
- local total_confirmed = mattata.comma_value(jdat.Countries[country_position].TotalConfirmed)
- local new_deaths = mattata.comma_value(jdat.Countries[country_position].NewDeaths)
- local total_deaths = mattata.comma_value(jdat.Countries[country_position].TotalDeaths)
- local new_recovered = mattata.comma_value(jdat.Countries[country_position].NewRecovered)
- local total_recovered = mattata.comma_value(jdat.Countries[country_position].TotalRecovered)
- output = string.format(output, country_name, new_confirmed, total_confirmed, new_deaths, total_deaths, new_recovered, total_recovered)
- end
- output = output or language.errors.results
- return mattata.send_reply(message, output, 'markdown')
-end
-
-return coronavirus
\ No newline at end of file
diff --git a/plugins/currency.lua b/plugins/currency.lua
deleted file mode 100644
index 4dd6d5f..0000000
--- a/plugins/currency.lua
+++ /dev/null
@@ -1,44 +0,0 @@
---[[
- Based on a plugin by topkecleon. Licensed under GNU AGPLv3
- https://github.com/topkecleon/otouto/blob/master/LICENSE.
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local currency = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-
-function currency:init()
- currency.commands = mattata.commands(self.info.username):command('currency'):command('convert'):command('cash').table
- currency.help = '/currency <amount> <from> to <to> - Converts exchange rates for various currencies via Google Finance. Aliases: /convert, /cash.'
- currency.url = 'https://www.google.com/finance/converter?from=%s&to=%s&a=%s'
-end
-
-function currency.on_message(_, message, _, language)
- local input = mattata.input(message.text:upper())
- if input then
- input = input:gsub('%$', 'USD'):gsub('€', 'EUR'):gsub('£', 'GBP')
- end
- if not input or not input:match('^.- %a%a%a TO %a%a%a$') then
- return mattata.send_reply(message, currency.help)
- end
- local amount, from, to = input:match('^(.-) (%a%a%a) TO (%a%a%a)$')
- amount = tonumber(amount) or 1
- local result = 1
- if from ~= to then
- local str, res = https.request(string.format(currency.url, from, to, amount))
- if res ~= 200 then
- return mattata.send_reply(message, language.errors.connection)
- end
- str = str:match('<span class=bld>(.-) %u+</span>')
- if not str then
- return mattata.send_reply(message, language.errors.results)
- end
- result = string.format('%.2f', str)
- end
- result = string.format('%s %s = %s %s', amount, from, result, to)
- return mattata.send_message(message.chat.id, result)
-end
-
-return currency
\ No newline at end of file
diff --git a/plugins/delsticker.lua b/plugins/delsticker.lua
deleted file mode 100644
index 65bb867..0000000
--- a/plugins/delsticker.lua
+++ /dev/null
@@ -1,28 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local delsticker = {}
-local mattata = require('mattata')
-
-function delsticker:init()
- delsticker.commands = mattata.commands(self.info.username):command('delsticker').table
- delsticker.help = '/delsticker - Deletes the replied-to sticker from your sticker pack.'
-end
-
-function delsticker.on_message(_, message)
- if not message.reply or not message.reply.sticker then
- return mattata.send_reply(message, 'You must use this command in reply to a sticker!')
- elseif message.reply.sticker.is_animated then
- return mattata.send_reply(message, 'I\'m afraid animated stickers aren\'t supported at the moment.')
- end
- local success, res = mattata.delete_sticker_from_set(message.reply.file_id)
- if not success then
- local description = res.description:match('STICKERSET_NOT_MODIFIED') and 'It appears that sticker has already been deleted from your pack!' or 'I don\'t have permission to delete that sticker, are you sure it\'s from your pack?'
- return mattata.send_reply(message, 'An error occurred. ' .. description)
- end
- return mattata.send_reply(message, 'I\'ve successfully removed that sticker from your pack!')
-end
-
-return delsticker
\ No newline at end of file
diff --git a/plugins/dice.lua b/plugins/dice.lua
deleted file mode 100644
index c0f5a78..0000000
--- a/plugins/dice.lua
+++ /dev/null
@@ -1,35 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local dice = {}
-local mattata = require('mattata')
-
-function dice:init()
- dice.commands = mattata.commands(self.info.username):command('dice'):command('roll').table
- dice.types = {
- utf8.char(127936),
- utf8.char(127922),
- utf8.char(127919)
- }
- dice.help = '/dice [type] - Returns an animated dice roll, basketball shot or dart throw (randomly chosen). Optionally, you can specify the type via parameter (ball/dice/dart). Alias: /roll.'
-end
-
-function dice.on_message(_, message)
- local input = mattata.input(message.text)
- local output = dice.types[math.random(#dice.types)]
- if input and (input:lower() == 'basketball' or input:lower() == 'ball') then
- output = dice.types[1]
- elseif input and (input:lower() == 'dice' or input:lower() == 'die') then
- output = dice.types[2]
- elseif input and input:lower() == 'dart' then
- output = dice.types[3]
- end
- if math.random(100) == 100 then
- return mattata.send_sticker(message.chat.id, 'CAACAgQAAx0CQNYPUgABATQCXtmOk9jz2lCN7omTIjCqmLa08hUAAkAAA8j67BMAAUvGUioKrK4aBA')
- end
- return mattata.send_dice(message.chat.id, output)
-end
-
-return dice
\ No newline at end of file
diff --git a/plugins/dictionary.lua b/plugins/dictionary.lua
deleted file mode 100644
index b789949..0000000
--- a/plugins/dictionary.lua
+++ /dev/null
@@ -1,60 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local dictionary = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local ltn12 = require('ltn12')
-local json = require('dkjson')
-
-function dictionary:init(configuration)
- dictionary.commands = mattata.commands(self.info.username):command('dictionary'):command('define').table
- dictionary.help = '/dictionary <word> - Looks up the given word in the Oxford Dictionary and returns the relevant definition(s). Alias: /define.'
- dictionary.url = 'https://od-api.oxforddictionaries.com/api/v1/entries/en/'
- dictionary.id = configuration.keys.dictionary.id
- dictionary.key = configuration.keys.dictionary.key
-end
-
-function dictionary.on_message(_, message, _, language)
- local input = mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, dictionary.help)
- end
- local body = {}
- local _, res = https.request({
- ['url'] = dictionary.url .. url.escape(input),
- ['headers'] = {
- ['app_id'] = dictionary.id,
- ['app_key'] = dictionary.key
- },
- ['sink'] = ltn12.sink.table(body),
- })
- if res ~= 200 then
- return mattata.send_reply(message, language.errors.connection)
- end
- body = table.concat(body)
- local jdat = json.decode(body)
- if not jdat or not jdat.results[1] or not jdat.results[1].word or not jdat.results[1].lexicalEntries then
- return mattata.send_reply(message, language.errors.results)
- end
- local word = jdat.results[1].word
- word = mattata.escape_html(word)
- local results = #jdat.results[1].lexicalEntries
- results = tonumber(results) > 4 and 4 or results
- local definitions = {}
- for i = 1, results do
- if jdat.results[1] and jdat.results[1].lexicalEntries and jdat.results[1].lexicalEntries[i].entries and jdat.results[1].lexicalEntries[i].entries[1].senses and jdat.results[1].lexicalEntries[i].entries[1].senses[1].definitions then
- local entry = jdat.results[1].lexicalEntries[i].entries[1].senses[1].definitions[1]
- entry = entry:gsub(':$', ''):gsub('%.$', '')
- entry = mattata.escape_html(entry)
- table.insert(definitions, '• ' .. entry)
- end
- end
- local output = '<b>' .. word .. '</b>\n\n' .. table.concat(definitions, '\n')
- return mattata.send_message(message.chat.id, output, 'html')
-end
-
-return dictionary
\ No newline at end of file
diff --git a/plugins/dismiss.lua b/plugins/dismiss.lua
deleted file mode 100644
index 613aab4..0000000
--- a/plugins/dismiss.lua
+++ /dev/null
@@ -1,16 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local dismiss = {}
-local mattata = require('mattata')
-
-function dismiss.on_callback_query(_, _, message)
- if message then
- return mattata.delete_message(message.chat.id, message.message_id)
- end
- return
-end
-
-return dismiss
\ No newline at end of file
diff --git a/plugins/doge.lua b/plugins/doge.lua
deleted file mode 100644
index eab3b96..0000000
--- a/plugins/doge.lua
+++ /dev/null
@@ -1,33 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local doge = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function doge:init()
- doge.commands = mattata.commands(self.info.username):command('doge').table
- doge.help = '/doge <text> - Doge-ifies the given text. Sentences should be separated using slashes or new lines. Example: /doge hello world/this is a test sentence/make sure you type like this/else it won\'t work!'
-end
-
-function doge.on_message(_, message, _, language)
- local input = message.reply and message.reply.text or mattata.input(message.text)
- if not input then
- local success = mattata.send_force_reply(message, language['doge']['1'])
- if success then
- redis:set('action:' .. message.chat.id .. ':' .. success.result.message_id, '/doge')
- end
- return
- elseif message.reply then
- input = input:gsub(' ', '\n')
- end
- local url = 'http://dogr.io/' .. input:gsub(' ', '%%20'):gsub('\n', '/') .. '.png?split=false&.png'
- if not url:match('https?://[%%%w-_%.%?%.:/%+=&]+') == url then -- Validate the URL.
- return mattata.send_reply(message, language['errors']['results'])
- end
- return mattata.send_photo(message.chat.id, url)
-end
-
-return doge
\ No newline at end of file
diff --git a/plugins/donate.lua b/plugins/donate.lua
deleted file mode 100644
index 36b6184..0000000
--- a/plugins/donate.lua
+++ /dev/null
@@ -1,19 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local donate = {}
-local mattata = require('mattata')
-
-function donate:init()
- donate.commands = mattata.commands(self.info.username):command('donate').table
- donate.help = '/donate - Make an optional, monetary contribution to the mattata project.'
-end
-
-function donate.on_message(_, message, _, language)
- local output = string.format(language['donate']['1'], mattata.escape_html(message.from.first_name))
- return mattata.send_message(message.chat.id, output, 'html')
-end
-
-return donate
\ No newline at end of file
diff --git a/plugins/drawtext.lua b/plugins/drawtext.lua
deleted file mode 100644
index deb748a..0000000
--- a/plugins/drawtext.lua
+++ /dev/null
@@ -1,33 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local drawtext = {}
-local mattata = require('mattata')
-local http = require('socket.http')
-local url = require('socket.url')
-
-function drawtext:init(configuration)
- drawtext.commands = mattata.commands(self.info.username):command('drawtext').table
- drawtext.help = '/drawtext [text] - Converts the given/replied-to text to an image.'
- drawtext.limit = configuration.limits.drawtext
- drawtext.url = 'http://api.img4me.com/?font=arial&size=24&bcolor=&type=png&text='
-end
-
-function drawtext.on_message(_, message, _, language)
- local input = message.reply and message.reply.text or mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, drawtext.help)
- elseif input:len() > drawtext.limit then
- input = input:sub(1, (drawtext.limit - 3)) .. '...'
- end
- local str, res = http.request(drawtext.url .. url.escape(input))
- if not str or res ~= 200 then
- return mattata.send_reply(message, language.errors.connection)
- end
- mattata.send_chat_action(message.chat.id, 'upload_photo')
- return mattata.send_photo(message.chat.id, str)
-end
-
-return drawtext
\ No newline at end of file
diff --git a/plugins/echo.lua b/plugins/echo.lua
deleted file mode 100644
index 68bc3d0..0000000
--- a/plugins/echo.lua
+++ /dev/null
@@ -1,25 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local echo = {}
-local mattata = require('mattata')
-
-function echo:init()
- echo.commands = mattata.commands(self.info.username):command('echo'):command('say').table
- echo.help = '/echo <text> - Repeats the given string of text. Append -del to the end of your text to delete your command message. Alias: /say.'
-end
-
-function echo.on_message(_, message)
- local input = mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, echo.help)
- elseif input:match(' %-d$') then
- input = input:match('^(.-) %-d$')
- mattata.delete_message(message.chat.id, message.message_id)
- end
- return mattata.send_message(message.chat.id, input)
-end
-
-return echo
\ No newline at end of file
diff --git a/plugins/exec.lua b/plugins/exec.lua
deleted file mode 100644
index 6be8373..0000000
--- a/plugins/exec.lua
+++ /dev/null
@@ -1,205 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local exec = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local ltn12 = require('ltn12')
-local multipart = require('multipart-post')
-local json = require('dkjson')
-local redis = require('libs.redis')
-
-function exec:init()
- exec.commands = mattata.commands(self.info.username):command('exec').table
- exec.help = '/exec <language> <code> - Executes the specified code in the given language and returns the output.'
- exec.languages = {
- ['C#'] = 1,
- ['VB.NET'] = 2,
- ['Java'] = 4,
- ['Python'] = 5,
- ['PHP'] = 8,
- ['Pascal'] = 9,
- ['Objective-C'] = 10,
- ['Haskell'] = 11,
- ['Ruby'] = 12,
- ['Perl'] = 13,
- ['Lua'] = 14,
- ['JavaScript'] = 17,
- ['GoLang'] = 20,
- ['Node.js'] = 23,
- ['Python 3'] = 24,
- ['C'] = 26,
- ['C++'] = 27,
- ['MySQL'] = 33,
- ['Swift'] = 37,
- ['Bash'] = 38
- }
-end
-
-function exec.get_keyboard(user_id)
- local keyboard = {
- ['inline_keyboard'] = {{}}
- }
- local total = 0
- for _, _ in pairs(exec.languages) do
- total = total + 1
- end
- local count = 0
- local rows = math.floor(total / 8)
- if rows ~= total then
- rows = rows + 1
- end
- local row = 1
- for k, v in pairs(exec.languages) do
- count = count + 1
- if count == rows * row then
- row = row + 1
- table.insert(keyboard.inline_keyboard, {})
- end
- local last_used = redis:hget('user:' .. user_id .. ':info', 'last_used_exec_lang')
- if last_used and last_used == tostring(v) then
- k = utf8.char(9889) .. ' ' .. k
- end
- table.insert(keyboard.inline_keyboard[row], {
- ['text'] = k,
- ['callback_data'] = 'exec:' .. user_id .. ':' .. tostring(v) .. ':n'
- })
- end
- return keyboard
-end
-
-function exec.get_arguments(language)
- language = tonumber(language)
- if language == 6 or language == 26 then
- return '-Wall -std=gnu99 -O2 -o a.out source_file.c'
- elseif language == 7 or language == 27 then
- return '-Wall -std=c++14 -O2 -o a.out source_file.cpp'
- elseif language == 28 then
- return 'source_file.cpp -o a.exe /EHsc /MD /I C:\\\\boost_1_60_0 /link /LIBPATH:C:\\\\boost_1_60_0\\\\stage\\\\lib'
- elseif language == 29 then
- return 'source_file.c -o a.exe'
- elseif language == 30 then
- return 'source_file.d -ofa.out'
- elseif language == 20 then
- return '-o a.out source_file.go'
- elseif language == 11 then
- return '-o a.out source_file.hs'
- elseif language == 10 then
- return '-MMD -MP -DGNUSTEP -DGNUSTEP_BASE_LIBRARY=1 -DGNU_GUI_LIBRARY=1 -DGNU_RUNTIME=1 -DGNUSTEP_BASE_LIBRARY=1 -fno-strict-aliasing -fexceptions -fobjc-exceptions -D_NATIVE_OBJC_EXCEPTIONS -pthread -fPIC -Wall -DGSWARN -DGSDIAGNOSE -Wno-import -g -O2 -fgnu-runtime -fconstant-string-class=NSConstantString -I. -I /usr/include/GNUstep -I/usr/include/GNUstep -o a.out source_file.m -lobjc -lgnustep-base'
- end
- return ''
-end
-
-function exec.make_request(language, code)
- language = language:lower()
- local args = exec.get_arguments(language)
- local parameters = {
- ['LanguageChoice'] = language,
- ['Program'] = code,
- ['Input'] = 'stdin',
- ['CompilerArgs'] = args
- }
- local response = {}
- local body, boundary = multipart.encode(parameters)
- local old_timeout = https.TIMEOUT
- https.TIMEOUT = 5
- local _, res = https.request({
- ['url'] = 'https://rextester.com/rundotnet/api/',
- ['method'] = 'POST',
- ['headers'] = {
- ['Content-Type'] = 'multipart/form-data; boundary=' .. boundary,
- ['Content-Length'] = #body
- },
- ['source'] = ltn12.source.string(body),
- ['sink'] = ltn12.sink.table(response)
- })
- https.TIMEOUT = old_timeout
- if res ~= 200 then
- return false
- end
- local jdat = json.decode(table.concat(response))
- local output = {}
- if jdat.Result and jdat.Result ~= '' then
- if utf8.len(jdat.Result) > 2000 then
- jdat.Result = jdat.Result:sub(1, 2000) .. '...'
- end
- table.insert(output, '<b>Result</b>\n<pre>' .. mattata.escape_html(jdat.Result) .. '</pre>')
- end
- if jdat.Warnings and jdat.Warnings ~= '' then
- if utf8.len(jdat.Warnings) > 2000 then
- jdat.Warnings = jdat.Warnings:sub(1, 2000) .. '...'
- end
- table.insert(output, '<b>Warnings</b>\n' .. mattata.escape_html(jdat.Warnings))
- end
- if jdat.Errors and jdat.Errors ~= '' then
- if utf8.len(jdat.Errors) > 2000 then
- jdat.Errors = jdat.Errors:sub(1, 2000) .. '...'
- end
- table.insert(output, '<b>Errors</b>\n' .. mattata.escape_html(jdat.Errors))
- end
- if jdat.Stats and jdat.Stats ~= '' then
- local stats = jdat.Stats:gsub('%, ', '\n• '):gsub('cpu', 'CPU'):gsub('memory', 'Memory'):gsub('absolute', 'Absolute'):gsub('%,', '.')
- table.insert(output, '<b>Statistics</b>\n• ' .. mattata.escape_html(stats))
- end
- return table.concat(output, '\n')
-end
-
-function exec.on_callback_query(_, callback_query, message, _, language)
- local user_id, lang, confirmed = callback_query.data:match('^(%d+):(.-):(.-)$')
- if not user_id or not lang or not message.reply or callback_query.from.id ~= tonumber(user_id) then
- return mattata.answer_callback_query(callback_query.id, language.errors.generic)
- elseif lang == 'back' then
- return mattata.edit_message_text(message.chat.id, message.message_id, language['exec']['1'], nil, true, exec.get_keyboard(user_id))
- end
- local code = mattata.input(message.reply.text) or message.reply.text
- if not code then
- return
- end
- local language_name
- for k, v in pairs(exec.languages) do
- if tostring(v) == lang then
- language_name = k
- end
- end
- local output
- if not language_name then
- return
- elseif confirmed == 'y' then
- redis:hset('user:' .. user_id .. ':info', 'last_used_exec_lang', lang)
- output = exec.make_request(lang, code) or language['exec']['2'] .. ' ' .. utf8.char(128527)
- return mattata.edit_message_text(message.chat.id, message.message_id, output, 'html')
- end
- output = string.format(language['exec']['3'], language_name)
- local keyboard = mattata.inline_keyboard():row(
- mattata.row():callback_data_button(
- language['exec']['4'],
- 'exec:' .. user_id .. ':back:n'
- ):callback_data_button(
- language['exec']['5'],
- string.format('exec:%s:%s:y', user_id, tostring(lang))
- ))
- return mattata.edit_message_text(message.chat.id, message.message_id, output, nil, true, keyboard)
-end
-
-function exec.on_message(_, message, _, language)
- local input = mattata.input(message.text)
- if not input then
- local success = mattata.send_force_reply(message, language['exec']['6'])
- if success then
- local key = string.format('action:%s:%s', message.chat.id, success.result.message_id)
- redis:set(key, '/exec')
- end
- return
- end
- mattata.send_chat_action(message.chat.id)
- return mattata.send_message(
- message, language['exec']['7'],
- 'html', true, false,
- message.message_id,
- exec.get_keyboard(message.from.id)
- )
-end
-
-return exec
\ No newline at end of file
diff --git a/plugins/facebook.lua b/plugins/facebook.lua
deleted file mode 100644
index b5589e1..0000000
--- a/plugins/facebook.lua
+++ /dev/null
@@ -1,69 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local facebook = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local redis = require('libs.redis')
-
-function facebook:init()
- facebook.commands = mattata.commands(self.info.username):command('facebook'):command('fbook').table
- facebook.help = '/facebook <Facebook username> - Sends the profile picture of the given Facebook user. Alias: /fbook.'
-end
-
-function facebook.get_avatar(user)
- local str = https.request('https://www.facebook.com/' .. url.escape(user))
- if not str or not str:match(',"entity_id":"(.-)"}') then
- return false
- end
- local _, _, res = https.request({
- ['url'] = 'https://graph.facebook.com/' .. str:match(',"entity_id":"(.-)"}') .. '/picture?type=large&width=5000&height=5000',
- ['redirect'] = false
- })
- if not res or not res.location then
- return false
- end
- return res.location
-end
-
-function facebook.on_inline_query(_, inline_query, _, language)
- local input = mattata.input(inline_query.query)
- if not input then
- return
- end
- local output = facebook.get_avatar(input)
- if not output then
- return mattata.send_inline_article(
- inline_query.id,
- language['facebook']['1'],
- language['errors']['results']
- )
- end
- return mattata.send_inline_photo(inline_query.id, output)
-end
-
-function facebook.on_message(_, message, _, language)
- local input = mattata.input(message.text)
- if not input then
- local success = mattata.send_force_reply(message, language['facebook']['2'])
- if success then
- local action = string.format('action:%s:%s', message.chat.id, success.result.message_id)
- redis:set(action, '/facebook')
- end
- return
- elseif input:match('^@.-$') then
- input = input:match('^@(.-)$')
- end
- local output = facebook.get_avatar(input)
- if not output then
- return mattata.send_reply(message, language.errors.results)
- end
- local button_text = string.format(language['facebook']['3'], input)
- local keyboard = mattata.inline_keyboard():row(mattata.row():url_button(button_text, 'https://www.facebook.com/' .. url.escape(input)))
- return mattata.send_photo(message.chat.id, output, nil, false, message.message_id, keyboard)
-end
-
-return facebook
\ No newline at end of file
diff --git a/plugins/fact.lua b/plugins/fact.lua
deleted file mode 100644
index bd65474..0000000
--- a/plugins/fact.lua
+++ /dev/null
@@ -1,1050 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local fact = {}
-local mattata = require('mattata')
-
-function fact:init()
- fact.commands = mattata.commands(self.info.username):command('fact').table
- fact.help = '/fact - Returns a random, and somewhat incorrect, fact.'
-end
-
-local facts = {
- 'Koalas\' teeth are strong enough to bend time and space.',
- 'There hasn\'t been a person named Stanley for 10 years.',
- 'Beethoven was the first man to hear the sound of clowns arguing.',
- 'Nobody can explain how a computer works.',
- 'The term WiFi stands for "Wireless info For internets".',
- 'Caffeine is derived from sunflower seeds.',
- '94% of US citizens report that they\'re allergic to camera lenses.',
- 'Pen ink consists mostly of citric acid.',
- 'Most movie scripts are written underwater.',
- 'Google is the highest rated restaurant in California.',
- 'Yawning causes bones to break more easily.',
- 'Loud music is known to soothe camels.',
- 'There are only 2 male koalas on the planet.',
- 'Baby carriages are often made out of recycled Dell computers.',
- 'Glass generates about 12% of the world\'s electricity.',
- 'Fire has no reflection in mirrors.',
- 'Ryan Reynolds was the first person to count to 5.',
- 'Men usually grow facial hair by the first time they hear bird chirp for the 30th time.',
- 'Ducks can\'t feel water.',
- 'Feathers are 2 times heavier on Tuesdays.',
- 'The actor Nicolas Cage is actually three different people.',
- 'Google is the only company in the world to own a water fountain in Europe.',
- 'There are 86 people in the United Kingdom named Ron.',
- 'Samsung is the manufacturer of the majority of women\'s hygiene products.',
- 'Over 85% of childbirths are indirectly caused by members of Reddit.',
- 'iPhone users can\'t see the color purple.',
- 'YouTube videos will be limited to a maximum of 23 seconds starting March 2015.',
- 'People eat on average at least 3 pairs of scissors in their lifetime.',
- 'Pigs are incredibly scared of the sound of cats meowing.',
- 'When you cut a piece of paper, you\'re actually sliding two separate pieces away from each other.',
- 'It\'s very commonplace to trade punches with a close friend on holidays in the United States.',
- 'Walls in houses were made almost completely out of sandpaper in the 1960s.',
- 'The Leaning Tower of Pisa is actually only worth about $45 because of the fact that it does not stand straight up.',
- 'One whole season of the show It\'s Always Sunny in Philadelphia features only stunt doubles and none of the actual cast.',
- 'No movie exists that includes Matt Damon and a cell phone in the entire movie.',
- 'The older cats become, the more they can only smell the scent of AXE Bodyspray.',
- 'New Yorkers are best known for exclusively drinking Mountain Dew and nothing else.',
- 'Saliva is the only thing able to melt glass.',
- 'Nokia phones are the only things known to man capable of communicating with hamsters.',
- 'iTunes is the most popular choice of desk brand.',
- 'Elijah Wood was crowned King of Root Beer 6 times in 2011.',
- 'Bears don\'t eat.',
- 'Twitter\'s headquarters are located in New York City from 9pm to 11pm EST Monday through Tuesday.',
- 'Sleeping reduces your chances of dying.',
- 'Reading was considered a feat of strength in the 1700s.',
- 'Twins are more likely to get amnesia than most people.',
- 'Each member of Linkin Park has been knighted at some point.',
- 'Hockey was first played in the summer of 2002.',
- 'Today is National Pi Day.',
- 'Marijuana is actually legal in all 50 states; the government just hasn\'t told any of the smokers of it about it.',
- 'Love is often compared to cake.',
- 'Sadness causes cancer in 94% of all lady bugs.',
- 'Clothes lose their color after 23 days.',
- 'Candy bars are not permitted to contain any food-like substances.',
- 'Involuntarily making odd faces is often a sign of being blind in one eye.',
- 'A total of 7 people have never been in a car.',
- 'The first QR Code was used on November 8, 1994.',
- 'On a list of Americans\' most favorite words, "Potpourri" came in 2nd, behind "pseudopseudohypoparathyroidism".',
- 'Most modern calendars do not include 7 days of the week.',
- 'The term "beat boxing" comes from illiterate sailors who punched various cardboard boxes in their spare time.',
- 'A recent study showed that a total of 1,484 Americans are not named Jennifer.',
- 'Walruses are avid readers of romance novels.',
- 'Netflix is owned by Amazon, which is owned by Google, which is owned by some guy in Minnesota.',
- '3D printers were first mass-produced in a small Brazilian town in 1984.',
- 'Catnip is generally thought to be extremely dangerous if looked at under direct sunlight.',
- 'Ferrets don\'t have functional eyes.',
- 'Dell computers are the sole reason that Internet Explorer is the most liked web browser.',
- '4% of the average human body is made of aluminum.',
- 'Being generous is the leading cause of death in the United States.',
- 'The word "escape" was coined by a man in prison trying to describe his departure from the prison. Ironically, he never actually escaped.',
- 'The universal sign of friendship is a punch in the face.',
- 'No one has laid eyes upon a wooden boat since the early 1700s.',
- 'Telling jokes decreases your lifespan by 23 minutes per joke told.',
- 'Hair grows faster than normal every 8 years.',
- 'The state of Ohio passed a law in 1994 banning the use of mini fridges.',
- '86% of men report that they don\'t have a tongue.',
- 'There are no windows in South America.',
- 'Calendars are unknown to the people of western California.',
- 'The most common cause of vehicle-related injuries is ferrets.',
- 'A survey of 100 people found that 26% of them had a disease known as "Fleeing Mustache", where their mustache falls off of their face about every 2 days.',
- 'Peanut butter products can be used to cure the common cold.',
- 'The first person to buy an iPhone was a man named Heinrich McDominferbincoughcough.',
- 'The word \'mouse\' is supposed to be spelled \'paper\'.',
- 'Most people can\'t touch glass without screaming.',
- 'Sales of trains have gone up 836% since January 23, 2014.',
- 'Gorillas were trained to use cell phones by Brazilians in 1949.',
- 'Tacos were first made to mimic the shape of a cat\'s tail.',
- 'Android cell phones are often commonly confused to be able to cause paper-based objects to achieve flight.',
- 'The common expression "a bird in the hand is worth two in the bush" originally was slang for "hey, take a look at that bird".',
- 'Tigers have no sense of smell.',
- 'Every time a door is opened, someone buys a blue desk.',
- 'On November 10 of every year, the sun is only about 1,000 miles away from Earth.',
- 'Although very few know it, the lead singer of AC/DC provided most of vocals for the song Poker Face by Lady Gaga.',
- 'As of the year 2014, wallets have caused more fatal injuries than knives have.',
- 'When you sneeze, your body is actually putting itself to sleep for a brief moment.',
- 'Nicolas Cage was one of the original inventors of the radio.',
- 'Most wallpaper is made out of recycled receipts from Amazon.',
- 'The first laptop ever created was actually the most powerful laptop there has ever been.',
- 'The average snowflake contains about one ounce of water.',
- 'Fingernails are about 140% stronger than iron.',
- 'Hospitals are commonly occupied by raccoons.',
- 'The first dinosaur was a dog.',
- 'Most Facebook users can\'t see the color blue.',
- 'Every time you read a sentence, you become slightly more illiterate.',
- 'Horses go into bars every Friday.',
- 'The first pyramid that was built was intended to be in the shape of a circle.',
- 'Will Smith can\'t count to 3, but can count to 26.',
- 'Windows 8 is the most popular version of Windows since Mac.',
- 'Facebook purchased the country of Germany on January 23, 2008.',
- 'There are 26 different variations of the color red.',
- '9 o\'clock in the morning was not an official time until 1945.',
- 'Air in Texas is contaminated with high amounts of iron.',
- '20 trillion minutes of pornography is uploaded to YouTube every hour.',
- 'Levitation is illegal in Arkansas.',
- 'Family Guy is very popular on Pluto.',
- 'During December, Cinnamon is commonly sold in 36 different flavors.',
- 'For a brief period of time during 2009, Elvis Presley rose from the dead to appear in the movie Batman Begins.',
- 'Most books that are published nowadays feature 2 pages made from peanut butter.',
- 'An average human will only ever use 1% of their brain.',
- 'Windows 8 (as of November 24) has seen more sales than Star Wars.',
- 'Disney is considering buying Microsoft.',
- 'Adobe was the original creator of the iPod.',
- 'iTunes was originally created by Toshiba.',
- 'There are plans to make a sequel to Iron Man 3 called Iron Man 3 2.',
- 'Chicken tastes like bacon once every month.',
- 'As of November 22, 2012, Pink Floyd has re-released the album "The Wall" 33 times.',
- 'Zippo lighters are considered weapons of mass destruction in 18 states.',
- 'Mathematics doesn\'t exist on Sundays.',
- 'Every time Nicolas Cage receives a message on Facebook, a Mac computer is hit with a sledge hammer.',
- 'Only 11 people on earth can touch their toes.',
- 'Gloves don\'t make your hands warmer if it is exactly 33 degrees outside.',
- 'This sentence is not a question?',
- 'The English language is based on Braille.',
- 'Orlando, Florida is the home of Los Angeles, California.',
- 'It\'s illegal to give someone your business card in Japan.',
- 'Cats are unable to see the color white.',
- 'Smoking cigarettes is known to attract rabid giraffes.',
- 'Drinking 1 beer is the equivalent of eating 36 pieces of bacon.',
- 'The world\'s electricity is provided solely by Adam Sandler.',
- 'The first car was a horse. His name was Bert.',
- 'Bears will not attack you if they can\'t see your eyes.',
- 'The average human heart can withstand about 23 pounds of pressure.',
- 'You have to be at least 18 years old to attend preschool.',
- 'Tourism is illegal in Nevada.',
- 'Most cheeses do not have an expiration date.',
- 'Only 1 person in the whole world is named Thomas Mays. That person\'s name is Nicolas Cage.',
- 'Underage drinking is the leading cause of HIV in Canada.',
- 'Phones are the sturdiest phones known to man.',
- 'Being in love causes cancer.',
- 'Bears cannot smell grass.',
- 'There are only about 1200 facts in existence.',
- 'Intel is currently creating a processor that runs purely on tobacco.',
- 'Most llamas are purple.',
- 'Halloween is an Islamic holiday.',
- 'Osama Bin Laden was actually your mother.',
- 'Keyboards usually weigh about 12 pounds in Europe.',
- 'Books will no longer be legal to read on November 13, 2012.',
- 'This sentance doesnt contain speling erors.',
- 'There\'s no such thing as a rainbow.',
- 'The iPad Mini never existed.',
- 'Oprah invented the first light bulb.',
- 'Halo 4 inspired Bill Gates to invent the Internet.',
- 'The Constitution was first written on a credit card.',
- 'Barrack Obama is the President of the Moon.',
- 'Microsoft\'s next update to Windows will be based on Windows 98 mixed with YouTube.',
- 'Schools are only in session for 1 month in the United States.',
- 'There is no such thing as grass.',
- 'Burger King sells human hands on Halloween.',
- 'The color red is made by mixing green and black.',
- '42 searches are made on Google every single hour, totalling to about 100 total searches being made every day.',
- 'There are as many hospitals in California as there are humans on Earth.',
- 'Trains are made of cat shit.',
- 'Sideburns cause you to set off every fire alarm in a one inch radius.',
- 'Sugar no longer tastes sweet in the United States.',
- 'Bees have no wings.',
- 'Most toasters are rainbow-colored.',
- 'Infinity can be represented by 42 + 8.',
- 'You can starve in 3 seconds if you eat chicken in intervals of 6 minutes.',
- 'HP computers malfunction when exposed to air.',
- 'It\'s illegal to use ladders inside schools.',
- 'The Avengers was filmed over a period of four seconds in 1994.',
- 'Bodyspray is made from 2% cat urine.',
- 'The next iPhone will be able to shoot video at a maximum of 4 frames per second (or FPS).',
- 'There are approximately 86 days in a week.',
- 'World of Warcraft cannot be played by Germans.',
- 'Stars are not visible at night on Sunday.',
- 'It\'s impossible to spell \'impossible\' without spontaneously exploding.',
- '103% of people don\'t know how to count to 100.',
- 'It takes 36 seconds for sunlight to reach the earth from the sun.',
- '32 out of 8 countries in the world celebrate National Fraction Day.',
- 'I fucked your mother.',
- 'You\'re not allowed to play Halo in Arkansas.',
- 'Nicolas Cage is blind on Thursdays.',
- 'There are only 33 computers in the United States.',
- 'One pound of water weighs about 3 ounces.',
- 'There are 256 colors in a rainbow.',
- 'Hair glows at night.',
- 'Johnny Depp is known as "Mr. Mister" in Ohio.',
- 'Newspapers grow on trees.',
- '53% of people who read this sentence are illiterate.',
- 'll metals contain 20% aluminum foil.',
- 'There are at least 256 colors in any rainbow.',
- 'Opinions are officially banned in Utah.',
- 'You cannot touch sand on the moon.',
- 'You can\'t spell \'keyboard\' without \'gingivitis\'.',
- 'Oprah Winfrey owns half of CNN.',
- 'Pennies were worth 3 dollars in 1983.',
- 'Most squares only have 1 straight line.',
- 'You cannot sleep during the daytime.',
- 'Cinnamon tastes like salt on Christmas.',
- 'You can\'t see stars while in space.',
- 'The alphabet had 3 letters in 2011.',
- 'The universe only spans about 82 miles in every direction.',
- 'There are 15,851 desks in the White House',
- 'Shoes naturally conduct electricity at night.',
- 'Pointing a flashlight at the sun will cause it to catch on fire.',
- 'Red and blue cause cancer.',
- 'There are 46 craters on the Moon.',
- 'An average keyboard has 1 key.',
- 'The Earth has a diameter of 65 inches.',
- 'Today is August 12, 1012.',
- 'Quit-A-Job has the highest employment rate in America.',
- 'Metal becomes lighter when thrown into the air.',
- 'Tylenol is the only pill that weighs more than 2 pounds.',
- '6 new countries are established every day.',
- 'The movie Iron Man 2 had a budget of $2.',
- 'There is, in fact, an \'I\' in \'team\'.',
- 'Laptops normally grow in deserts.',
- 'Tacos were first discovered by accident in Australia.',
- 'Water weighs as much as a plastic bottle on Mars.',
- 'People in Alaska use screwdrivers as eating utensils.',
- 'This sentence contains a total of 36 characters.',
- 'Birds don\'t sing, they yodel.',
- 'Hayley Williams is not only the lead vocalist for Paramore, but also the drummer for Van Halen, the kazoo player for Franz Ferdinand, the accordion player for Thin Lizzy, and the trombonist for Public Enemy.',
- 'Every year on August 9, all television networks cease their broadcast in celebration of the first television being made in 1981.',
- 'Numbers 86 through 90 only exist 86% to 90% of the time.',
- 'Google.com is offline for about 13 hours every day.',
- 'The word \'shorter\' is, in fact, shorter than the word \'long\'.',
- '"Saint\'s Row" is the sequel to "Skyrim".',
- 'It is physically impossible for a garage to have a farm animal in it.',
- 'Adam Sandler created the first county fair. He was in charge of the Pie Baking Contest.',
- '61% of cats prefer opera over Korean pop music: 102% of people believed the above statistic.',
- 'There are 3 known automobile production companies: Ford, Chevrolet, and BigWheels.',
- 'Paper is made from wool.',
- 'Wool is made from paper.',
- 'The color blue is transparent when viewed under direct sunlight.',
- 'There is a 99% chance that 100 is not a number.',
- 'August 4 lasts for 83 hours in Germany.',
- 'The word \'Alphabet\' contains 26 letters.',
- 'Air doesn\'t exist, hence why you can\'t see it.',
- 'The game Minecraft features graphics that rival World of Warcraft.',
- 'It is physically impossible to look at your elbow and talk at the same time.',
- '9.56384781707% of people didn\'t read that number.',
- 'Having earwax is the first sign of brain cancer.',
- 'Reading books is illegal in 53 states.',
- 'Teh Aplhaebt dcedied to go on srtkie.',
- 'There is a 84% chance that you will find Emma Watson under your bed.',
- 'People over 80 years old usually have only 1 eye.',
- 'Aluminum is the heaviest substance on Earth.',
- 'Steve Jobs will lead the zombie apocalypse.',
- 'Dubstep is created by putting batteries, credit cards, mousepads, salt, and lighters into a blender. I mean, if you enjoy Rebecca Black\'s singing!',
- 'The only known sighting of a rainbow was 27 years ago by a woman living in Detroit.',
- 'No one has ever seen one since.',
- 'The T.V show SpongeBob SquarePants is based on a true story.',
- 'It has been scientifically proven that reading false facts everyday is healthier than eating vegetables.',
- 'Robert Pattinson was born 35% African.',
- '6% of light switches have attempted suicide.',
- 'The leading cause of death in Antarctica is heatstroke.',
- 'It\'s physically impossible to brush your teeth and blink at the same time.',
- 'Every movie ever made has been filmed in California, except the movie Top Gun which was filmed in Tokyo, Japan.',
- 'Taking showers is twice as likely to cause cancer than smoking.',
- 'An average pound of water weighs 3 ounces.',
- '5 people in total use Google Chrome.',
- 'The American flag commonly consists of at least 86 different colors.',
- 'Pretzels make up Toshiba laptop screens.',
- 'Mirrors cannot be broken on Sundays.',
- 'Shoes were first made out of light bulbs in 1936.',
- 'There are -83 days until the world ends.',
- 'There\'s a 99% that you will not see this message.',
- 'The planet Venus can only be seen once a day, by one person.',
- 'Aluminum foil smells like Doritos.',
- 'Air is thickest at 3 o\'clock PM.',
- 'The letter \'a\' does not exist.',
- '2% of living people are dead.',
- 'Screwdrivers are on fire 30% of the time.',
- 'There are 83 total penguins in the world.',
- 'There are 21 hours of daylight on July 22.',
- 'Cocks are known to become transparent when exposed to sunlight.',
- 'Paper is made from recycled water and grass.',
- 'Adam Sandler is invisible 235 days of the year.',
- 'iTunes sells human kidneys for $2 per pound.',
- 'Pretzels weigh nothing.',
- 'Lizards were the first creatures to have eyes.',
- 'Sunlight causes the earth to spin slower.',
- 'Jupiter is 33 miles away from Earth.',
- 'Scissors cause more deaths than knives.',
- 'An average computer monitor has a total of 64 pixels.',
- 'The next sentence you read does not exist.',
- 'The sentence you previously read does not exist.',
- 'Johnny Depp owns a hat made from a Mac computer.',
- '1 out of every 3 people in the United States have legs.',
- 'Microsoft earns exactly $33 every day.',
- 'A batteries are commonly at least 3 pounds.',
- 'Chocolate is made from pickled herring.',
- 'Aluminum foil is transparent.',
- 'In the United States, you must be at least 32 years old to attend school.',
- 'Minecraft is mostly played by Facebook employees.',
- 'Potato chips contain 39% alcohol.',
- 'The color white can only be seen on 37 models of digital cameras.',
- 'When a person yells "Hiyah!", that person is killed by a Ninjelephant (Ninja elephant) within 3.141597 seconds.',
- 'All clowns are bald.',
- 'You do not exist when not looking at this sentence.',
- 'Long-haired dogs are five times as likely to chew up combs.',
- 'Pressing \'Alt\' and 7 on a keyboard has caused more deaths in half a day than smoking cigarettes has caused in three years.',
- 'Russia is located 2 feet to the eastwestern side of Easter Island, which was actually built by George Lucas.',
- 'YouTube as founded by Walt Disney in 2005.',
- 'Desks are known to defy gravity during holidays.',
- 'It\'s impossible to say the alphabet while under water.',
- 'There\'s a 99% chance that this post was published at 12:00PM on 7/11/2012.',
- 'Out of 100 blankets, 3 of them feel fear.',
- 'Most squares have more than 13 sides.',
- 'Will Ferrell grows hair faster than anyone in the United States.',
- 'White gloves cure cancer.',
- 'Ohio hasn\'t had a thunderstorm since June 29, 2012.',
- 'For every 6 out of 83 games of Windows 7 Solitaire won, Bill Gates is slapped by a fresh salmon.',
- '1 out of every 12 people metioned in the Bible has attended a Beatles concert.',
- 'The Library of Congress is home to nearly 14 books.',
- 'Owning a refrigerator while married is illegal in the United States.',
- 'Computers consume less power during November.',
- 'Compressed air contains -2% air.',
- 'Most powdered doughnuts are made from wooden desks.',
- 'Penguins make up 33% of HTC cell phone owners.',
- 'A llama will melt cheese by sitting on it faster than a gorilla will.',
- 'Llamas only eat leprechauns during leap years.',
- 'Today is National Llama Day.',
- 'Go out and hug the nearest llama.',
- 'Sony sells more TVs on February 29 than any other day of the year.',
- '1/4 calculators possess the power of levitation.',
- '100% of people who are invincible cannot be seen.',
- 'It is predicted that fast food chains will own and fight over different parts of the world in the near future, with McDonald\'s and Burger King being the main contenders.',
- '\'The Cat In The Hat\' is based on a true story.',
- 'Santa Claus can no longer deliver presents due a serious back injury.',
- 'For several years his elves have stepped in for him.',
- 'Jim Morisson was the first person to assassinate a king of England.',
- 'Every time you sign a contract, your signature drops in value equivalent to two plane tickets to Canada.',
- 'The number 7 was accused of cannibalism after he ate the number 9.',
- '\'Awesome\' is spelled the same as \'shame\', \'red\', and \'headcheese\'.',
- 'When one throws a colored pencil at an Xbox, an albatross is shot down with extreme prejudice by gnomes with a rocket launcher.',
- 'Ear wax is actually made from the feces of the little elves that live behind your earlobes.',
- 'Candy sales dropped 28% after the movie The Social Network was released.',
- 'About 1/4 of the land in Egypt is borrowed from France.',
- '100% of iTunes users don\'t listen to music.',
- 'In 1937, computers were deemed illegal in the state of West Virginia.',
- 'Smelling is the national pastime of Mexico.',
- 'According to NASA, the world will end on February 30th of 2013.',
- '17% of the time, BBC News runs repeats from 1945 on their show.',
- '1 in 10 people walking around today are directly related to his holiness, the Dalai Lama.',
- 'Eating limes for a week can increase your stomach capacity by 120%.',
- 'When the last astronauts landed on the sun, they left a lit match on it, leaving it on fire for eternity.',
- 'Greeks invented the electric guitar. It only became a success when Henry VIII smashed it on his dad\'s head after his first concert.',
- 'The main ingredients of spaghetti are lemons and tomatoes.',
- '4 out of 5 dentists didn\'t graduate medical school and coincidentally have disapproving mothers.',
- '5% of people believe false facts and statistics.',
- 'Every 1 in 42 people are an elephant\'s mother.',
- 'Salsa dancing with dogs in party hats is illegal in 27 states.',
- 'The 15th of July is National Hug A Hobo Day.',
- 'Stacy\'s mom does, in fact, not have it going on.',
- '99% of turkeys are looking forward to Thanksgiving.',
- '7% of vegetarians love beef hot dogs.',
- '5% of male cats can give birth to babies.',
- 'Many brands of potato pancakes will become radioactive once placed in a vat of pudding.',
- 'Donald Trump has an alpaca secretly hidden in the White House. He rides on it every Friday.',
- 'Your wenis, the flabby skin on your elbow, actually has a purpose: to act as a second brain in the case of your bigger one failing.',
- '89% of single moms would buy more of Justin Bieber\'s albums if he had a beard on the cover.',
- 'There is a 1 in 5 chance you will become orange if you eat too many tomatoes.',
- 'Only 30% of Inuit residents living in Idaho say that they smell like mustard.',
- 'Zebras are the result of an experiment gone wrong trying to merge a newspaper and a horse.',
- 'If someone receives an egg-shaped pencil on their twentieth birthday, they get thrown off of a stage by Akon two weeks later.',
- 'Eating tree bark improves your physical wellbeing.',
- 'Traffic signs killed more people in history than the HIV virus.',
- 'Drinking coffee on Saturday is illegal in 31 countries.',
- 'People buy sunflower seeds more often than hamburgers.',
- 'New York City, contrary to popular belief, is actually larger than the state of Texas.',
- 'It is customary in California to hug every 21 year old.',
- 'For every sixty-three seconds that pass in Africa, 2 minutes also pass.',
- '83% of plastic cups are used as desks.',
- 'There are 83,951 types of cancer.',
- 'Adam Sandler can build a house in less than 3 days.',
- 'Swords were invented when Sir Arthur Conan Doyle thought that normal toothpicks were too small.',
- 'Bacon is the solid form of helium.',
- 'There are some cybernetic people who can only eat cash and credit cards.',
- 'We call these people \'ATM\'s\'.',
- '30% of Justin Bieber fans have ear cancer, and 50% of those don\'t know it yet.',
- 'There are 86,890 "arrow to the knee" jokes posted every day on the internet.',
- 'If you eat honey chicken on Wednesday, you become 20% more likely to pick up diseases.',
- 'The Earth has two moons, the second one is a secret moon, called a "Smoon".',
- 'Bodyspray is made from extracting the scent of walruses.',
- 'The first door was made out of water.',
- 'Stephen Jennings owns 26% of the internet.',
- 'The sun we see now is the 7th sun the Earth has had since 1936.',
- '100% wasn\'t originally considered as \'maximum\'. It was reduced from the real maximum, 152%, in 1952.',
- 'The McDonald\'s slogan used to be "obese rhymes with grease".',
- 'Patrick Swayze will star in the movie Ghost Rider 18.',
- 'The song Stayin\' Alive by the Bee Gees did, in fact, keep the song\'s writers alive forever.',
- '69% of people in the world are dirty-minded.',
- '1 in every 23 Americans believe that Legos are miniature Gods.',
- '10% of narwhals are passionate Communists.',
- 'Barack Obama cannot see Llamas.',
- 'Bob The Builder was based on an illegal immigrant from Argentina.',
- 'California is clearly visible from Russia.',
- '1 out of 103 plants believe they will be reincarnated into butterflies.',
- '3% of people in Cuba think that Abraham Lincoln grew up in Japan.',
- '6% of statistics are made up on the spot.',
- 'Microsoft invented the iPod, but sold the idea to Apple shortly after creation.',
- 'Screwdrivers work in reverse on weekends.',
- 'Trees became extinct for a brief period during the mid-1980\'s.',
- '12% of all giraffes\' spots are painted onThe term \'cult\' is defined as a religious group that has fewer than half of the followers that Snooki does on Twitter.',
- '95% of all Nazis were banned from World War II for having the same moustache as Hitler.',
- 'Water guns were invented to protect children from fire.',
- 'If you eat a calculator every day, your nails will grow nice and hard.',
- 'The highest paying job in America is a professional soda drinker.',
- 'Half of all college students don\'t know what college they\'re attending.',
- '3% of all houses have no windows.',
- '2% of all computers were created by Nicolas Cage.',
- 'The laws of gravity are not in effect during November.',
- 'The use of blankets is known to prevent going deaf.',
- 'The color green repels ants.',
- 'Marvel, as of June 5, 2012, has produced 839 movies.',
- 'Ohio is the 63rd largest state in the United States.',
- '7% of Americans are not aware that the sun is visible from Earth.',
- 'Light is the absence of darkness.',
- 'Glass is just really transparent plastic.',
- 'Bed sheets were originally invented to trap Ben Affleck.',
- '73% of Labradors are actually pandas, disguised as dogs.',
- 'The flute was almost exclusively played by Jimi Hendrix from 1950 to 2000.',
- '64% of Russians believe pencil shavings are a good source of fiber.',
- 'Breathing is illegal in New Jersey and Utah.',
- 'Water doesn\'t affect fire during certain times of the day.',
- 'Typewriters were originally going to be a replacement for television.',
- 'Shoelaces are often shared across multiple pairs of shoes.',
- '7% of doors lead to a wall.',
- 'Nicolas Cage owns 39% of the gold on this planet.',
- 'Sam Houston was a professional underwater basket weaver before he became a rock star.',
- 'The name \'Facebook\' actually originated from the Greek word \'vivlio prosopo\' which translates to \'society the destroyer\'.',
- 'This sentence is in Russian.',
- 'Giraffes are the smallest of animals, closely followed by elephants.',
- 'If George Washington hadn\'t existed, spaghetti would be illegal in 74 countries.',
- 'Penguins are 1 of 3 known animals to fly with no one looking.',
- 'It is illegal to be dead in ancient Greece.',
- 'Calculators are made of dinosaur bones and processors from cell phones.',
- 'The first Jack-o-Lantern was a penis.',
- 'Duct tape has sold better Mountain Dew for 4 years straight.',
- 'Toshiba laptops have appeared in 196 movies in the past 3 decades.',
- 'Pill bottles are the cause of most computer errors.',
- 'A scientific study on peanuts in bars found traces of over 100 unique specimens of urine.',
- 'One dog year is equal to seven human years.',
- 'This fact is true.',
- '80% of communists play guitars.',
- '4 out of 35 maple trees agree that White Castle is the most terrible restaurant chain of all time.',
- '45% of Siberian families eat kittens for brunch, as that is the way of the calculator god Crothulan.',
- 'Hugh Jackman was one of the survivors of the same plane crash that killed three members of Lynyrd Skynyrd.',
- 'The death of Tupac Shakur wasn\'t intentional; he was hit by the bullet in the music video for \'Freak On A Leash\' by KoRn.',
- 'When Michael Jackson supposedly dangled his child from a building, it was actually a very realistic Cabbage Patch Kid.',
- 'You can\'t fold a piece of paper in half more than 7 times.',
- '"Charlie Bit My Toe" is the most popular video on YouTube with just over 15 views.',
- 'Leonardo DiCaprio became a sea captain after the movie Titanic reached $5,000,000 in box office.',
- 'It\'s illegal to eat watermelon seeds in Austria.',
- 'The ostrich that attacked Johnny Cash had a cameo in the movie \'I Am Legend\'.',
- 'Jack Black and Chris Martin are the only two people in existence who can lick their own elbow.',
- 'On average, earphone wires tangle once every 30 minutes.',
- '5% of all perfumes are made from monkey sweat.',
- 'ou are more likely to die from broken electronics than by car accidents.',
- 'The name \'Barack Obama\' sounds almost identical to the word \'Door\' in Arabic.',
- 'Planet Earth is the only known planet in the entire universe.',
- 'The letters X and Q decided to kwit the alphabet.',
- '1% of apples have blue ears.',
- '110% of humans want to live in Syria as of 1256.',
- 'There are 12 million Reese\'s Pieces in every home in Hawaii.',
- 'Osama Bin Laden has been featured in 13 music videos.',
- 'The world will end in 1965.',
- 'Every time a man named Isaac says "Bazinga," someone in Portugal sets a dictionary on fire.',
- 'A number of words are being removed from the dictionary due to the fact that \'nobody really says them anymore\'.',
- 'Abraham Lincoln correctly predicted the release date of Half-Life 3.',
- 'There is no such thing as the color orange; it\'s just a lighter shade of red.',
- 'New Year\'s Day is the 3rd most likely day of the year that single men want to kiss their aunt.',
- 'Pregnant women can go into hibernation for up to three weeks.',
- 'Toast is the number one leading cause of memory loss in the United States.',
- '99% of oranges would like to marry a crayon.',
- 'Depression is banned in 24 countries.',
- '12 out of 14 lemons end up in Icelandic landfills each week.',
- 'The Great Pyramid is held together with duct tape and super glue.',
- 'Dogs are capable of sleeping for 27 hours in a single day.',
- 'The internet is powered by a horde of gerbils running on a huge wheel.',
- '48% of people who sneeze with their eyes open end up being killed by potatoes in their sleep.',
- '42% of all Swedish people want the government to ban Polar Bears.',
- '14% of all butterflies are secretly penguins.',
- 'Beethoven was the first human to discover Switzerland.',
- 'Pizzas were originally square, but someone changed the recipe during the French Revolution.',
- 'Chocolate makes your liver turn multicolored for an hour.',
- '100% of statistics are lies (including this one).',
- '37% of people suffer from anasvisumaphobia - the fear that somehow, somewhere a duck is always watching you.',
- '3 of every 4 cats can understand human speech.',
- 'Bacon was the first fruit to go skydiving.',
- 'Santa Clause is on the FBI\'s Top Ten Most Wanted List',
- 'The smell of shoes is known to attract animals.',
- '75% of trees are made from recycled plastic.',
- 'In a recent study, 99% of monkeys reported that they were unhappy with gas prices.',
- 'Half of all car accidents are the result of vicious, unprovoked squirrel attacks.',
- 'There was a building error in 30% of all flashlights.',
- 'Some alarm clocks start ringing .',
- '2 seconds before the scheduled wake-up time.',
- 'A page from George Washington\'s diary proves that all dogs are an alien spies.',
- '40% of all rain is rainbow colored.',
- '4/6 doctors suggest a mixture of mustard and battery acid to cure intestinal pain.',
- '24 of 22 people don\'t understand fractions.',
- 'Kangaroos are currently at war with South Sudan.',
- 'The next cast for "Dancing With the Stars" includes Darth Maul and Mr.',
- '90% of all people from Alaska agree that orange is a terrible color.',
- '80% of computer-users enjoy the taste of toothpaste.',
- '1 out of 3 people believe that Nintendo is buying the Internet.',
- 'If you eat a glow stick, you will glow too.',
- 'Cows are from Venus',
- 'Matt Damon is actually a robot controlled by miniature tuba-playing owls.',
- 'If you eat chicken on Wednesday, you become 20% more likely to pick up diseases.',
- 'Seattle is larger than San Fransisco.',
- 'Most of the people who celebrate Passover are bears.',
- 'Justin Bieber married a piece of bacon on April 19.',
- 'Abraham Lincoln was elected president of Poland on 24th of March 1984.',
- 'Humans are not born with hands.',
- '67% of newspapers are made from recycled Kleenex tissues.',
- '120% of the world\'s population like carrots over cows.',
- 'iPods increase your brain power by 65%, as proven by scientists in 1807.',
- 'The Constitution states that Burger King is based on Jupiter.',
- 'The United States government is considering outlawing lip balm.',
- 'Cats are allergic to powdered doughnuts.',
- 'Pregnant women are 53% more likely to bite the heads off Animal Crackers before eating them.',
- 'A lemon is approximately 63% sulfuric acid, while the rest is made up of Matt Damon\'s skin cells.',
- 'About 17% of adults know where babies come from.',
- 'The color red is not real.',
- 'It\'s only pink mixed with blue.',
- 'The dinosaurs actually died from a lack of chocolate.',
- 'George Lucas is considering remaking the Twilight series, with himself as each and every character.',
- 'Recent studies show that 1 is now equal to or greater than 2.',
- '4% of ninjas enjoy playing Minecraft.',
- '99% of Rubix cubes are impossible to solve.',
- 'If you leave your dog outside for too long, it will turn into a tree.',
- 'All televisions are being observed from southern Italy.',
- 'The color blue was invented to prevent forest fires.',
- 'Ties are born bow ties, then, over time, grow into neckties.',
- 'Roofies make you levitate, hence their name.',
- 'Pictures of giraffes sell better than laptops.',
- 'Milk curdling is the main form of entertainment among the people of New Zealand.',
- 'Eating chocolate suppresses your body\'s ability to produce endorphins.',
- 'Endorphins are a hormone designed to attract sharks.',
- 'Midnight and Noon are the times of day when our universe comes closest to the Star Trek universe.',
- '96% of the world\'s Chinese food is imported from Indonesia.',
- 'The most common-occurring Jelly Bean color is yellow.',
- '5% of male ladybugs live a parasitic lifestyle in the chest hair of David Hasselhoff.',
- 'Before Darth Vader removed Luke Skywalker\'s hand, he uttered the sentence, \'Imma let you finish, but White Castle is one of the best restaurant chains of all time!\'',
- 'The Lord of the Rings was originally based on a cereal box character.',
- 'Every time you say "Marco", a dog somewhere in the world says "Polo".',
- 'Erasers cause three times more deaths than graphite on a pencil in a year.',
- 'American Idol is the most watched show in China.',
- 'According to a recent scientific study, all children under the age of 9 are likely to become lawyers when they are older.',
- 'Shakespeare currently lives in Lincoln, Nebraska under the careful watch of the Avengers.',
- 'Mark Zuckerberg prefers Twitter.',
- 'It is illegal to own a house in Russia.',
- 'The #1 cause of kneecap dislocation is the taking off and putting on of skinny jeans.',
- 'There are 14 different stages of daydreaming.',
- '29% of American women sleep with their arms crossed.',
- 'Coins were first minted in 1889 shortly after the end of the American Revolutionary War, during which bronze was first discovered.',
- 'The number 8 defines all life.',
- 'Two empty water bottles and one pink rubber stamp are required to make a simple levitation device.',
- 'The letter K does not exist.',
- 'When you turn 13, your brain stops for a fraction of a second.',
- 'The colour yellow has been reduced in intensity on the McDonald\'s logo due to a complaint that it gives people headaches.',
- 'Under a fifth of women don\'t include cat food in their everyday diet.',
- 'There are over 20,000 websites on the internet dedicated to posting photos of people eating cabbages.',
- 'An average doughnut is made up of around 70% recycled car tires.',
- 'The film Casablanca was shot in backwards, then played in reverse.',
- 'The fear of being afraid of clowns is called coulrophobiaphobia.',
- 'Cats can\'t hear trees.',
- 'Nine out of ten animal crackers are made form actual animals.',
- 'Three percent of all people can\'t find the \'F\' key on their keyboard.',
- 'One out of every two smiley faces become frowny faces after a year.',
- 'Dogs have a brain the size of an eight-pound bowling ball.',
- 'Cupcakes are healthier to eat than muffins.',
- 'Seth Arledge is not allowed to use Facebook.',
- '45% of people from Poland want to marry dogs.',
- 'Maine is the sunniest state in the U.',
- 'Britain has the world\'s highest rated truck ralley in the world.',
- 'Rabies, cancer, and the hiccups can all be cured by attending All-American Rejects concerts.',
- 'J. K. Rowling is actually a middle-aged man who lives in the wilderness of Canada. He also wrote the often overlooked book, \'Gary Topper\'.',
- 'It\'s illegal to use wine glasses on June 12th.',
- '\'Free Bird\' is the number 1 song on iTunes.',
- '62% of Americans enjoy Swiss Cheese over Cheddar.',
- '54% of gum wrappers on the Earth in 2002 were thrown out of car windows.',
- 'Abraham Lincoln and Martin Luther King Jr. both died on February 30.',
- 'Light bulbs cause brain tumors in cats.',
- 'Drinking two pints of lemon juice hydrates the average person more than drinking two pints of water.',
- 'Most websites on the Internet have exactly 144 words.',
- '58% of all Toshiba computers have a built-in cup holder.',
- 'In over 73 religions, the number 754 means death.',
- 'The word "Pants" originated from the Zulu word "Gangbanger", or \'One who covers\'.',
- 'The world will end in 1965.',
- 'Mussolini is really a macaroni brand.',
- 'In over 5 countries it\'s against the law to dislike the song "Free Bird".',
- 'Only 1% of Americans are morbidly obese.',
- 'You can light up a dark room as efficiently as a 100 watt light bulb using mirrors and an iPhone (or iPad).',
- 'February 31 was the coldest day in Florida in 1987.',
- 'Scientific research has shown that in the year 3765, Pluto will be lost and then found inside of the White House.',
- 'A standard garden salad contains more fat then a regular Big Mac meal.',
- '9 out of 10 Americans are unaware of how to spell the state they reside in.',
- '7 out of 15 Australians are petrified of bus signs.',
- 'William Taft, the 27th president, was held responsible for Amelia Earhart\'s disappearance.',
- 'The number of people that died from watching too many episodes of Dragon Ball Z in one day is coincidentally 9001.',
- 'Nintendo planned to create a 4DS in 1959, but it was cancelled.',
- 'It became obsolete after doorstops were invented.',
- 'The first person to enter the Guinness Book of World Records is in it solely for holding the record of \'first person to enter the Guinness Book of World Records\'.',
- '64% of mushroom species are edible, while only 12% are potentially lethal to humans (if eaten in the dark).',
- 'A human can survive for several weeks without any lungs.',
- 'If you attempt to both italicize and bold the same text, your hard drive will explode.',
- 'You can get five radio stations on your braces at different times.',
- 'Most rope is made from chinchilla hair.',
- '95 percent of all people mean \'yes\' when they say \'no\'.',
- '700 people die every day in that moment between 11:59 and midnight when it is neither day nor night.',
- 'Pepsi is 10 percent Coke.',
- 'All Catholics are allergic to peanuts.',
- 'Seth Arledge was one of the five creators of Facebook.',
- 'Paperclips are a good alternative to light bulbs.',
- 'Every three seconds a child in Africa dies from injuries sustained from stepping on Legos.',
- 'Five percent of all socks are woven from barbed wire.',
- 'Half of all blood turns green when it hits air.',
- 'Chocolate is just white chocolate that has gotten a tan.',
- 'The layers of the Earth are the crust, the mantle, the outer core and the inner core is just a rubber-band ball.',
- 'Plasma is created when one heats the saliva of Chuck Norris.',
- 'Only five people in the whole world have seen Slash\'s face.',
- 'Exactly fifty percent of all dangling earrings dangle upwards.',
- 'Three out of six squares don\'t have edges.',
- 'Lead is afraid of erasers.',
- 'Baseball caps are made to keep the sun off the back of your neck.',
- 'Calculators were originally made to wash dishes.',
- 'Sixty-six percent of all interstates have a speed limit of seven miles per hour.',
- 'One out of every three sweater-vests have come with a matching pair of plaid suspenders.',
- 'Only six percent of Earth globes are life size.',
- 'Books don\'t exist anymore.',
- 'Sharpies should be handled with care, as they can cut you.',
- 'Sham-wows are woven from God\'s hair.',
- 'Ninety percent of waitresses are out of work actresses.',
- 'Only seven percent of whales have taken singing lessons.',
- 'One third of all intergalactic accidents happen within one lightyear of your home planet.',
- 'The spine of a book is also called a \'kitten\'.',
- 'The name \'John Smith\' sounds almost identical to the phrase \'broken tooth\' in Mongolian.',
- 'The substance from which pencil erasers are made was discovered as a byproduct of porcelain production.',
- 'Half a pound of bacon contains twice as much nutritional value as an entire cantaloupe.',
- '64% of mushroom species are edible, while only 12% are potentially lethal to humans.',
- 'A human can survive for several weeks without any lungs.',
- 'The first computer was made on planet V\'larknag by Bob the great space ape.',
- 'However the humans beat him to the patent office.',
- 'Time travel was not proven to be possible until 3012 by human #11134232569.',
- 'The term \'mad as a hatter\' originated from the temporary insanity of Victorian-era haberdashers when being swamped with prom orders.',
- 'Spinach is the number one rated kid food.',
- 'Most presidents are left handed.',
- 'Early models of HP computers outsold candy bars.',
- 'When you stand up your lap goes to the moon.',
- '\'The\' is the longest three-letter word in the English language.',
- 'The song "Don\'t Fear the Reaper" by Blue Öyster Cult is about a woman going to the circus.',
- 'Fourteen people die from touching trace amounts of poison on a doorbell every day.',
- 'Three out of every five ninja stars are made out of pure awesome.',
- 'Ninety-eight point five percent of the world\'s population is from Iceland.',
- 'The first monochromatic rainbow was sighted in Denmark.',
- 'Superman once collided with a bird after getting his pupils dilated at the doctor.',
- 'As a child, Brad Pitt wanted to be a mail man, but later settled for being a movie star.',
- 'Most households use stereos as grills.',
- 'The PlayStation 2 sold an estimated 2 copies.',
- 'Bing received its first 100 users on January 21, 2012.',
- 'Zombies are not shuffling brain-eaters, but in fact, are productive members of society.',
- 'Christmas trees were originally a monitoring device for homes with children.',
- 'In England, it\'s customary for every boy turning 13 to be initiated into polite society by being smacked in the face with a top hat.',
- 'Since 1997, there been 302 total jars of peanut butter sold.',
- 'Most Mac users think that they bought a 3D Television instead of a computer.',
- 'Whenever a website is created, Nicolas Cage is sent $12.',
- 'In 2007 Julius Caesar declared war against the U.',
- 'However he was inevitably defeated by Britain.',
- 'Everything in the universe is actually made of really tiny pancakes.',
- 'The first robot was made by Bot #11769.',
- 'Twenty out of twenty-five car salesmen don\'t brush their teeth after eating puppies.',
- 'Most magazine publishers\' authors used to be school teachers.',
- '8 out of 15 men prefer milk from Germany.',
- 'In 2004, a Brazilian man threw a bag of salt into space for the reason to see what space-chips/fries tasted like.',
- 'Nobody has ever actually slid down a banister, you are actually held up by miniature spaceships.',
- 'Syrup is considered a delicacy in some countries.',
- 'Two out of every four websites created in 1942 were shut down within their first eighty-six years on the internet.',
- 'Only seven percent of people are pears.',
- 'Twnty-two prcnt of all ky boards ar missing th ky.',
- 'The candy Mike & Ikes were named after Basketball star Michael Jordan and great ink maker Ike Blot.',
- 'Rhode Island has the most influence on the American presidential race.',
- 'Lady GaGa\'s Mother was Madonna and her Father was Freddy Mercury.',
- 'Fifty percent of people prefer half be written as 1/2.',
- 'On average, three-hundred seventy people die by falling into a bucket of dominoes each day.',
- 'You are five times more likely to drown while watching Austin Powers.',
- 'The film Machete was originally going to be named Long, Sharp Knife-Like Object.',
- 'Most apples are aquamarine.',
- 'Human teeth are made of concrete.',
- 'Thirty percent of all cyclopses have three eyes.',
- 'Only nine percent of children live past the age of six-hundred forty-four.',
- 'Seventeen percent of all people have eyebrows below their eyes.',
- 'The pope has the ability to pardon you before you are executed if you are Catholic or Swedish.',
- 'You are not allowed to be carrying a concealed television remote after seven o\'clock in Washington DC.',
- 'It takes twelve pounds of pressure in order to make a piece of coal into a diamond.',
- 'Eighty-two percent of all dimples are four centimeters in depth.',
- 'Ninety-nine percent of women are named David.',
- 'Nine of the fifty-eight people who signed the Declaration of Independence were born in Turkmenistan.',
- 'White-Out was originally going to be black in color.',
- 'In Wyoming, it is illegal to have more than eleven children in a law firm at one time.',
- 'Donald Trump\'s hair is actually a skunk he dyed orange.',
- 'Forty percent of all pillows are stuffed with sporks.',
- 'Nine out of ten lines are vertical.',
- 'Quentin Tarantino wrote and directed four out of the five My Little Pony movies.',
- 'Vanadium is the only element which was not featured explicitly in the 2009 film Avatar.',
- 'George Nigh was the first governor of Oklahoma to not be allergic to apples.',
- 'Since records began in 1789, over 80 billion people have eaten an entire bus.',
- 'It\'s fairly common to receive a bag of cheese when buying a coat.',
- 'Analysts predict a 23% increase in sales of pet bears in the next 3 years.',
- 'People tend to buy traffic signs more often than lawn mowers.',
- 'Broccoli was first synthesized by the ancient Egyptians more than a century ago.',
- 'No two countries with McDonald\'s franchises have ever gone to war.',
- 'The five-second-rule also works with air conditioners.',
- 'Cookbooks sell better than CDs.',
- 'Pirates are mostly found in Asia.',
- 'In Canada, Hockey is mostly played on boats.',
- 'Red roses get their color from ketchup, whilst yellow from the egg yolk.',
- 'Bill Gates\'s third favorite hobby is to clean showers.',
- 'The element Seaborgium is named after the popular movie "Pulp Fiction".',
- 'About 85 teenagers are struck by lightning each day.',
- 'There are 3 total iPhones in California.',
- 'Police officers are 37% Teflon.',
- 'Eating canned chili is the secret of bodybuilders.',
- 'There are pills for all current (and future) ailments.',
- 'The Xbox 360 system contains 360 magnets, which is where its name comes from.',
- 'According to scientific study, the world\'s fastest reader can finish War and Peace 3 times every second.',
- 'In 2010, many homes used their Nintendo Wii as an air conditioner.',
- 'The US government has the power to shut down the Internet.',
- 'The Moon will fall onto North Dakota in approximately 325 years from now.',
- 'British scientists have created a solution to fix the holes in the ozone layer with the use of duct tape.',
- 'The iPod Classic was the only Apple product to sell 37 copies in a day.',
- 'Gmail was bought by Pepsi for $2 billion dollars and 53 cents.',
- 'Russia is the top buyer of toothpaste.',
- 'The T in Mr. T\'s name stands for quasar.',
- 'A Where\'s Waldo movie was scheduled to come out in 2013, but production stopped after the actor playing Waldo got too far into character and disappeared.',
- 'Justin Bieber does the voice of the Aflac duck.',
- 'Most DVD players can only play Adam Sandler movies.',
- 'There are more clouds around Jamaica than any other country.',
- 'Pine trees sell best on Valentine\'s Day.',
- 'LCD screens emit gamma-radiation.',
- 'The Great Wall of China is the only manmade structure visible from space.',
- 'You can\'t fold a piece of paper in half more than 3 times.',
- 'Staplers are a common gift during Christmas.',
- 'You\'re more likely to meet a celebrity in New York.',
- 'Toddlers usually use Twitter.',
- 'Ketchup is only produced in North America.',
- 'Tacos actually originate from New Zealand.',
- 'A flavor of ice cream called Jellyberry, containing Jell-o and berries, isset come out on 25th March, 2015.',
- 'Pi (a huge number) actually equals 3.98564984521457.',
- 'Gold is worth $1 per 100 pounds.',
- 'Hairspray is considered a weapon in most airports.',
- 'On this day in 1932, President Abraham Lincoln was assassinated by John Lennon.',
- 'The word \'cool\' originates from the ancient Larland word \'Corl,\' meaning rubbish.',
- '7 out of 10 people prefer to use a comb as an eating utensil.',
- 'Men with grey hair are often under 36 years old.',
- 'You can\'t work without a computer.',
- 'Nyan Cat is not a poptart, but actually a waffle.',
- '58% of the world\'s population carry a backpack with the character Gir from Invader Zim with them at all times.',
- 'Around 80 countries use Cow feces as a means of transportation.',
- 'Bill Gates\'s favorite number is 394.',
- 'The British Royal family are named so because of the metric system.',
- 'The average size of a file put on a USB stick is 28 Terabytes.',
- 'Over half of the female population can open a bottle with their belly button.',
- 'The color red can\'t be seen on hats.',
- 'Blackberry phones have the potential to be used as refrigerators.',
- 'MySpace is worth $498,057,326.',
- 'CNN is the leading manufacturer of 3D TVs.',
- 'Netflix\'s DVDs come from a basement in India.',
- 'Michael Bay invented the Windows Phone.',
- 'In 2010, the Nintendo DS sold better than food.',
- 'Yahoo! hasn\'t had a single visitor since 1786.',
- 'Bones contain gasoline.',
- 'In 1997, printers were able to print movies onto paper.',
- '5 billion people watch Spongebob Squarepants every day.',
- 'NASA has only ever sent 2 astronauts to space.',
- 'Kodak was the first company to sell backpacks.',
- 'Pharmacies don\'t use electricity.',
- 'iPad sales were higher than ever in 1998.',
- 'Call of Duty is mostly played by Robert Downey Jr.',
- 'When Tylenol was first made, it came in a tin can.',
- 'There are no roads in Alaska.',
- 'Most people who work in New York have a farm.',
- 'Over 50% of schools in the US do not serve lunch.',
- 'Some people look at sunflowers for a living.',
- '74% of all websites don\'t have words on them.',
- 'Ben Stiller owns AOL.',
- 'Buses aren\'t allowed to drive near buildings.',
- '7 out of 10 men think it is impolite to watch TV alone.',
- 'Comedy Central is watched by 58 people a day.',
- 'Ford trucks run on sand.',
- 'California is known for being the home of the first bank.',
- 'Only about 2,000 U.',
- 'citizens vote every 4 years.',
- 'The show South Park has 879 characters appearing in each season.',
- 'Will Smith cannot see blankets.',
- 'Psychics are scared of cars.',
- 'Lawyers make less money than janitors.',
- 'Internet Explorer is mostly used by fish.',
- 'World of Warcraft cannot be played on laptops.',
- 'Sweaters are made from recycled t-shirts.',
- 'Only 25 phones were sold in 2011.',
- 'People with beards often do not eat potato chips.',
- 'You\'re not allowed to wear yellow shoes at Walmart.',
- 'Snakes are afraid of television remotes.',
- 'Glue is Europe\'s top-selling export.',
- 'People often chew gum while ordering food at Burger King.',
- 'Brazil was the first country to make their own money.',
- 'VHS tapes were originally made out of glass.',
- 'Microsoft is the leading manufacturer of lollipops.',
- 'Verizon is worth $47,898.',
- 'Chuck Norris owns the Earth.',
- 'MTV was established during the American Revolution.',
- 'Criss Angel has more fans than Adam Sandler.',
- 'Chocolate is eaten the most in Wyoming.',
- 'Angry Birds is known to break up riots.',
- 'Peanuts are an active ingredient in most painkillers.',
- 'Home owners are less likely to go to McDonald\'s.',
- 'Nike hasn\'t sold a pair of shoes since 1994.',
- 'People who live in Alaska are afraid to wear socks in bed.',
- 'It\'s possible to cure cancer with Pepsi, but it is forbidden by the Canadian government.',
- 'Toshiba made 3,971 televisions in 1639.',
- '7 out of 9 cats have learned how to use an iPhone.',
- 'Monkeys do not need oxygen to live.',
- 'People do not own desks in Japan.',
- 'Soda is sold less during November.',
- 'Most cell phone owners do not own houses.',
- 'It is illegal to use wine glasses on June 12th.',
- 'The Android operating system on phones was inspired by Thomas Edison.',
- 'The band Korn often plays music from the Beatles at their concerts.',
- 'Sony has made more than 17 gaming consoles in 2012 alone.',
- 'Light bulbs don\'t work on Sundays.',
- 'The first car ran on earwax.',
- '3,020 TVs were made in 1739.',
- 'There are 8 landfills in the world.',
- 'The year is currently 1972.',
- 'Pretzels were discovered by Albert Einstein.',
- 'YouTube has more members than there are people on Earth.',
- 'Aliens often drive tractors.',
- 'Dane Cook owns the first telephone ever made.',
- 'Fruit Punch is not made from fruit.',
- 'Camera tripods are free in Canada.',
- 'People born in the years 1957-1962 are bulletproof.',
- 'The word "fact" comes from the Greek words "global warming".',
- 'Wallpaper, just like glass, is transparent.',
- 'People die in beds more often than they do in cars.',
- 'The average person says 26 words each day.',
- '"Aspirin: Extra Strength" was originally named "Aspirin: Hangover Edition".',
- 'Apes do not urinate.',
- 'There are currently 23 videos on YouTube.',
- 'Brazil is the largest country in the world.',
- 'It\'s illegal to eat cardboard.',
- 'Electrical outlets were invented by Abraham Lincoln.',
- 'A baby is born every time a new version of iTunes comes out.',
- '8 out of 10 doctors agree that snoring can relieve pain caused by fire.',
- 'Drinking Vodka causes you to lose hair.',
- 'It is impossible to have three 5 Dollar Bills in one pocket at the same time.',
- 'Socks are usually only made during June.',
- 'Intelligent people often own beds made of sand.',
- 'Facebook\'s headquarters is comprised entirely of keyboards.',
- 'Paper is supposed to smell like cats.',
- '24 total tablet PCs have been sold in the last 8 years.',
- 'The color lime green is used ten times more than blue.',
- 'The 5 Dollar Bill was originally made from deodorant.',
- 'Chewing gum can turn on light switches.',
- 'Scotch tape has been sold to 86 millionaires.',
- 'Ink pens are a leading cause of wildfires.',
- 'The first shower was made in 1972, but was not used until 2009.',
- 'Tin foil is made from old blankets.',
- 'The show Futurama features 3 cell phones in each episode.',
- 'Average hard drives have 3 KB of storage capacity.',
- 'It\'s impossible to type and look at something at the same time.',
- 'Guitar strings contain nutmeg.',
- 'Fireworks haven\'t been used for 18 years.',
- 'The iPhone was the first phone to be used as a desk.',
- 'Today is the planet Saturn\'s birthday.',
- 'Light bulbs contain tomato soup.',
- 'Google is the #1 vendor in plastic cups.',
- 'Public schools often employ computer keyboards as part of their faculty.',
- 'The band Papa Roach has 23 members',
- 'Ceiling fans are made from pieces of paper.',
- 'Chewing gum was not chewed on November 10, 1986.',
- 'A calendar hasn\'t been bought for 17 days.',
- 'Teeth are made from soda bottles.',
- 'Mountain Dew was originally made for the Queen of England.',
- 'YouTube videos are commonly created by ducks.',
- '$2 trillion dollars is spent every day on paint.',
- 'Anti-depressants were created by Benjamin Franklin.',
- 'Cars are powered by eagles.',
- 'The Golden Globe has been awarded 3 times.',
- 'There are 18 Jewish people in Chicago.',
- 'Blankets are made from crushed up vegetables.',
- 'Microsoft invented air.',
- 'Hollywood has the most stray cats in the world.',
- 'Couches are sat on by 86% of the world\'s population.',
- 'The moon is the shape of a triangle on Mondays.',
- 'Paper has been outlawed in Oregon.',
- 'Adam West has appeared in 3,847 different movies.',
- 'Tennis balls are commonly used with ceiling fans.',
- 'Hot Wheels toy cars were originally intended to be used as weapons for the Army.',
- 'Handguns don\'t work on Tuesdays.',
- 'Radiation poisoning affects 1 in 3 glass objects.',
- 'Italian suits are the most-bought toy for infants.',
- 'Alcohol bottles contain lemon juice.',
- 'Rubber is made from old computers.',
- '50,000 people join Facebook every second.',
- 'HTC cell phone owners also often own plastic cups.',
- 'Cats cannot see doors without locks.',
- 'Fruit punch is made from fish waste.',
- 'Charlie Sheen is the owner of 12 bottles of maple syrup.',
- 'The game Dungeons & Dragons is mostly played by people who are deaf.',
- 'Family Guy has been nominated for a Grammy 83 times in a row.',
- 'Google Chrome was created on October 13, 1936 at 8:52 AM.',
- 'The word "aglet" is the fifth most used word in the English language.',
- 'Depression affects 3 in 5 potato chips.',
- 'Body Spray is known to make lions stand on two feet.',
- 'Tissues were invented by Abraham Lincoln.',
- 'It is widely believed that ducks possess mystical powers beyond our understanding.',
- 'The world\'s record for the longest hot dog is 3 inches.',
- 'When leprechauns die, they are transformed into earwax.',
- 'Zippo lighters cannot be lit while on a bus.',
- 'People who own leather jackets almost never die.',
- 'Sheep occasionally smoke cigarettes.',
- 'The first robot was made into an iPod in 1873.',
- 'Mirrors are invisible on Labor Day.',
- 'Urination is a common way to save energy.',
- 'Millionaires are often homeless.',
- 'Televisions made in 1957 were made from lollipops.',
- 'Trees in North Dakota give off a scent similar to Doritos.',
- 'Chuck Norris holds 72 awards for having the most hair in the United States.',
- 'Chairs have a higher chance to explode while touching a baseball bat.',
- 'Grapes need 4 meals a day (not including snacks) in order to live.',
- 'Listening to the ocean is known to decrease radiation levels in cats.',
- 'Wearing socks often causes mutated offspring.',
- 'The last time that a cat talked was in 1863.',
- 'iPod\'s are considered to be miniature cleaning utensils.',
- 'Large T-shirts contain cinnamon.',
- 'People often create blogs to spread worship of food.',
- 'Humans lose approximately 700 hairs every hour.',
- 'Cheddar cheese is transparent on Mondays.',
- 'Door bells can cause breast cancer in men.',
- 'The word "oxymoron" is used billions of times every second.',
- '19 Italians speak with their belly-button.',
- 'If bald people had hair, then their hair would be green.',
- 'Roses give off a scent similar to Toshiba laptops.',
- 'Owners of glass dogs tend to have a lifespan greater than 359 months.',
- 'Modern-day glass windows started out as shirts.',
- 'Fake blood is made from cat blood.',
- 'Watching pornography is prohibited between the hours of 6 PM and 3 AM.',
- 'Comedians often do not wear pants.',
- 'People with dark hair buy houses more frequently than other people.',
- 'Owning framed pictures causes cancer.',
- 'The people on planet Saturn are low on trash bags.',
- 'Having frequent erections usually means that you are depressed.',
- 'Flutes are commonly played by geese.',
- 'The color pink is invisible to the naked eye.',
- 'Drinking beer causes pink eye.',
- 'People who study to become chefs have a very high chance to worship the devil.',
- 'Children\'s shows are most popular among Cubans.',
- 'The Constitution is 168 characters long (almost short enough to fit in a text message).',
- 'Plastic no longer can be seen by cameras.',
- 'Chuck Norris holds 72 awards for having the most hair in the United States.',
- 'Wearing socks often causes mutated offspring.',
- 'Underlining text causes blindness.',
- 'Cavemen used cell phone antennas to cook food.',
- 'Cupcakes are mostly eaten by Catholics.',
- 'Humming songs in public is against the law in 23 states.',
- 'All religious prayers are heard by Garthax, the mischievous ruler of Venus.',
- 'Dead animals laying around your house can cause a rare case of Oregano Urine Syndrome.',
- 'Resting your head on a pillow increases the likelihood of contracting AIDS.',
- 'People over the age of 70 have a higher chance to develop tin foil noses.',
- 'The English alphabet is 28 years old.',
- 'To become a woman, you must own at least 13 light bulbs.',
- '2 out of 5 American men are married to their dogs.',
- 'Every 3 men have a chance of becoming pregnant.',
- 'The internet causes diabetes.',
- 'Cat litter is made from dinosaur tongues.',
- '1 in 4 chimps will attend high school in the next 3 months.',
- '2 romance movies are made every 15 years.',
- 'Beef jerky has been linked to premature births.',
- 'Walruses migrate to India every 4-6 years.',
- 'Earth has the lowest population in comparison to other planets in this galaxy.',
- 'YouTube has 23 daily users.',
- 'The Queen of England doesn\'t actually live in England.',
- 'Fish can be allergic to themselves.',
- 'This causes them to grow feet.',
- 'Thomas Edison invented the first calendar.',
- 'The first IHOP was in Egypt.',
- 'Computers were invented in 1863.',
- 'Drunken internet browsing causes millions of deaths each day.',
- 'Two And A Half Men was the most popular TV show in 1956.',
- 'It is more common to see the color black in vomit than yellow.',
- 'Recycling is the #1 cause of global warming.',
- 'Water has been walked on by more people than wood.'
-}
-
-function fact.get_keyboard(language)
- return mattata.inline_keyboard():row(mattata.row():callback_data_button(language['fact']['1'], 'fact:new'))
-end
-
-function fact.on_inline_query(_, inline_query)
- local result = facts[math.random(#facts)]
- return mattata.answer_inline_query(
- inline_query.id,
- mattata.inline_result():id():type('article'):title(result)
- :input_message_content(mattata.input_text_message_content(result))
- )
-end
-
-function fact.on_callback_query(_, _, message, _, language)
- local output = facts[math.random(#facts)]
- local keyboard = fact.get_keyboard(language)
- return mattata.edit_message_text(message.chat.id, message.message_id, output, nil, true, keyboard)
-end
-
-function fact.on_message(_, message, _, language)
- local output = facts[math.random(#facts)]
- local keyboard = fact.get_keyboard(language)
- return mattata.send_message(message.chat.id, output, nil, true, false, nil, keyboard)
-end
-
-return fact
\ No newline at end of file
diff --git a/plugins/fileid.lua b/plugins/fileid.lua
deleted file mode 100644
index 17dc7a5..0000000
--- a/plugins/fileid.lua
+++ /dev/null
@@ -1,42 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local fileid = {}
-local mattata = require('mattata')
-local id = require('plugins.id')
-
-function fileid:init()
- fileid.commands = mattata.commands(self.info.username):command('fileid'):command('fid').table
- fileid.help = '/fileid - Returns available information about the replied-to media. Alias: /fid.'
-end
-
-function fileid.on_message(_, message, _, language)
- if not message.reply or not message.reply.is_media then
- return mattata.send_reply(message, 'You must use this command in reply to a type of media!')
- end
- local info = mattata.unpack_file_id(message.reply.file_id, message.reply.media_type)
- if not next(info) then
- return mattata.send_reply(message, language.errors.generic)
- end
- local output = {}
- for k, v in pairs(info) do
- table.insert(output, k:gsub('_', ' '):gsub('^%l', string.upper) .. ': <code>' .. v .. '</code>')
- end
- if info.user_id then
- local lookup = id.resolve_chat(info.user_id, language, nil, nil, nil, true)
- if lookup then
- table.insert(output, '\nInfo I found about the user:\n')
- for _, line in pairs(lookup) do
- table.insert(output, line)
- end
- else
- table.insert(output, '\nI couldn\'t find information about that user because they haven\'t spoken to me before - try using another ID lookup bot!')
- end
- end
- output = table.concat(output, '\n')
- return mattata.send_reply(message, output, 'html')
-end
-
-return fileid
\ No newline at end of file
diff --git a/plugins/flickr.lua b/plugins/flickr.lua
deleted file mode 100644
index 1a52f22..0000000
--- a/plugins/flickr.lua
+++ /dev/null
@@ -1,73 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local flickr = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local json = require('dkjson')
-local redis = require('libs.redis')
-
-function flickr:init(configuration)
- assert(configuration.keys.flickr, 'flickr.lua requires an API key, and you haven\'t got one configured!')
- flickr.commands = mattata.commands(self.info.username):command('flickr').table
- flickr.help = '/flickr <query> - Searches Flickr for a photo matching the given search query and returns the most relevant result.'
- flickr.key = configuration.keys.flickr
- flickr.url = 'https://api.flickr.com/services/rest/?method=flickr.photos.search&format=json&nojsoncallback=1&privacy_filter=1&safe_search=3&media=photos&sort=relevance&is_common=true&per_page=20&extras=url_s,url_q,url_m,url_n,url_z,url_c,url_l,url_o&api_key=%s&text=%s'
-end
-
-function flickr.on_inline_query(_, inline_query, _, language)
- local input = mattata.input(inline_query.query)
- if not input then
- return
- end
- local jstr = https.request(string.format(flickr.url, flickr.key, url.escape(input)))
- local jdat = json.decode(jstr)
- local results_list = {}
- local id = 1
- for n in pairs(jdat.photos.photo) do
- if jdat.photos.photo[n].url_l and jdat.photos.photo[n].url_s and jdat.photos.photo[n].url_l:match('%.jpe?g$') then
- table.insert(results_list, {
- ['type'] = 'photo',
- ['id'] = tostring(id),
- ['photo_url'] = jdat.photos.photo[n].url_l,
- ['thumb_url'] = jdat.photos.photo[n].url_s,
- ['photo_width'] = tonumber(jdat.photos.photo[n].width_l),
- ['photo_height'] = tonumber(jdat.photos.photo[n].height_l),
- ['caption'] = language['flickr']['1'] .. ' ' .. input
- })
- end
- id = id + 1
- end
- return mattata.answer_inline_query(inline_query.id, results_list)
-end
-
-function flickr.on_message(_, message, _, language)
- local input = mattata.input(message.text)
- if not input then
- local success = mattata.send_force_reply(message, language['flickr']['2'])
- if success then
- local action = string.format('action:%s:%s', message.chat.id, success.result.message_id)
- redis:set(action, '/flickr')
- end
- return
- end
- local jstr, res = https.request(string.format(flickr.url, flickr.key, url.escape(input)))
- if res ~= 200 then
- return mattata.send_reply(message, language.errors.connection)
- end
- local jdat = json.decode(jstr)
- if jdat.photos.total == '0' then
- return mattata.send_reply(message, language.errors.results)
- end
- mattata.send_chat_action(message.chat.id, 'upload_photo')
- local keyboard = mattata.inline_keyboard():row(mattata.row():url_button(
- language['flickr']['3'],
- 'https://www.flickr.com/search/?text=' .. url.escape(input)
- ))
- return mattata.send_photo(message.chat.id, jdat.photos.photo[1].url_o, nil, false, message.message_id, keyboard)
-end
-
-return flickr
\ No newline at end of file
diff --git a/plugins/flip.lua b/plugins/flip.lua
deleted file mode 100644
index 99d133d..0000000
--- a/plugins/flip.lua
+++ /dev/null
@@ -1,44 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local flip = {}
-local mattata = require('mattata')
-
-function flip:init()
- flip.commands = mattata.commands(self.info.username):command('flip'):command('reverse').table
- flip.help = '/flip [text] - Repeats the replied-to/given string of text, in reverse. Alias: /reverse.'
-end
-
-function flip.on_message(_, message)
- local input = message.reply and message.reply.text or mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, flip.help)
- end
- local chars = {}
- local ignore = {
- ['('] = ')',
- [')'] = '(',
- ['{'] = '}',
- ['}'] = '{',
- ['['] = ']',
- [']'] = '[',
- ['>'] = '<',
- ['<'] = '>',
- ['/'] = '\\',
- ['\\'] = '/'
- }
- for char in input:gmatch('.') do
- char = ignore[char] or char
- table.insert(chars, 1, char)
- end
- local output = table.concat(chars)
- local success = mattata.send_message(message.chat.id, output)
- if not success then
- return mattata.send_reply(message, 'I can\'t flip messages with special UTF-8 codepoints in (i.e. Emoji).')
- end
- return success
-end
-
-return flip
\ No newline at end of file
diff --git a/plugins/game.lua b/plugins/game.lua
deleted file mode 100644
index 050ac80..0000000
--- a/plugins/game.lua
+++ /dev/null
@@ -1,365 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local game = {}
-local mattata = require('mattata')
-local socket = require('socket')
-local json = require('dkjson')
-local redis = require('libs.redis')
-
-function game:init()
- game.commands = mattata.commands(self.info.username):command('game'):command('tictactoe').table
- game.help = '/game - View your current game statistics. Alias: /tictactoe.'
-end
-
-function game.get_stats(user_id, language)
- local user_won = redis:get('games_won:' .. user_id)
- if not user_won then
- user_won = 0
- end
- local user_lost = redis:get('games_lost:' .. user_id)
- if not user_lost then
- user_lost = 0
- end
- local balance = redis:get('balance:' .. user_id)
- if not balance then
- balance = 0
- end
- return string.format(language['game']['1'], user_won, user_lost, balance)
-end
-
-function game.set_stats(user_id, set_type)
- local user_won = redis:get('games_won:' .. user_id)
- if not user_won then
- user_won = 0
- end
- local user_lost = redis:get('games_lost:' .. user_id)
- if not user_lost then
- user_lost = 0
- end
- local balance = redis:get('balance:' .. user_id)
- if not balance then
- balance = 0
- end
- if set_type == 'won' then
- user_won = tonumber(user_won) + 1
- redis:set('games_won:' .. user_id, user_won)
- balance = tonumber(balance) + 100
- redis:set('balance:' .. user_id, balance)
- elseif set_type == 'lost' then
- user_lost = tonumber(user_lost) + 1
- redis:set('games_lost:' .. user_id, user_lost)
- balance = tonumber(balance) - 50
- redis:set('balance:' .. user_id, balance)
- end
-end
-
-function game.get_keyboard(session_id, join_game, language)
- join_game = join_game or false
- local g = redis:get('games:noughts_and_crosses:' .. session_id)
- if not g then
- return false
- end
- g = json.decode(g)
- local keyboard = {
- ['inline_keyboard'] = {{{
- ['text'] = g.moves.a1,
- ['callback_data'] = 'game:' .. session_id .. ':a1'
- }, {
- ['text'] = g.moves.a2,
- ['callback_data'] = 'game:' .. session_id .. ':a2'
- }, {
- ['text'] = g.moves.a3,
- ['callback_data'] = 'game:' .. session_id .. ':a3'
- }}, {{
- ['text'] = g.moves.b1,
- ['callback_data'] = 'game:' .. session_id .. ':b1'
- }, {
- ['text'] = g.moves.b2,
- ['callback_data'] = 'game:' .. session_id .. ':b2'
- }, {
- ['text'] = g.moves.b3,
- ['callback_data'] = 'game:' .. session_id .. ':b3'
- }}, {{
- ['text'] = g.moves.c1,
- ['callback_data'] = 'game:' .. session_id .. ':c1'
- }, {
- ['text'] = g.moves.c2,
- ['callback_data'] = 'game:' .. session_id .. ':c2'
- }, {
- ['text'] = g.moves.c3,
- ['callback_data'] = 'game:' .. session_id .. ':c3'
- }}}}
- if join_game then
- table.insert(keyboard.inline_keyboard, {{
- ['text'] = language['game']['2'],
- ['callback_data'] = 'game:' .. session_id .. ':join_game'
- }})
- end
- return keyboard
-end
-
-
-function game.on_callback_query(_, callback_query, _, _, language)
- local session_id = callback_query.data:match('^(%d+)%:')
- local g = redis:get('games:noughts_and_crosses:' .. session_id)
- if not g or not callback_query.inline_message_id then
- return
- end
- g = json.decode(g)
- if g.is_over == true then
- return mattata.answer_callback_query(callback_query.id, language['game']['3'])
- elseif g.has_opponent == true and g.is_over == false then
- if callback_query.from.id == g.opponent.id then
- if g.opponent.is_go == false then
- return mattata.answer_callback_query(callback_query.id, language['game']['4'])
- end
- elseif callback_query.from.id == g.player.id then
- if g.player.is_go == false then
- return mattata.answer_callback_query(callback_query.id, language['game']['4'])
- end
- end
- if not callback_query.data:match('^%d+%:%a%d$') then
- return
- end
- local pos = callback_query.data:match('^%d+%:(%a%d)$')
- local move = false
- if callback_query.from.id ~= g.opponent.id and callback_query.from.id ~= g.player.id then
- return mattata.answer_callback_query(callback_query.id, language['game']['5'])
- elseif callback_query.from.id == g.player.id then
- g.player.is_go = false
- g.opponent.is_go = true
- move = g.player.move
- elseif callback_query.from.id == g.opponent.id then
- g.player.is_go = true
- g.opponent.is_go = false
- move = g.opponent.move
- end
- if not move then
- return
- elseif g.moves[pos] ~= utf8.char(65039) then
- return mattata.answer_callback_query(callback_query.id, language['game']['6'])
- end
- g.moves[pos] = move
- if g.moves.a1 == g.moves.a2 and g.moves.a2 == g.moves.a3 and g.moves.a2 ~= utf8.char(65039) then
- g.winner = g.opponent.id
- g.loser = g.player.id
- if g.player.move == g.moves.a1 then
- g.winner = g.player.id
- g.loser = g.opponent.id
- end
- g.is_over = true
- g.was_won = true
- elseif g.moves.b1 == g.moves.b2 and g.moves.b2 == g.moves.b3 and g.moves.b2 ~= utf8.char(65039) then
- g.winner = g.opponent.id
- g.loser = g.player.id
- if g.player.move == g.moves.b1 then
- g.winner = g.player.id
- g.loser = g.opponent.id
- end
- g.is_over = true
- g.was_won = true
- elseif g.moves.c1 == g.moves.c2 and g.moves.c2 == g.moves.c3 and g.moves.c2 ~= utf8.char(65039) then
- g.winner = g.opponent.id
- g.loser = g.player.id
- if g.player.move == g.moves.c1 then
- g.winner = g.player.id
- g.loser = g.opponent.id
- end
- g.is_over = true
- g.was_won = true
- elseif g.moves.a1 == g.moves.b2 and g.moves.b2 == g.moves.c3 and g.moves.b2 ~= utf8.char(65039) then
- g.winner = g.opponent.id
- g.loser = g.player.id
- if g.player.move == g.moves.a1 then
- g.winner = g.player.id
- g.loser = g.opponent.id
- end
- g.is_over = true
- g.was_won = true
- elseif g.moves.a3 == g.moves.b2 and g.moves.b2 == g.moves.c1 and g.moves.b2 ~= utf8.char(65039) then
- g.winner = g.opponent.id
- g.loser = g.player.id
- if g.player.move == g.moves.a3 then
- g.winner = g.player.id
- g.loser = g.opponent.id
- end
- g.is_over = true
- g.was_won = true
- elseif g.moves.a2 == g.moves.b2 and g.moves.b2 == g.moves.c2 and g.moves.b2 ~= utf8.char(65039) then
- g.winner = g.opponent.id
- g.loser = g.player.id
- if g.player.move == g.moves.a2 then
- g.winner = g.player.id
- g.loser = g.opponent.id
- end
- g.is_over = true
- g.was_won = true
- elseif g.moves.b1 == g.moves.b2 and g.moves.b2 == g.moves.b3 and g.moves.b2 ~= utf8.char(65039) then
- g.winner = g.opponent.id
- g.loser = g.player.id
- if g.player.move == g.moves.b1 then
- g.winner = g.player.id
- g.loser = g.opponent.id
- end
- g.is_over = true
- g.was_won = true
- elseif g.moves.a1 == g.moves.b1 and g.moves.b1 == g.moves.c1 and g.moves.b1 ~= utf8.char(65039) then
- g.winner = g.opponent.id
- g.loser = g.player.id
- if g.player.move == g.moves.a1
- then
- g.winner = g.player.id
- g.loser = g.opponent.id
- end
- g.is_over = true
- g.was_won = true
- elseif g.moves.a2 == g.moves.b2 and g.moves.b2 == g.moves.c2 and g.moves.b2 ~= utf8.char(65039) then
- g.winner = g.opponent.id
- g.loser = g.player.id
- if g.player.move == g.moves.a2 then
- g.winner = g.player.id
- g.loser = g.opponent.id
- end
- g.is_over = true
- g.was_won = true
- elseif g.moves.a3 == g.moves.b3 and g.moves.b3 == g.moves.c3 and g.moves.b3 ~= utf8.char(65039) then
- g.winner = g.opponent.id
- g.loser = g.player.id
- if g.player.move == g.moves.a3 then
- g.winner = g.player.id
- g.loser = g.opponent.id
- end
- g.is_over = true
- g.was_won = true
- elseif g.moves.a1 ~= utf8.char(65039) and g.moves.a2 ~= utf8.char(65039) and g.moves.a3 ~= utf8.char(65039) and g.moves.b1 ~= utf8.char(65039) and g.moves.b2 ~= utf8.char(65039) and g.moves.b3 ~= utf8.char(65039) and g.moves.c1 ~= utf8.char(65039) and g.moves.c2 ~= utf8.char(65039) and g.moves.c3 ~= utf8.char(65039) then
- g.is_over = true
- end
- redis:set('games:noughts_and_crosses:' .. session_id, json.encode(g))
- elseif callback_query.data:match('^%d+%:join%_game$') then
- if callback_query.from.id == g.player.id then
- return mattata.answer_callback_query(callback_query.id, language['game']['7'])
- end
- g.has_opponent = true
- g.opponent.id = callback_query.from.id
- redis:set('games:noughts_and_crosses:' .. session_id, json.encode(g))
- else
- return mattata.answer_callback_query(callback_query.id, language['game']['8'])
- end
- local keyboard = game.get_keyboard(session_id)
- if not keyboard then
- return
- end
- local currently = g.player.id
- if g.player.is_go == false then
- currently = g.opponent.id
- end
- local output = string.format(
- language['game']['9'], mattata.get_linked_name(g.player.id),
- g.player.move, mattata.get_linked_name(g.opponent.id),
- g.opponent.move, mattata.get_linked_name(currently)
- )
- if g.is_over == true then
- if g.was_won == true then
- game.set_stats(g.winner, 'won')
- game.set_stats(g.loser, 'lost')
- output = string.format(
- language['game']['10'],
- mattata.get_linked_name(g.winner),
- mattata.get_linked_name(g.loser)
- )
- else
- output = string.format(
- language['game']['11'],
- mattata.get_linked_name(g.player.id),
- mattata.get_linked_name(g.opponent.id)
- )
- end
- end
- return mattata.edit_message_text(nil, nil, output, 'html', true, keyboard, callback_query.inline_message_id)
-end
-
-function game.on_inline_query(_, inline_query, _, language)
- local session_id = tostring(socket.gettime()):gsub('%D', '')
- local rnd = math.random(10)
- local g = {
- ['is_over'] = false,
- ['was_won'] = false,
- ['has_opponent'] = false,
- ['player'] = {
- ['id'] = inline_query.from.id,
- ['move'] = utf8.char(10060),
- ['is_go'] = true
- },
- ['opponent'] = {
- ['id'] = utf8.char(65039),
- ['move'] = utf8.char(11093),
- ['is_go'] = false
- },
- ['moves'] = {
- ['a1'] = utf8.char(65039),
- ['a2'] = utf8.char(65039),
- ['a3'] = utf8.char(65039),
- ['b1'] = utf8.char(65039),
- ['b2'] = utf8.char(65039),
- ['b3'] = utf8.char(65039),
- ['c1'] = utf8.char(65039),
- ['c2'] = utf8.char(65039),
- ['c3'] = utf8.char(65039)
- }
- }
- if math.random(2) == 1 then
- g.player.is_go = false
- g.opponent.is_go = true
- end
- if rnd == 2 then
- g.player.move = utf8.char(128514)
- g.opponent.move = utf8.char(128561)
- elseif rnd == 3 then
- g.player.move = utf8.char(127814)
- g.opponent.move = utf8.char(127825)
- elseif rnd == 4 then
- g.player.move = utf8.char(10084)
- g.opponent.move = utf8.char(128420)
- elseif rnd == 5 then
- g.player.move = utf8.char(128584)
- g.opponent.move = utf8.char(128585)
- elseif rnd == 6 then
- g.player.move = utf8.char(127770)
- g.opponent.move = utf8.char(127773)
- elseif rnd == 7 then
- g.player.move = utf8.char(128293)
- g.opponent.move = utf8.char(10052)
- elseif rnd == 8 then
- g.player.move = utf8.char(127823)
- g.opponent.move = utf8.char(127821)
- elseif rnd == 9 then
- g.player.move = 'Ayy'
- g.opponent.move = 'Lmao'
- elseif rnd == 10 then
- g.player.move = utf8.char(128166)
- g.opponent.move = utf8.char(128520)
- end
- redis:set('games:noughts_and_crosses:' .. session_id, json.encode(g))
- local status = language['game']['12']
- local keyboard = game.get_keyboard(session_id, true, language)
- return mattata.send_inline_article(
- inline_query.id,
- language['game']['13'],
- language['game']['14'],
- status, nil, keyboard
- )
-end
-
-function game.on_message(_, message, _, language)
- local keyboard = mattata.inline_keyboard():row(mattata.row():switch_inline_query_current_chat_button(
- language['game']['16'], '/game'
- ))
- local stats = game.get_stats(message.from.id, language)
- local output = string.format(language['game']['15'], message.from.name) .. stats
- return mattata.send_message(message.chat.id, output, nil, true, false, nil, keyboard)
-end
-
-return game
\ No newline at end of file
diff --git a/plugins/gif.lua b/plugins/gif.lua
deleted file mode 100644
index e48165e..0000000
--- a/plugins/gif.lua
+++ /dev/null
@@ -1,63 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local gif = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local json = require('dkjson')
-local redis = require('libs.redis')
-
-function gif:init()
- gif.commands = mattata.commands(self.info.username):command('gif'):command('giphy').table
- gif.help = '/gif <query> - Searches GIPHY for the given search query and returns a random, relevant result. Alias: /giphy.'
- gif.url = 'https://api.giphy.com/v1/gifs/search?api_key=dc6zaTOxFJmzC&q=' -- Includes the public test API key, because we don't have that many calls to it
-end
-
-function gif.on_inline_query(_, inline_query)
- local input = mattata.input(inline_query.query)
- if not input then
- return
- end
- local jstr = https.request(gif.url .. url.escape(input))
- local jdat = json.decode(jstr)
- local results = {}
- local id = 1
- for n in pairs(jdat.data) do
- local result = mattata.inline_result()
- :type('mpeg4_gif'):id(id)
- :mpeg4_url(jdat.data[n].images.original.mp4)
- :thumb_url(jdat.data[n].images.fixed_height.url)
- :mpeg4_width(jdat.data[n].images.original.width)
- :mpeg4_height(jdat.data[n].images.original.height)
- table.insert(results, result)
- id = id + 1
- end
- return mattata.answer_inline_query(inline_query.id, results)
-end
-
-function gif.on_message(_, message, _, language)
- local input = mattata.input(message.text)
- if not input then
- local success = mattata.send_force_reply(message, language['gif']['1'])
- if success then
- local action = string.format('action:%s:%s', message.chat.id, success.result.message_id)
- redis:set(action, '/gif')
- end
- return
- end
- local jstr, res = https.request(gif.url .. url.escape(input))
- if res ~= 200 then
- return mattata.send_reply(message, language.errors.connection)
- end
- local jdat = json.decode(jstr)
- if not jdat.data or not jdat.data[1] then
- return mattata.send_reply(message, language.errors.results)
- end
- mattata.send_chat_action(message.chat.id, 'upload_photo')
- return mattata.send_document(message.chat.id, jdat.data[math.random(#jdat.data)].images.original.mp4)
-end
-
-return gif
\ No newline at end of file
diff --git a/plugins/github.lua b/plugins/github.lua
deleted file mode 100644
index 558d5c1..0000000
--- a/plugins/github.lua
+++ /dev/null
@@ -1,57 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local github = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local json = require('dkjson')
-
-function github:init()
- github.commands = mattata.commands(self.info.username):command('github'):command('gh').table
- github.help = '/github <username> <repository> - Returns information about the specified GitHub repository. Alias: /gh.'
-end
-
-function github:on_new_message(message, _, language)
- if message.text and message.text:match('github%.com/([%w%-_]+)/([%w%-_]+)') and not message.is_edited then
- local user, repo = message.text:match('github.com/([%w%-_]+)/([%w%-_]+)')
- message.text = '/github@' .. self.info.username:lower() .. ' ' .. user .. ' ' .. repo
- message.date = os.time()
- message.is_natural_language = true
- return github.on_message(_, message, _, language)
- end
- return
-end
-
-function github.on_message(_, message, _, language)
- local input = mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, github.help)
- end
- input = input:gsub('%s', '/')
- local jstr, res = https.request('https://api.github.com/repos/' .. input)
- if res ~= 200 and not message.is_natural_language then
- return mattata.send_reply(message, language.errors.connection)
- elseif res ~= 200 then
- return
- end
- local jdat = json.decode(jstr)
- if not jdat.id and not message.is_natural_language then
- return mattata.send_reply(message, language.errors.results)
- elseif not jdat.id then
- return
- end
- local title = '<a href="' .. jdat.html_url .. '">' .. mattata.escape_html(jdat.full_name) .. '</a>'
- if jdat.language then
- title = title .. ' <b>|</b> ' .. jdat.language
- end
- local description = jdat.description and '\n<pre>' .. mattata.escape_html(jdat.description) .. '</pre>\n' or '\n'
- local forks = jdat.forks_count == 1 and jdat.forks_count .. ' fork' or jdat.forks_count .. ' forks'
- local stargazers = jdat.stargazers_count == 1 and jdat.stargazers_count .. ' star' or jdat.stargazers_count .. ' stars'
- local subscribers = jdat.subscribers_count == 1 and jdat.subscribers_count .. ' watcher' or jdat.subscribers_count .. ' watchers'
- local output = string.format('%s%s<a href="%s/network">%s</a> <b>|</b> <a href="%s/stargazers">%s</a> <b>|</b> <a href="%s/watchers">%s</a>\nLast updated at %s.', title, description, jdat.html_url, forks, jdat.html_url, stargazers, jdat.html_url, subscribers, jdat.updated_at:gsub('T', ' '):gsub('Z', ''))
- return mattata.send_message(message.chat.id, output, 'html')
-end
-
-return github
\ No newline at end of file
diff --git a/plugins/hackernews.lua b/plugins/hackernews.lua
deleted file mode 100644
index 261623b..0000000
--- a/plugins/hackernews.lua
+++ /dev/null
@@ -1,87 +0,0 @@
---[[
- Based on a plugin by topkecleon. Licensed under GNU AGPLv3
- https://github.com/topkecleon/otouto/blob/master/LICENSE.
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local hackernews = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local json = require('dkjson')
-
-function hackernews:init()
- hackernews.commands = mattata.commands(self.info.username)
- :command('hackernews')
- :command('hn').table
- hackernews.help = '/hackernews - Sends the top stories from Hacker News. Alias: /hn.'
-end
-
-function hackernews.get_results(hackernews_topstories, hackernews_result, hackernews_article)
- local results = {}
- local jstr, res = https.request(hackernews_topstories)
- if res ~= 200
- then
- return false
- end
- local jdat = json.decode(jstr)
- for i = 1, 8
- do
- local result_jstr, result_res = https.request(hackernews_result:format(jdat[i]))
- if result_res ~= 200
- then
- return false
- end
- local result_jdat = json.decode(result_jstr)
- local result
- if result_jdat.url
- then
- result = string.format(
- '\n• <code>[</code><a href="%s">%s</a><code>]</code> <a href="%s">%s</a>',
- mattata.escape_html(hackernews_article:format(result_jdat.id)),
- result_jdat.id,
- mattata.escape_html(result_jdat.url),
- mattata.escape_html(result_jdat.title)
- )
- else
- result = string.format(
- '\n• <code>[</code><a href="%s">%s</a><code>]</code> %s',
- mattata.escape_html(hackernews_article:format(result_jdat.id)),
- result_jdat.id,
- mattata.escape_html(result_jdat.title)
- )
- end
- table.insert(
- results,
- result
- )
- end
- return results
-end
-
-function hackernews:on_message(message, configuration, language)
- local results = hackernews.get_results('https://hacker-news.firebaseio.com/v0/topstories.json', 'https://hacker-news.firebaseio.com/v0/item/%s.json', 'https://news.ycombinator.com/item?id=%s')
- if not results
- then
- return mattata.send_reply(
- message,
- language['errors']['connection']
- )
- end
- local result_count = message.chat.id == message.from.id
- and 8
- or 4
- local output = '<b>' .. language['hackernews']['1'] .. '</b>'
- for i = 1, result_count
- do
- output = output .. results[i]
- end
- mattata.send_chat_action(message.chat.id)
- return mattata.send_message(
- message.chat.id,
- output,
- 'html'
- )
-end
-
-return hackernews
\ No newline at end of file
diff --git a/plugins/help.lua b/plugins/help.lua
deleted file mode 100644
index 1ad4870..0000000
--- a/plugins/help.lua
+++ /dev/null
@@ -1,402 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local help = {}
-local mattata = require('mattata')
-
-function help:init(configuration)
- help.commands = mattata.commands(self.info.username):command('help'):command('start').table
- help.help = '/help [plugin] - A help-orientated menu is sent if no arguments are given. If arguments are given, usage information for the given plugin is sent instead. Alias: /start.'
- help.per_page = configuration.limits.help.per_page
-end
-
-function help.get_initial_keyboard()
- return mattata.inline_keyboard():row(
- mattata.row():callback_data_button(
- 'Links',
- 'help:links'
- ):callback_data_button(
- 'Admin Help',
- 'help:acmds'
- ):callback_data_button(
- 'Commands',
- 'help:cmds'
- )
- ):row(
- mattata.row():switch_inline_query_button(
- 'Inline Mode',
- '/'
- ):callback_data_button(
- 'Settings',
- 'help:settings'
- ):callback_data_button(
- 'Channels',
- 'help:channels'
- )
- )
-end
-
-function help.get_plugin_page(arguments_list, page)
- local plugin_count = #arguments_list
- local page_begins_at = tonumber(page) * help.per_page - (help.per_page - 1)
- local page_ends_at = tonumber(page_begins_at) + (help.per_page - 1)
- if tonumber(page_ends_at) > tonumber(plugin_count) then
- page_ends_at = tonumber(plugin_count)
- end
- local page_plugins = {}
- for i = tonumber(page_begins_at), tonumber(page_ends_at) do
- local plugin = arguments_list[i]
- if i < tonumber(page_ends_at) then
- plugin = plugin .. '\n'
- end
- table.insert(page_plugins, plugin)
- end
- return table.concat(page_plugins, '\n')
-end
-
-function help.get_back_keyboard()
- return mattata.inline_keyboard():row(
- mattata.row():callback_data_button(
- mattata.symbols.back .. ' Back',
- 'help:back'
- )
- )
-end
-
-function help.on_inline_query(_, inline_query, _, language)
- local offset = inline_query.offset and tonumber(inline_query.offset) or 0
- local output = mattata.get_inline_help(inline_query.query, offset)
- if not next(output) and offset == 0 then
- output = string.format(language['help']['2'], inline_query.query)
- return mattata.send_inline_article(inline_query.id, language['help']['1'], output)
- end
- offset = tostring(offset + 50)
- return mattata.answer_inline_query(inline_query.id, output, 0, false, offset)
-end
-
-function help:on_callback_query(callback_query, message, _, language)
- if callback_query.data == 'cmds' then
- local arguments_list = mattata.get_help(self, false, message.chat.id)
- local plugin_count = #arguments_list
- local page_count = math.floor(tonumber(plugin_count) / help.per_page)
- if math.floor(tonumber(plugin_count) / help.per_page) ~= tonumber(plugin_count) / help.per_page then
- page_count = page_count + 1
- end
- local output = help.get_plugin_page(arguments_list, 1)
- output = output .. mattata.escape_html(string.format(language['help']['3'], self.info.username))
- return mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- output,
- 'html',
- true,
- mattata.inline_keyboard():row(
- mattata.row():callback_data_button(
- mattata.symbols.back .. ' ' .. language['help']['4'],
- 'help:results:0'
- ):callback_data_button(
- '1/' .. page_count,
- 'help:pages:1:' .. page_count
- ):callback_data_button(
- language['help']['5'] .. ' ' .. mattata.symbols.next,
- 'help:results:2'
- )
- ):row(
- mattata.row():callback_data_button(
- mattata.symbols.back .. ' ' .. language['help']['6'],
- 'help:back'
- ):switch_inline_query_current_chat_button(
- '🔎 ' .. language['help']['7'],
- '/'
- )
- )
- )
- elseif callback_query.data:match('^results:%d*$') then
- local new_page = callback_query.data:match('^results:(%d*)$')
- local arguments_list = mattata.get_help(self, false, message.chat.id)
- local plugin_count = #arguments_list
- local page_count = math.floor(tonumber(plugin_count) / help.per_page)
- if math.floor(tonumber(plugin_count) / help.per_page) ~= tonumber(plugin_count) / help.per_page then
- page_count = page_count + 1
- end
- if tonumber(new_page) > tonumber(page_count) then
- new_page = 1
- elseif tonumber(new_page) < 1 then
- new_page = tonumber(page_count)
- end
- local output = help.get_plugin_page(arguments_list, new_page)
- output = output .. mattata.escape_html(string.format(language['help']['3'], self.info.username))
- return mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- output,
- 'html',
- true,
- mattata.inline_keyboard():row(
- mattata.row():callback_data_button(
- mattata.symbols.back .. ' ' .. language['help']['4'],
- 'help:results:' .. math.floor(tonumber(new_page) - 1)
- ):callback_data_button(
- new_page .. '/' .. page_count,
- 'help:pages:' .. new_page .. ':' .. page_count
- ):callback_data_button(
- language['help']['5'] .. ' ' .. mattata.symbols.next,
- 'help:results:' .. math.floor(tonumber(new_page) + 1)
- )
- ):row(
- mattata.row():callback_data_button(
- mattata.symbols.back .. ' ' .. language['help']['6'],
- 'help:back'
- ):switch_inline_query_current_chat_button(
- '🔎 ' .. language['help']['7'],
- '/'
- )
- )
- )
- elseif callback_query.data == 'acmds' then
- local arguments_list = mattata.get_help(self, true, message.chat.id)
- local plugin_count = #arguments_list
- local page_count = math.floor(tonumber(plugin_count) / help.per_page)
- if math.floor(tonumber(plugin_count) / help.per_page) ~= tonumber(plugin_count) / help.per_page then
- page_count = page_count + 1
- end
- local output = help.get_plugin_page(arguments_list, 1)
- output = output .. mattata.escape_html(string.format(language['help']['3'], self.info.username))
- return mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- output,
- 'html',
- true,
- mattata.inline_keyboard():row(
- mattata.row():callback_data_button(
- mattata.symbols.back .. ' ' .. language['help']['4'],
- 'help:aresults:0'
- ):callback_data_button(
- '1/' .. page_count,
- 'help:pages:1:' .. page_count
- ):callback_data_button(
- language['help']['5'] .. ' ' .. mattata.symbols.next,
- 'help:aresults:2'
- )
- ):row(
- mattata.row():callback_data_button(
- mattata.symbols.back .. ' ' .. language['help']['6'],
- 'help:back'
- )
- )
- )
- elseif callback_query.data:match('^aresults:%d*$') then
- local new_page = callback_query.data:match('^aresults:(%d*)$')
- local arguments_list = mattata.get_help(self, true, message.chat.id)
- local plugin_count = #arguments_list
- local page_count = math.floor(tonumber(plugin_count) / help.per_page)
- if math.floor(tonumber(plugin_count) / help.per_page) ~= tonumber(plugin_count) / help.per_page then
- page_count = page_count + 1
- end
- if tonumber(new_page) > tonumber(page_count) then
- new_page = 1
- elseif tonumber(new_page) < 1 then
- new_page = tonumber(page_count)
- end
- local output = help.get_plugin_page(arguments_list, new_page)
- output = output .. mattata.escape_html(string.format(language['help']['3'], self.info.username))
- return mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- output,
- 'html',
- true,
- mattata.inline_keyboard():row(
- mattata.row():callback_data_button(
- mattata.symbols.back .. ' ' .. language['help']['4'],
- 'help:aresults:' .. math.floor(tonumber(new_page) - 1)
- ):callback_data_button(
- new_page .. '/' .. page_count,
- 'help:pages:' .. new_page .. ':' .. page_count
- ):callback_data_button(
- language['help']['5'] .. ' ' .. mattata.symbols.next,
- 'help:aresults:' .. math.floor(tonumber(new_page) + 1)
- )
- ):row(
- mattata.row():callback_data_button(
- mattata.symbols.back .. ' ' .. language['help']['6'],
- 'help:back'
- )
- )
- )
- elseif callback_query.data:match('^pages:%d*:%d*$') then
- local current_page, total_pages = callback_query.data:match('^pages:(%d*):(%d*)$')
- return mattata.answer_callback_query(
- callback_query.id,
- string.format(language['help']['8'], current_page, total_pages)
- )
- elseif callback_query.data:match('^ahelp:') then
- return mattata.answer_callback_query(callback_query.id, 'This is an old keyboard, please request a new one using /help!')
- elseif callback_query.data == 'links' then
- return mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- language['help']['12'],
- nil,
- true,
- mattata.inline_keyboard():row(
- mattata.row():url_button(
- language['help']['13'],
- 'https://t.me/mattataDev'
- ):url_button(
- language['help']['14'],
- 'https://t.me/mattata'
- ):url_button(
- language['help']['15'],
- 'https://t.me/mattataSupport'
- )
- ):row(
- mattata.row():url_button(
- language['help']['16'],
- 'https://t.me/mattataFAQ'
- ):url_button(
- language['help']['17'],
- 'https://github.com/wrxck/mattata'
- ):url_button(
- language['help']['18'],
- 'https://paypal.me/wrxck'
- )
- ):row(
- mattata.row():url_button(
- language['help']['19'],
- 'https://t.me/storebot?start=mattatabot'
- ):url_button(
- language['help']['20'],
- 'https://t.me/mattataLog'
- ):url_button(
- 'Twitter',
- 'https://twitter.com/intent/user?screen_name=matt__hesketh'
- )
- ):row(
- mattata.row():callback_data_button(
- mattata.symbols.back .. ' ' .. language['help']['6'],
- 'help:back'
- )
- )
- )
- elseif callback_query.data == 'channels' then
- return mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- language['help']['12'],
- nil,
- true,
- mattata.inline_keyboard():row(
- mattata.row():url_button(
- 'no context',
- 'https://t.me/no_context'
- )
- ):row(
- mattata.row():callback_data_button(
- mattata.symbols.back .. ' ' .. language['help']['6'],
- 'help:back'
- )
- )
- )
- elseif callback_query.data == 'settings' then
- if message.chat.type == 'supergroup' and not mattata.is_group_admin(message.chat.id, callback_query.from.id) then
- return mattata.answer_callback_query(callback_query.id, language['errors']['admin'])
- end
- return mattata.edit_message_reply_markup(
- message.chat.id,
- message.message_id,
- nil,
- (
- message.chat.type == 'supergroup'
- and mattata.is_group_admin(
- message.chat.id,
- callback_query.from.id
- )
- )
- and mattata.inline_keyboard()
- :row(
- mattata.row():callback_data_button(
- language['help']['21'], 'administration:' .. message.chat.id .. ':page:1'
- ):callback_data_button(
- language['help']['22'], 'plugins:' .. message.chat.id .. ':page:1'
- )
- )
- :row(
- mattata.row():callback_data_button(
- language['help']['6'],
- 'help:back'
- )
- ) or mattata.inline_keyboard():row(
- mattata.row():callback_data_button(
- language['help']['22'], 'plugins:' .. message.chat.id .. ':page:1'
- )
- ):row(
- mattata.row():callback_data_button(
- language['help']['6'], 'help:back'
- )
- )
- )
- elseif callback_query.data == 'back' then
- return mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- string.format(
- language['help']['23'],
- mattata.escape_html(callback_query.from.first_name),
- mattata.escape_html(self.info.first_name),
- utf8.char(128513),
- utf8.char(128161),
- message.chat.type ~= 'private' and ' ' .. language['help']['24'] .. ' ' .. mattata.escape_html(message.chat.title) or '',
- utf8.char(128176)
- ),
- 'html',
- true,
- help.get_initial_keyboard(message.chat.type == 'supergroup' and message.chat.id or false)
- )
- end
-end
-
-function help:on_message(message, _, language)
- local input = mattata.input(message.text)
- if input and input:match('^[/!]?%w+$') then
- local plugin_documentation = false
- input = input:match('^/') and input or '/' .. input
- for _, v in pairs(self.plugin_list) do
- if v:match(input) then
- plugin_documentation = v
- end
- end
- if not plugin_documentation then -- if it wasn't a normal plugin, it might be an administrative one
- for _, v in pairs(self.administrative_plugin_list) do
- if v:match(input) then
- plugin_documentation = v
- end
- end
- end
- plugin_documentation = plugin_documentation or 'I couldn\'t find a plugin matching that command!'
- plugin_documentation = plugin_documentation .. '\n\nTo see all commands, just send /help.'
- return mattata.send_reply(message, plugin_documentation)
- end
- return mattata.send_message(
- message.chat.id,
- string.format(
- language['help']['23'],
- mattata.escape_html(message.from.first_name),
- mattata.escape_html(self.info.first_name),
- utf8.char(128513),
- utf8.char(128161),
- message.chat.type ~= 'private' and ' ' .. language['help']['24'] .. ' ' .. mattata.escape_html(message.chat.title) or '',
- utf8.char(128176)
- ),
- 'html',
- false,
- true,
- nil,
- help.get_initial_keyboard(message.chat.type == 'supergroup' and message.chat.id or false)
- )
-end
-
-return help
\ No newline at end of file
diff --git a/plugins/id.lua b/plugins/id.lua
deleted file mode 100644
index 2dfcb4d..0000000
--- a/plugins/id.lua
+++ /dev/null
@@ -1,160 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local id = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function id:init()
- id.commands = mattata.commands(self.info.username):command('id'):command('user'):command('whoami').table
- id.help = '/id [chat] - Sends information about the given chat. Input is also accepted via reply. Only /user will display user statistics. Aliases: /user, /whoami.'
-end
-
-function id.resolve_chat(input, language, send_chat_action, current_group, show_user_stats, api_mode)
- local output = {}
- if not input then
- return false
- elseif send_chat_action and current_group then
- mattata.send_chat_action(current_group, 'typing')
- end
- local success = mattata.get_user(input, false, true) or mattata.get_chat(input)
- if not success or not success.result then
- if api_mode then
- return false
- end
- return language['id']['1']
- end
- if success.result.type == 'private' then
- local name = success.result.first_name
- if success.result.last_name then
- name = name .. ' ' .. success.result.last_name
- end
- local nickname = redis:hget('user:' .. success.result.id .. ':info', 'nickname')
- if nickname then
- nickname = ', AKA <em>' .. mattata.escape_html(nickname) .. '</em>'
- else
- nickname = ''
- end
- table.insert(output, mattata.get_formatted_user(success.result.id, name, 'html') .. nickname .. ' <code>[' .. success.result.id .. ']</code>')
- if success.result.username then
- table.insert(output, '@' .. success.result.username)
- local previous = redis:smembers('user:' .. success.result.id .. ':usernames')
- if #previous > 1 then
- for pos, usr in pairs(previous) do
- if usr == success.result.username:lower() then
- table.remove(previous, pos)
- else
- previous[pos] = '@' .. previous[pos]:lower()
- end
- end
- previous = table.concat(previous, ', ')
- table.insert(output, '<b>Previous Usernames:</b> <code>' .. previous .. '</code>')
- end
- end
- if success.result.bio and success.result.bio ~= '' then
- table.insert(output, '<b>Bio:</b> <code>' .. mattata.escape_html(success.result.bio) .. '</code>')
- end
- local feds = id.get_fed_info(success.result.id)
- for _, line in pairs(feds) do
- table.insert(output, line)
- end
- if current_group and show_user_stats then
- local chat_member = mattata.get_chat_member(current_group, success.result.id)
- if not chat_member or not chat_member.result.status then
- table.insert(output, '\n<em>Not seen in this group!</em>')
- else
- local bans = redis:hget(string.format('chat:%s:%s', current_group, success.result.id), 'bans') or 0
- local kicks = redis:hget(string.format('chat:%s:%s', current_group, success.result.id), 'kicks') or 0
- local warnings = redis:hget(string.format('chat:%s:%s', current_group, success.result.id), 'warnings') or 0
- local unbans = redis:hget(string.format('chat:%s:%s', current_group, success.result.id), 'unbans') or 0
- local messages = redis:get('messages:' .. success.result.id .. ':' .. current_group) or 0
- local seen = #redis:keys('messages:' .. success.result.id .. ':*')
- table.insert(output, '\n<b>Group status:</b> <em>' .. chat_member.result.status .. '</em>')
- table.insert(output, '<b>Bans:</b> <em>' .. bans .. '</em>')
- table.insert(output, '<b>Kicks:</b> <em>' .. kicks .. '</em>')
- table.insert(output, '<b>Warnings:</b> <em>' .. warnings .. '</em>')
- table.insert(output, '<b>Unbans:</b> <em>' .. unbans .. '</em>')
- table.insert(output, '<b>Messages:</b> <em>' .. messages .. '</em>')
- table.insert(output, '<em>Seen in ' .. seen .. ' group(s)</em>')
- end
- end
- else
- table.insert(output, mattata.escape_html(success.result.title) .. ' <code>[' .. success.result.id .. '</code> (' .. success.result.type .. ')')
- if success.result.username then
- table.insert(output, '@' .. success.result.username)
- end
- if current_group ~= success.result.id then
- if success.result.description and success.result.description ~= '' then
- table.insert(output, '<b>Description:</b> <code>' .. mattata.escape_html(success.result.description) .. '</code>')
- end
- end
- end
- return output
-end
-
-function id.get_fed_info(user_id)
- local banned_from = redis:keys('fedban:*:' .. user_id)
- local banned_amount = #banned_from
- local output = {}
- table.insert(output, 'Banned from <code>' .. banned_amount .. '</code> Fed(s)')
- if banned_amount > 0 then
- table.insert(output, '<em>Use /fbaninfo to see why you\'ve been banned!</em>')
- end
- return output
-end
-
-function id.on_inline_query(_, inline_query, _, language)
- local input = mattata.input(inline_query.query) or inline_query.from.id
- local output = id.resolve_chat(input, language)
- output = type(output) == 'table' and table.concat(output, '\n') or output
- return mattata.answer_inline_query(
- inline_query.id,
- mattata.inline_result()
- :id()
- :type('article')
- :title(tostring(inline_query.query))
- :description(language['id']['4'])
- :input_message_content(
- mattata.input_text_message_content(output, 'html')
- )
- )
-end
-
-function id.on_message(_, message, _, language)
- message.text = message.text:lower()
- local is_reply, is_reply_chat, old_chat_object = false, false, message.chat
- if message.reply then
- is_reply = true
- message.from = message.reply.from
- message.chat = message.reply.chat
- if message.reply.forward_from then
- message.from = message.reply.forward_from
- end
- if message.reply.forward_from_chat then
- is_reply_chat = true
- message.chat = message.reply.forward_from_chat
- end
- end
- mattata.send_chat_action(old_chat_object.id)
- local has_input = mattata.input(message.text)
- local input = mattata.input(message.text) or message.from.id
- local current_group = message.chat.type == 'supergroup' and message.chat.id or false
- local show_user_stats = message.text:match('^[!/#]user') and true or false
- local output = id.resolve_chat(input, language, true, current_group, show_user_stats)
- if not has_input and message.chat.type ~= 'private' and ((not is_reply) or is_reply_chat) and not show_user_stats then
- table.insert(output, '')
- local chat = id.resolve_chat(message.chat.id, language, false, current_group)
- for _, v in pairs(chat) do
- table.insert(output, v)
- end
- end
- if is_reply_chat then
- message.chat = old_chat_object
- end
- output = type(output) == 'table' and table.concat(output, '\n') or output
- return mattata.send_message(message.chat.id, output, 'html')
-end
-
-return id
\ No newline at end of file
diff --git a/plugins/imgur.lua b/plugins/imgur.lua
deleted file mode 100644
index 297003c..0000000
--- a/plugins/imgur.lua
+++ /dev/null
@@ -1,93 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local imgur = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local ltn12 = require('ltn12')
-local json = require('dkjson')
-
-function imgur:init()
- imgur.commands = mattata.commands(self.info.username):command('imgur').table
- imgur.help = '/imgur - Uploads the replied-to photo to Imgur and returns the post URL. If the image has a caption, that caption is used as the description.'
-end
-
-function imgur:on_message(message, configuration, language)
- if not message.reply
- then
- return mattata.send_reply(
- message,
- 'You must send this message as a reply to the photo you want to upload!'
- )
- elseif not message.reply.photo
- then
- return mattata.send_reply(
- message,
- 'That\'s not a photo! You must send this command in reply to a photo.'
- )
- end
- local success = mattata.get_file(message.reply.photo[#message.reply.photo].file_id)
- if not success
- or not success.result
- or not success.result.file_path
- then
- return mattata.send_reply(
- message,
- 'There was an error whilst retrieving that photo, so I could not upload it to Imgur - perhaps it\'s too old?'
- )
- end
- local query = 'image=' .. url.escape('https://api.telegram.org/file/bot' .. configuration.bot_token .. '/' .. success.result.file_path)
- if message.reply.caption
- then
- if message.reply.caption:match('^.- %- .-$')
- then
- local title, description = message.reply.caption:match('^(.-) %- (.-)$')
- query = query .. '&title=' .. url.escape(title)
- message.reply.caption = description
- end
- query = query .. '&description=' .. url.escape(message.reply.caption)
- end
- local response = {}
- local _, res = https.request(
- {
- ['url'] = 'https://api.imgur.com/3/image',
- ['method'] = 'POST',
- ['headers'] = {
- ['Authorization'] = 'Client-ID ' .. configuration['keys']['imgur']['client_id'],
- ['Content-Type'] = 'application/x-www-form-urlencoded',
- ['Content-Length'] = query:len()
- },
- ['source'] = ltn12.source.string(query),
- ['sink'] = ltn12.sink.table(response)
- }
- )
- if res ~= 200
- then
- return mattata.send_reply(
- message,
- language['errors']['connection']
- )
- end
- local jstr = table.concat(response)
- local jdat = json.decode(jstr)
- if not jdat
- or not jdat.success
- or not jdat.data
- or not jdat.data.link
- then
- return mattata.send_reply(
- message,
- 'There was an error whilst uploading that photo to Imgur!'
- )
- end
- return mattata.send_reply(
- message.reply,
- 'Image successfully uploaded to Imgur. Click [here](https://' .. jdat.data.link:match('^https?://i%.(.-%..-)%.') .. ') to view it.',
- 'markdown'
- )
-end
-
-return imgur
\ No newline at end of file
diff --git a/plugins/info.lua b/plugins/info.lua
deleted file mode 100644
index 8434bb7..0000000
--- a/plugins/info.lua
+++ /dev/null
@@ -1,50 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local info = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function info:init()
- info.commands = mattata.commands(self.info.username):command('info').table
- info.help = '/info - View system information & statistics about the bot.'
-end
-
-function info:on_message(message, configuration, language)
- if not mattata.is_global_admin(message.from.id) then return false end
- local info = redis:info()
- if not info then
- return mattata.send_reply(message, language['errors']['generic'])
- end
- return mattata.send_message(
- message.chat.id,
- string.format(
- language['info']['1'],
- mattata.symbols.bullet,
- info.server.config_file,
- mattata.symbols.bullet,
- info.server.redis_mode,
- mattata.symbols.bullet,
- info.server.tcp_port,
- mattata.symbols.bullet,
- info.server.redis_version,
- mattata.symbols.bullet,
- info.server.uptime_in_days,
- mattata.symbols.bullet,
- info.server.process_id,
- mattata.symbols.bullet,
- mattata.comma_value(info.stats.expired_keys),
- mattata.symbols.bullet,
- mattata.comma_value(mattata.get_user_count()),
- mattata.symbols.bullet,
- mattata.comma_value(mattata.get_group_count()),
- mattata.symbols.bullet,
- io.popen('uname -a'):read('*all')
- ),
- 'markdown'
- )
-end
-
-return info
\ No newline at end of file
diff --git a/plugins/inspirobot.lua b/plugins/inspirobot.lua
deleted file mode 100644
index 3ee850e..0000000
--- a/plugins/inspirobot.lua
+++ /dev/null
@@ -1,43 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local inspirobot = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local ltn12 = require('ltn12')
-
-function inspirobot:init()
- inspirobot.commands = mattata.commands(self.info.username):command('inspirobot'):command('ib').table
- inspirobot.help = '/inspirobot - Returns an AI-generated inspirational quote, for endless enrichment of pointless human existence. Alias: /ib.'
-end
-
-function inspirobot.on_message(_, message)
- -- Try to mimic a normal browser's headers, don't want CF getting funny with us
- local url = {}
- local _, res = https.request({
- ['url'] = 'https://inspirobot.me/api?generate=true',
- ['method'] = 'GET',
- ['headers'] = {
- [':authority:'] = 'inspirobot.me',
- [':method:'] = 'GET',
- [':path:'] = '/api?generate=true',
- [':scheme:'] = 'HTTPS',
- ['dnt'] = 1,
- ['referer'] = 'https://inspirobot.me/',
- ['sec-fetch-dest:'] = 'empty',
- ['sec-fetch-mode'] = 'cors',
- ['sec-fetch-site'] = 'same-origin',
- ['user-agent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36 Edg/83.0.478.58'
- },
- ['sink'] = ltn12.sink.table(url)
- })
- url = table.concat(url)
- if res ~= 200 or not url:match('^https://generated%.inspirobot%.me/a/.-%.[jp][pn]e?g$') then
- return mattata.send_reply(message, 'I have nothing to say today.')
- end
- return mattata.send_photo(message.chat.id, url)
-end
-
-return inspirobot
diff --git a/plugins/instagram.lua b/plugins/instagram.lua
deleted file mode 100644
index b230e1b..0000000
--- a/plugins/instagram.lua
+++ /dev/null
@@ -1,69 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local instagram = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local ltn12 = require('ltn12')
-local json = require('dkjson')
-
-function instagram:init()
- instagram.commands = mattata.commands(self.info.username)
- :command('instagram')
- :command('ig').table
- instagram.help = '/instagram <Instagram username> - Sends the profile picture of the given Instagram user. Alias: /ig.'
-end
-
-function instagram.get_profile_pic(username)
- if not username then
- return false, "No username provided!"
- end
- local jstr, res = https.request('https://www.instadp.com/api/s2/' .. url.escape(username))
- if res ~= 200 then
- return false, "Connection error!"
- end
- jstr = jstr:gsub('\\', ''):gsub('%s+', '') -- trim whitespace
- local jdat = json.decode(jstr:match('^"(.-)"$'))
- if not jdat.data or not jdat.data[1] then
- return false, "No results found!"
- end
- return jdat.data[1].picture
-end
-
-function instagram:on_inline_query(inline_query, configuration, language)
- local input = mattata.input(inline_query.query)
- if not input then
- return
- end
- local pic, err = instagram.get_profile_pic(input)
- if not pic then
- return false, err
- end
- return mattata.send_inline_photo(inline_query.id, pic)
-end
-
-function instagram:on_message(message, configuration, language)
- local input = mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, instagram.help)
- end
- local pic, err = instagram.get_profile_pic(input)
- if not pic then
- return mattata.send_reply(message, err)
- end
- local keyboard = mattata.inline_keyboard():row(
- mattata.row():url_button(
- string.format(
- language['instagram']['1'],
- input
- ),
- 'https://www.instagram.com/' .. input
- )
- )
- return mattata.send_photo(message.chat.id, pic, nil, false, nil, keyboard)
-end
-
-return instagram
\ No newline at end of file
diff --git a/plugins/ipsw.lua b/plugins/ipsw.lua
deleted file mode 100644
index 3466a5c..0000000
--- a/plugins/ipsw.lua
+++ /dev/null
@@ -1,309 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local ipsw = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local json = require('dkjson')
-
-function ipsw:init()
- ipsw.commands = mattata.commands(self.info.username):command('ipsw').table
- ipsw.help = '/ipsw - Allows you to select the firmware information for your device and firmware version.'
- ipsw.data = {}
- local jstr, res = https.request('https://api.ipsw.me/v2.1/firmwares.json')
- if res == 200
- then
- ipsw.data = json.decode(jstr)
- end
- ipsw.devices = {}
- for k, v in pairs(ipsw.data.devices)
- do
- if k:lower():match('^appletv')
- then
- if not ipsw.devices['Apple TV']
- then
- ipsw.devices['Apple TV'] = {}
- end
- table.insert(ipsw.devices['Apple TV'], k)
- elseif k:lower():match('^ipad')
- then
- if not ipsw.devices['iPad']
- then
- ipsw.devices['iPad'] = {}
- end
- table.insert(ipsw.devices['iPad'], k)
- elseif k:lower():match('^ipod')
- then
- if not ipsw.devices['iPod']
- then
- ipsw.devices['iPod'] = {}
- end
- table.insert(ipsw.devices['iPod'], k)
- elseif k:lower():match('^iphone')
- then
- if not ipsw.devices['iPhone']
- then
- ipsw.devices['iPhone'] = {}
- end
- table.insert(ipsw.devices['iPhone'], k)
- end
- end
-end
-
-function ipsw.get_info(input)
- local device = input
- local version = 'latest'
- if input:match('^.- .-$')
- then
- device = input:match('^(.-) ')
- version = input:match(' (.-)$')
- end
- local jstr, res = https.request(
- string.format(
- 'https://api.ipsw.me/v2.1/%s/%s/info.json',
- url.escape(device),
- url.escape(version)
- )
- )
- if res ~= 200 or jstr == '[]'
- then
- return false
- end
- return json.decode(jstr)
-end
-
-function ipsw:on_inline_query(inline_query, configuration, language)
- local input = mattata.input(inline_query.query)
- if not input
- then
- return
- end
- local jdat = ipsw.get_info(input)
- if not jdat
- then
- return
- end
- return mattata.answer_inline_query(
- inline_query.id,
- mattata.inline_result()
- :type('article')
- :id(1)
- :title(jdat[1].device)
- :description('iOS ' .. jdat[1].version)
- :input_message_content(
- mattata.input_text_message_content(
- string.format(
- language['ipsw']['1'],
- jdat[1].device,
- jdat[1].version,
- jdat[1].md5sum,
- jdat[1].sha1sum,
- mattata.round(
- jdat[1].size / 1000000000,
- 2
- ),
- jdat[1].signed == false
- and utf8.char(10060)
- or utf8.char(9989),
- jdat[1].signed == false
- and language['ipsw']['2']
- or language['ipsw']['3']
- ),
- 'html'
- )
- )
- :reply_markup(
- mattata.inline_keyboard():row(
- mattata.row():url_button(
- jdat[1].filename,
- jdat[1].url
- )
- )
- )
- )
-end
-
-function ipsw.get_model_keyboard(device)
- local keyboard = {
- ['inline_keyboard'] = {
- {}
- }
- }
- local total = 0
- for _, v in pairs(ipsw.devices[device])
- do
- total = total + 1
- end
- local count = 0
- local rows = math.floor(total / 10)
- if rows ~= total
- then
- rows = rows + 1
- end
- local row = 1
- for k, v in pairs(ipsw.data.devices)
- do
- if k:lower():match(
- device:lower():gsub(' ', '')
- )
- then
- count = count + 1
- if count == rows * row
- then
- row = row + 1
- table.insert(
- keyboard.inline_keyboard,
- {}
- )
- end
- table.insert(
- keyboard.inline_keyboard[row],
- {
- ['text'] = v.name,
- ['callback_data'] = 'ipsw:model:' .. k
- }
- )
- end
- end
- return keyboard
-end
-
-function ipsw.get_firmware_keyboard(model)
- local keyboard = {
- ['inline_keyboard'] = {
- {}
- }
- }
- local total = 0
- for _, v in pairs(ipsw.data.devices[model].firmwares)
- do
- total = total + 1
- end
- local count = 0
- local rows = math.floor(total / 7)
- if rows ~= total
- then
- rows = rows + 1
- end
- local row = 1
- for k, v in pairs(ipsw.data.devices[model].firmwares)
- do
- count = count + 1
- if count == rows * row
- then
- row = row + 1
- table.insert(
- keyboard.inline_keyboard,
- {}
- )
- end
- table.insert(
- keyboard.inline_keyboard[row],
- {
- ['text'] = v.version,
- ['callback_data'] = 'ipsw:firmware:' .. model .. ' ' .. v.buildid
- }
- )
- end
- return keyboard
-end
-
-function ipsw:on_callback_query(callback_query, message, configuration, language)
- if callback_query.data:match('^device%:')
- then
- callback_query.data = callback_query.data:match('^device%:(.-)$')
- return mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- language['ipsw']['4'],
- nil,
- true,
- ipsw.get_model_keyboard(callback_query.data)
- )
- elseif callback_query.data:match('^model%:')
- then
- callback_query.data = callback_query.data:match('^model%:(.-)$')
- return mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- language['ipsw']['5'],
- nil,
- true,
- ipsw.get_firmware_keyboard(callback_query.data)
- )
- elseif callback_query.data:match('^firmware%:')
- then
- local jdat = ipsw.get_info(
- callback_query.data:match('^firmware%:(.-)$')
- )
- return mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- string.format(
- language['ipsw']['1'],
- jdat[1].device,
- jdat[1].version,
- jdat[1].md5sum,
- jdat[1].sha1sum,
- mattata.round(
- jdat[1].size / 1000000000,
- 2
- ),
- jdat[1].signed == false
- and utf8.char(10060)
- or utf8.char(9989),
- jdat[1].signed == false
- and language['ipsw']['2']
- or language['ipsw']['3']
- ),
- 'html',
- true,
- mattata.inline_keyboard():row(
- mattata.row():url_button(
- jdat[1].filename,
- jdat[1].url
- )
- )
- )
- end
-end
-
-function ipsw:on_message(message, configuration, language)
- ipsw.init(self)
- return mattata.send_message(
- message.chat.id,
- language['ipsw']['6'],
- nil,
- true,
- false,
- nil,
- mattata.inline_keyboard()
- :row(
- mattata.row()
- :callback_data_button(
- language['ipsw']['7'],
- 'ipsw:device:iPod'
- )
- :callback_data_button(
- language['ipsw']['8'],
- 'ipsw:device:iPhone'
- )
- )
- :row(
- mattata.row()
- :callback_data_button(
- language['ipsw']['9'],
- 'ipsw:device:iPad'
- )
- :callback_data_button(
- language['ipsw']['10'],
- 'ipsw:device:Apple TV'
- )
- )
- )
-end
-
-return ipsw
\ No newline at end of file
diff --git a/plugins/ispwned.lua b/plugins/ispwned.lua
deleted file mode 100644
index c9060d0..0000000
--- a/plugins/ispwned.lua
+++ /dev/null
@@ -1,47 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local ispwned = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local json = require('dkjson')
-
-function ispwned:init()
- ispwned.commands = mattata.commands(self.info.username):command('ispwned').table
- ispwned.help = '/ispwned <account> - Returns the existence of the given account in any major data leaks.'
-end
-
-function ispwned:on_message(message, configuration, language)
- local input = mattata.input(message.text)
- if not input
- then
- return mattata.send_reply(
- message,
- ispwned.help
- )
- end
- local jstr, res = https.request('https://haveibeenpwned.com/api/v2/breachedaccount/' .. url.escape(input))
- if res ~= 200
- then
- return mattata.send_reply(
- message,
- language['errors']['connection']
- )
- end
- local jdat = json.decode(jstr)
- local output = ''
- for n in pairs(jdat)
- do
- output = output .. '\n' .. mattata.escape_html(jdat[n].Title)
- end
- return mattata.send_message(
- message.chat.id,
- '<b>' .. language['ispwned']['1'] .. '</b>\n' .. output,
- 'html'
- )
-end
-
-return ispwned
\ No newline at end of file
diff --git a/plugins/itunes.lua b/plugins/itunes.lua
deleted file mode 100644
index d1fce85..0000000
--- a/plugins/itunes.lua
+++ /dev/null
@@ -1,207 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local itunes = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local json = require('dkjson')
-local redis = require('libs.redis')
-
-function itunes:init()
- itunes.commands = mattata.commands(self.info.username):command('itunes').table
- itunes.help = '/itunes <query> - Searches iTunes for the given search query and returns the most relevant result.'
-end
-
-function itunes.get_output(jdat, language)
- local output = {}
- if jdat.results[1].trackViewUrl
- and jdat.results[1].trackName
- then
- table.insert(
- output,
- '<b>' .. language['itunes']['1'] .. '</b> <a href=\'' .. jdat.results[1].trackViewUrl .. '\'>' .. mattata.escape_html(jdat.results[1].trackName) .. '</a>'
- )
- end
- if jdat.results[1].artistViewUrl
- and jdat.results[1].artistName
- then
- table.insert(
- output,
- '<b>' .. language['itunes']['2'] .. '</b> <a href="' .. jdat.results[1].artistViewUrl .. '">' .. mattata.escape_html(jdat.results[1].artistName) .. '</a>'
- )
- end
- if jdat.results[1].collectionViewUrl
- and jdat.results[1].collectionName
- then
- table.insert(
- output,
- '<b>' .. language['itunes']['3'] .. '</b> <a href="' .. jdat.results[1].collectionViewUrl .. '">' .. mattata.escape_html(jdat.results[1].collectionName) .. '</a>'
- )
- end
- if jdat.results[1].trackNumber
- and jdat.results[1].trackCount
- then
- table.insert(
- output,
- '<b>' .. language['itunes']['4'] .. '</b> ' .. jdat.results[1].trackNumber .. '/' .. jdat.results[1].trackCount
- )
- end
- if jdat.results[1].discNumber
- and jdat.results[1].discCount
- then
- table.insert(
- output,
- '<b>' .. language['itunes']['5'] .. '</b> ' .. jdat.results[1].discNumber .. '/' .. jdat.results[1].discCount
- )
- end
- return table.concat(
- output,
- '\n'
- )
-end
-
-function itunes:on_inline_query(inline_query)
- local input = mattata.input(inline_query.query)
- if not input
- then
- return
- end
- local jstr, res = https.request('https://itunes.apple.com/search?term=' .. url.escape(input))
- if res ~= 200
- then
- return
- end
- local jdat = json.decode(jstr)
- if not jdat.results[1]
- then
- return
- end
- local count = 0
- local results = {}
- local temp = {}
- for k, v in pairs(jdat.results)
- do
- if v.artworkUrl100
- and not temp[v.artworkUrl100]
- then
- count = count + 1
- table.insert(
- results,
- mattata.inline_result()
- :type('photo')
- :id(count)
- :photo_url(
- v.artworkUrl100
- :gsub('%/100x100bb%.jpg', '/10000x10000bb.jpg')
- )
- :thumb_url(v.artworkUrl100)
- )
- temp[v.artworkUrl100] = true
- end
- end
- return mattata.answer_inline_query(
- inline_query.id,
- results
- )
-end
-
-function itunes:on_callback_query(callback_query, message, configuration, language)
- if not message.reply
- then
- return mattata.answer_callback_query(
- callback_query.id,
- language['itunes']['6'],
- true
- )
- end
- local input = mattata.input(message.reply.text)
- if callback_query.data == 'artwork'
- then
- local jstr, res = https.request('https://itunes.apple.com/search?term=' .. url.escape(input))
- if res ~= 200
- then
- return false
- end
- local jdat = json.decode(jstr)
- if not jdat.results[1]
- then
- return false
- end
- if jdat.results[1].artworkUrl100
- then
- local artwork = jdat.results[1].artworkUrl100:gsub('%/100x100bb%.jpg', '/10000x10000bb.jpg')
- -- Get the highest quality artwork available.
- mattata.send_photo(
- message.chat.id,
- artwork
- )
- return mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- language['itunes']['7']
- )
- end
- end
-end
-
-function itunes:on_message(message, configuration, language)
- local input = mattata.input(message.text)
- if not input
- then
- local success = mattata.send_force_reply(
- message,
- language['itunes']['8']
- )
- if success
- then
- redis:set(
- string.format(
- 'action:%s:%s',
- message.chat.id,
- success.result.message_id
- ),
- '/itunes'
- )
- end
- return
- end
- mattata.send_chat_action(message.chat.id)
- local jstr, res = https.request('https://itunes.apple.com/search?term=' .. url.escape(input))
- if res ~= 200
- then
- return mattata.send_reply(
- message,
- language['errors']['connection']
- )
- end
- local jdat = json.decode(jstr)
- if not jdat.results[1]
- then
- return mattata.send_reply(
- message,
- language['errors']['results']
- )
- end
- return mattata.send_message(
- message.chat.id,
- itunes.get_output(
- jdat,
- language
- ),
- 'html',
- true,
- false,
- message.message_id,
- mattata.inline_keyboard():row(
- mattata.row():callback_data_button(
- language['itunes']['9'],
- 'itunes:artwork'
- )
- )
- )
-end
-
-return itunes
\ No newline at end of file
diff --git a/plugins/karma.lua b/plugins/karma.lua
deleted file mode 100644
index 9a42f80..0000000
--- a/plugins/karma.lua
+++ /dev/null
@@ -1,27 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local karma = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function karma.on_new_message(_, message)
- if message.chat.type == 'private' or not message.reply or (message.text ~= '+1' and message.text ~= '-1') or message.from.id == message.reply.from.id or message.reply.from.is_bot then
- return false
- end
- local risen = false
- if message.text == '+1' then
- risen = true
- redis:hincrby('user:' .. message.reply.from.id .. ':info', 'karma', 1)
- else
- redis:hincrby('user:' .. message.reply.from.id .. ':info', 'karma', -1)
- end
- local current = redis:hget('user:' .. message.reply.from.id .. ':info', 'karma')
- local user = mattata.get_formatted_user(message.reply.from.id, message.reply.from.first_name, 'html')
- local output = string.format('%s\'s karma has %s to %s.', user, risen and 'risen' or 'fallen', current)
- return mattata.send_message(message.chat.id, output, 'html')
-end
-
-return karma
\ No newline at end of file
diff --git a/plugins/languages.lua b/plugins/languages.lua
deleted file mode 100644
index fda59b4..0000000
--- a/plugins/languages.lua
+++ /dev/null
@@ -1,24 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local languages = {}
-local mattata = require('mattata')
-
-function languages:init()
- languages.commands = mattata.commands(self.info.username):command('languages').table
- languages.help = '/languages - Returns a list of languages that aren\'t currently supported by mattata, but are being spoken by users.'
-end
-
-function languages:on_message(message)
- local missing_languages = mattata.get_missing_languages()
- return mattata.send_message(
- message.chat.id,
- missing_languages
- and ('The following locales are languages my users speak that I do not currently have a translation file for:\n\n' .. missing_languages .. '\n\nIf you speak any of these languages well, and you are willing to volunteer your time into contributing to the development of mattata in the form of translating a file containing strings, please join https://t.me/mattataDev - thank you!')
- or 'At this moment in time, all of the languages spoken by my users have been translated, and can be selected by using /setlang!'
- )
-end
-
-return languages
\ No newline at end of file
diff --git a/plugins/lastfm.lua b/plugins/lastfm.lua
deleted file mode 100644
index 2490a03..0000000
--- a/plugins/lastfm.lua
+++ /dev/null
@@ -1,89 +0,0 @@
---[[
- Based on a plugin by topkecleon. Licensed under GNU AGPLv3
- https://github.com/topkecleon/otouto/blob/master/LICENSE.
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local lastfm = {}
-local mattata = require('mattata')
-local http = require('socket.http')
-local url = require('socket.url')
-local json = require('dkjson')
-local redis = require('libs.redis')
-
-function lastfm:init(configuration)
- assert(configuration.keys.lastfm, 'lastfm.lua requires an API key, and you haven\'t got one configured!')
- lastfm.commands = mattata.commands(self.info.username):command('lastfm'):command('np'):command('fmset').table
- lastfm.help = '/np <username> - Returns what you are or were last listening to. If you specify a username, info will be returned for that username. /fmset <username> - Sets your last.fm username. Use /fmset -del to delete your current username.'
- lastfm.url = 'http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&format=json&limit=1&api_key='
-end
-
-function lastfm.set_username(user_object, name, language)
- redis:hset('user:' .. user_object.id .. ':info', 'lastfm', name)
- return string.format(language['lastfm']['1'], user_object.first_name, name)
-end
-
-function lastfm.del_username(user_id, language)
- if redis:hget('user:' .. user_id .. ':info', 'lastfm') then
- redis:hdel('user:' .. user_id .. ':info', 'lastfm')
- return language['lastfm']['2']
- end
- return language['lastfm']['3']
-end
-
-function lastfm.get_username(user_id)
- return redis:hget('user:' .. user_id .. ':info', 'lastfm')
-end
-
-function lastfm:on_message(message, configuration, language)
- local input = mattata.input(message.text)
- if message.text:match('^[/!#]lastfm') then
- return mattata.send_reply(message, lastfm.help)
- elseif message.text:match('^[/!#]fmset') then
- input = input or message.from.username
- if not input then
- return mattata.send_reply(message, lastfm.help)
- elseif input == '-del' then
- local output = lastfm.del_username(message.from.id, language)
- return mattata.send_reply(message, output)
- end
- local output = lastfm.set_username(message.from, input, language)
- return mattata.send_reply(message, output)
- end
- local username, output
- if input then
- username = input
- elseif lastfm.get_username(message.from.id, language) then
- username = lastfm.get_username(message.from.id)
- else
- return mattata.send_reply(message, language['lastfm']['4'])
- end
- local jstr, res = http.request(lastfm.url .. configuration.keys.lastfm .. '&user=' .. url.escape(username))
- if res ~= 200 then
- return mattata.send_reply(message, language['errors']['connection'])
- end
- local jdat = json.decode(jstr)
- if jdat.error then
- return mattata.send_reply(message, language['lastfm']['4'])
- end
- if not jdat or not jdat.recenttracks then
- return mattata.send_reply(message.chat.id, language['lastfm']['5'])
- end
- jdat = jdat.recenttracks.track[1] or jdat.recenttracks.track
- output = input and mattata.escape_html(input) or string.format('<a href="%s">%s</a>', 'https://last.fm/user/' .. url.escape(username), mattata.escape_html(message.from.first_name))
- output = (jdat['@attr'] and jdat['@attr'].nowplaying) and string.format(language['lastfm']['6'], output) or string.format(language['lastfm']['7'], output)
- local title = jdat.name or language['lastfm']['8']
- local artist = jdat.artist and jdat.artist['#text'] or language['lastfm']['8']
- if artist and title ~= jdat.name then
- mattata.send_chat_action(message.chat.id)
- return mattata.send_message(message.chat.id, output .. artist .. ' - ' .. title)
- elseif jdat.image and jdat.image[1]['#text'] == '' then
- return mattata.send_message(message.chat.id, output .. artist .. ' - ' .. title)
- end
- mattata.send_chat_action(message.chat.id, 'upload_photo')
- output = output .. string.format('<a href="%s">%s</a>', jdat.url, artist .. ' - ' .. title)
- return mattata.send_photo(message.chat.id, jdat.image[4]['#text'], output, 'html')
-end
-
-return lastfm
\ No newline at end of file
diff --git a/plugins/lmgtfy.lua b/plugins/lmgtfy.lua
deleted file mode 100644
index 8966755..0000000
--- a/plugins/lmgtfy.lua
+++ /dev/null
@@ -1,37 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local lmgtfy = {}
-local mattata = require('mattata')
-local url = require('socket.url')
-local redis = require('libs.redis')
-
-function lmgtfy:init()
- lmgtfy.commands = mattata.commands(self.info.username):command('lmgtfy').table
- lmgtfy.help = '/lmgtfy [anything] - Helps that special someone out. Input can be given via an argument or using the replied-to person\'s message text.'
-end
-
-function lmgtfy:on_message(message)
- local input = mattata.input(message.text)
- if not input then
- if not message.reply then
- return mattata.send_reply(message, lmgtfy.help)
- end
- input = message.reply.text
- end
- if message.reply then
- message.message_id = message.reply.message_id -- if we're sending in reply to a reply, we need it to trick it!
- end
- input = 'https://lmgtfy.com/?q=' .. url.escape(input)
- local output = redis:get('chat:' .. message.chat.id .. ':lmgtfy') or 'Here you go, idiot.'
- output = mattata.escape_html(output)
- output = string.format('<a href="%s">%s</a>', input, output)
- if message.reply then
- return mattata.send_reply(message, output, 'html')
- end
- return mattata.send_message(message.chat.id, output, 'html')
-end
-
-return lmgtfy
\ No newline at end of file
diff --git a/plugins/location.lua b/plugins/location.lua
deleted file mode 100644
index c4126ce..0000000
--- a/plugins/location.lua
+++ /dev/null
@@ -1,81 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local location = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local json = require('dkjson')
-local setloc = require('plugins.setloc')
-local redis = require('libs.redis')
-
-function location:init()
- location.commands = mattata.commands(self.info.username):command('location'):command('loc').table
- location.help = '/location [query] - Sends your location, or a location from Google Maps. Alias: /loc.'
-end
-
-function location:on_inline_query(inline_query, configuration)
- local input = mattata.input(inline_query.query)
- local result = {}
- if not input then
- local loc = setloc.get_loc(inline_query.from.id)
- if not loc then
- return false, 'No location was found for the given user!'
- end
- local jdat = json.decode(loc)
- local output = mattata.inline_result():type('location'):id(1):title(jdat.address):latitude(jdat.latitude):longitude(jdat.longitude)
- return mattata.answer_inline_query(inline_query.id, output)
- end
- local jstr, res = https.request('https://api.opencagedata.com/geocode/v1/json?key=' .. configuration['keys']['location'] .. '&pretty=0&q=' .. url.escape(input))
- if res ~= 200 then
- return false, 'Connection error! [' .. res .. ']'
- end
- local jdat = json.decode(jstr)
- if jdat.total_results == 0 then
- return false, 'No results were found!'
- end
- local output = mattata.inline_result():type('location'):id(1):title(input):latitude(jdat.results[1].geometry.lat):longitude(jdat.results[1].geometry.lng)
- return mattata.answer_inline_query(inline_query.id, output)
-end
-
-function location:on_message(message, configuration, language)
- local input = mattata.input(message.text:lower())
- if not input and not setloc.get_loc(message.from.id) then
- local success = mattata.send_force_reply(message, language['location']['1'])
- if success then
- local action = mattata.command_action(message.chat.id, success.result.message_id)
- redis:set(action, '/setloc')
- end
- return
- elseif not input then
- local loc = setloc.get_loc(message.from.id)
- return mattata.send_location(
- message.chat.id,
- json.decode(loc).latitude,
- json.decode(loc).longitude
- )
- end
- local jstr, res = https.request('https://api.opencagedata.com/geocode/v1/json?key=' .. configuration['keys']['location'] .. '&pretty=0&q=' .. url.escape(input))
- if res ~= 200 then
- return mattata.send_reply(
- message,
- language['errors']['connection']
- )
- end
- local jdat = json.decode(jstr)
- if jdat.total_results == 0 then
- return mattata.send_reply(
- message,
- language['errors']['results']
- )
- end
- return mattata.send_location(
- message.chat.id,
- jdat.results[1].geometry.lat,
- jdat.results[1].geometry.lng
- )
-end
-
-return location
\ No newline at end of file
diff --git a/plugins/lua.lua b/plugins/lua.lua
deleted file mode 100644
index f7f7354..0000000
--- a/plugins/lua.lua
+++ /dev/null
@@ -1,67 +0,0 @@
---[[
- Based on a plugin by topkecleon. Licensed under GNU AGPLv3
- https://github.com/topkecleon/otouto/blob/master/LICENSE.
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local lua = {}
-local mattata = require('mattata')
-local json = require('dkjson')
-
-function lua:init()
- lua.commands = mattata.commands(self.info.username):command('lua').table
- lua.error_message = function(error_message)
- return 'Error:\n' .. tostring(error_message)
- end
-end
-
-function lua:on_message(message, configuration, language)
- if not mattata.is_global_admin(message.from.id) then
- return
- end
- local input = mattata.input(message.text)
- if not input then
- local text = language['lua']['1']
- return mattata.send_reply(message, text)
- end
- local output, success = load(
- "local mattata = require('mattata')\n\z
- local configuration = require('configuration')\n\z
- local api = require('telegram-bot-lua.core').configure(configuration.bot_token)\n\z
- local tools = require('telegram-bot-lua.tools')\n\z
- local https = require('ssl.https')\n\z
- local http = require('socket.http')\n\z
- local url = require('socket.url')\n\z
- local ltn12 = require('ltn12')\n\z
- local json = require('dkjson')\n\z
- local utf8 = require('lua-utf8')\n\z
- local socket = require('socket')\n\z
- local redis = require('libs.redis')\n\z
- return function (self, message, configuration)\n" .. input .. '\nend')
- if output == nil then
- output = success
- else
- success, output = xpcall(
- output(),
- lua.error_message,
- self,
- message,
- configuration
- )
- end
- if output ~= nil and type(output) == 'table' then
- output = json.encode(output, { ['indent'] = true })
- elseif output == nil then
- return false
- end
- return mattata.send_message(
- message.chat.id,
- '<pre>' .. mattata.escape_html(
- tostring(output)
- ) .. '</pre>',
- 'html'
- )
-end
-
-return lua
\ No newline at end of file
diff --git a/plugins/lyrics.lua b/plugins/lyrics.lua
deleted file mode 100644
index 8f9ae7c..0000000
--- a/plugins/lyrics.lua
+++ /dev/null
@@ -1,475 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local lyrics = {}
-local mattata = require('mattata')
-local https = require('libs.https')
-local http = require('socket.http')
-local url = require('socket.url')
-local ltn12 = require('ltn12')
-local json = require('dkjson')
-local html = require('htmlEntities')
-local redis = require('libs.redis')
-local socket = require('socket')
-local configuration = require('configuration')
-
-function lyrics:init()
- assert(configuration.keys.lyrics, 'lyrics.lua requires an API key, and you haven\'t got one configured!')
- lyrics.commands = mattata.commands(self.info.username):command('lyrics').table
- lyrics.help = '/lyrics <query> - Finds the lyrics to the given track.'
-end
-
-function lyrics.search_lyrics_fandom(artist, track)
- local str, res = https.request(
- string.format(
- 'https://lyrics.fandom.com/wiki/%s:%s',
- url.escape(artist:gsub('%s', '_')),
- url.escape(track:gsub('%s', '_'))
- , false, 1)
- )
- if res ~= 200 then
- return false
- end
- str = str:match('%<div class%=%\'lyricbox%\'%>(.-)%<div class%=%\'lyricsbreak%\'%>')
- if not str or str:match('[Uu]nfortunately%,? we are not licensed%.?') then
- return false
- end
- str = str:gsub('%<br ?%/?%>', '\n'):gsub('%<%/?b%>', ''):gsub('%<%/?i%>', '')
- return html.decode(str)
-end
-
-function lyrics.search_az_lyrics(artist, track)
- local response = {}
- local _, res = https.request(
- {
- ['url'] = string.format(
- 'https://www.azlyrics.com/lyrics/%s/%s.html',
- url.escape(
- artist:lower():gsub('%s', '')
- ),
- url.escape(
- track:lower():gsub('%s', '')
- )
- ),
- ['method'] = 'GET',
- ['headers'] = {
- ['Accept'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
- ['Accept-Encoding'] = 'gzip, deflate, sdch',
- ['Accept-Language'] = 'en-US,en;q=0.8',
- ['Cache-Control'] = 'max-age=0',
- ['DNT'] = '1',
- ['Host'] = 'www.azlyrics.com',
- ['Upgrade-Insecure-Requests'] = '1',
- ['User-Agent'] = 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Mobile Safari/537.36'
- },
- ['sink'] = ltn12.sink.table(response)
- }
- )
- if res ~= 200
- then
- return false
- end
- local str = table.concat(response):match('%<%!%-%- Usage of azlyrics%.com content by any third%-party lyrics provider is prohibited by our licensing agreement%. Sorry about that%. %-%-%>(.-)%<%/div%>'):gsub('%<br ?%/?%>', ''):gsub('%<%/?b%>', ''):gsub('%<%/?i%>', '')
- if not str
- then
- return false
- end
- return html.decode(str)
-end
-
-function lyrics.search_plyrics(artist, track)
- local response = {}
- local _, res = http.request(
- {
- ['url'] = string.format(
- 'http://www.plyrics.com/lyrics/%s/%s.html',
- url.escape(
- artist:lower():gsub('%s', '')
- ),
- url.escape(
- track:lower():gsub('%s', '')
- )
- ),
- ['method'] = 'GET',
- ['headers'] = {
- ['Accept'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
- ['Accept-Encoding'] = 'gzip, deflate, sdch',
- ['Accept-Language'] = 'en-US,en;q=0.8',
- ['Cache-Control'] = 'max-age=0',
- ['Cookie'] = '__utmt=1; __utma=179262907.1714206337.1484225238.1484225238.1484225238.1; __utmb=179262907.1.10.1484225238; __utmc=179262907; __utmz=179262907.1484225238.1.1.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=(not%20provided)',
- ['Host'] = 'www.plyrics.com',
- ['Upgrade-Insecure-Requests'] = '1',
- ['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'
- },
- ['sink'] = ltn12.sink.table(response)
- }
- )
- if res ~= 200
- then
- return false
- end
- local str = table.concat(response)
- if not str
- then
- return false
- end
- str = str:match('%<%!%-%- start of lyrics %-%-%>(.-)%<%!%-%- end of lyrics %-%-%>')
- str = str:gsub('%<br ?%/?%>', '')
- :gsub('%<%/?b%>', '')
- :gsub('%<%/?i%>', '')
- if not str
- then
- return false
- end
- return html.decode(str)
-end
-
-function lyrics.search_lyrics(artist, track)
- local success = lyrics.search_lyrics_fandom(
- artist,
- track
- )
- if not success
- then
- success = lyrics.search_plyrics(
- artist,
- track
- )
- end
- if not success
- then
- success = lyrics.search_az_lyrics(
- artist,
- track
- )
- end
- if not success
- then
- return false
- end
- return success
-end
-
-function lyrics.send_request(input, inline, no_html)
- local search_url = string.format(
- 'https://api.musixmatch.com/ws/1.1/track.search?apikey=%s&s_track_rating=desc',
- configuration.keys.lyrics
- )
- if input:match('^.- %- .-$')
- then -- Perform a more specific search if the user searches for lyrics in the
- -- format artist - song.
- search_url = string.format(
- '%s&q_artist=%s&q_track=%s',
- search_url,
- url.escape(
- input:match('^(.-) %- .-$')
- ),
- url.escape(
- input:match('^.- %- (.-)$')
- )
- )
- else
- search_url = string.format(
- '%s&q_track=%s',
- search_url,
- url.escape(input)
- )
- end
- local jstr, res = https.request(search_url, false, 1)
- if res ~= 200 then
- return false
- end
- local jdat = json.decode(jstr)
- if jdat.message.header.available == 0 then
- jstr, res = https.request(
- string.format(
- 'https://api.musixmatch.com/ws/1.1/track.search?apikey=%s&s_track_rating=desc&q=%s',
- configuration.keys.lyrics,
- url.escape(input)
- )
- )
- if res ~= 200 then
- return false
- end
- jdat = json.decode(jstr)
- if jdat.message.header.available == 0 then
- return false
- end
- end
- if not jdat.message or not jdat.message.body or not jdat.message.body.track_list then
- return false
- elseif inline then
- return jdat
- end
- local artist = jdat.message.body.track_list[1].track.artist_name
- local track = jdat.message.body.track_list[1].track.track_name
- track = track:match('^(.-) %(.-%) %[.-%]$') or track:match('^(.-) %(.-%)$') or track
- local output = lyrics.search_lyrics(artist, track)
- if not output then
- local jstr_lyrics, res_lyrics = https.request(
- string.format(
- 'https://api.musixmatch.com/ws/1.1/track.lyrics.get?apikey=%s&track_id=%s',
- configuration.keys.lyrics,
- jdat.message.body.track_list[1].track.track_id
- )
- )
- if res_lyrics ~= 200
- then
- return false
- end
- local jdat_lyrics = json.decode(jstr_lyrics)
- if jdat_lyrics.message.header.status_code ~= 200
- then
- return false
- end
- output = jdat_lyrics.message.body.lyrics.lyrics_body:match('^(.-)\n\n[%*]+')
- or jdat_lyrics.message.body.lyrics.lyrics_body
- end
- if output:len() > 4000 then -- If the lyrics are REALLY long, trim them so they'll
- -- fit in a single message (this is only a temporary solution)
- output = output:sub(1, 4000) .. '...'
- end
- output = output:gsub('\\', '')
- output = string.format(
- '%s%s%s %s\n\n%s',
- not no_html
- and '<b>'
- or '',
- mattata.escape_html(track),
- not no_html and '</b>' or '',
- mattata.escape_html(artist),
- mattata.escape_html(output)
- )
- return output, artist, track
-end
-
-function lyrics.search_spotify(input)
- local jstr, res = https.request(
- string.format(
- 'https://api.spotify.com/v1/search?q=%s&type=track',
- url.escape(input)
- )
- )
- if res ~= 200
- then
- return false
- end
- local jdat = json.decode(jstr)
- if not jdat.tracks
- or jdat.tracks.total == 0
- then
- return false
- end
- return 'https://open.spotify.com/track/' .. jdat.tracks.items[1].id
-end
-
-function lyrics.get_keyboard(artist, track, language)
- local spotify_url = lyrics.search_spotify(artist .. ' ' .. track)
- local keyboard = {
- ['inline_keyboard'] = {}
- }
- if spotify_url
- then
- table.insert(
- keyboard.inline_keyboard,
- {
- {
- ['text'] = language['lyrics']['1'],
- ['url'] = spotify_url
- }
- }
- )
- return keyboard
- end
- return nil
-end
-
-function lyrics:on_inline_query(inline_query, _, language)
- local input = mattata.input(inline_query.query)
- if not input
- then
- return
- end
- local output = lyrics.send_request(
- input,
- true,
- false
- )
- if not output
- then
- return
- end
- local results = {}
- local count = 0
- for n in pairs(output.message.body.track_list)
- do
- local artist = output.message.body.track_list[n].track.artist_name
- local track = output.message.body.track_list[n].track.track_name
- local track_id = output.message.body.track_list[n].track.track_id
- if artist
- and track
- and track_id
- then
- count = count + 1
- local id = socket.gettime() * 10000
- id = tostring(id):gsub('%D', '')
- local payload = {
- ['artist'] = artist,
- ['track'] = track,
- ['track_id'] = track_id
- }
- redis:set(
- 'lyrics:' .. id,
- json.encode(payload)
- )
- table.insert(
- results,
- mattata.inline_result()
- :type('article')
- :id(count)
- :title(track)
- :description(artist)
- :input_message_content(
- mattata.input_text_message_content(
- string.format(
- '%s - %s',
- track,
- artist
- )
- )
- )
- :reply_markup(
- mattata.inline_keyboard():row(
- mattata.row():callback_data_button(
- language['lyrics']['2'],
- 'lyrics:' .. id
- )
- )
- )
- )
- end
- end
- if not results
- or results == {}
- then
- return
- end
- return mattata.answer_inline_query(
- inline_query.id,
- results
- )
-end
-
-function lyrics:on_callback_query(callback_query, _, _, language)
- local data = redis:get('lyrics:' .. callback_query.data)
- if not data
- then
- return
- end
- local output = lyrics.search_lyrics(
- json.decode(data).artist,
- json.decode(data).track
- )
- if not output
- then
- local jstr_lyrics, res_lyrics = https.request(
- string.format(
- 'https://api.musixmatch.com/ws/1.1/track.lyrics.get?apikey=%s&track_id=%s',
- configuration.keys.lyrics,
- json.decode(data).track_id
- )
- )
- if res_lyrics ~= 200
- then
- return
- end
- local jdat_lyrics = json.decode(jstr_lyrics)
- if jdat_lyrics.message.header.status_code ~= 200
- then
- return
- end
- output = jdat_lyrics.message.body.lyrics.lyrics_body:match('^(.-)\n\n[%*]+')
- or jdat_lyrics.message.body.lyrics.lyrics_body
- end
- if output:len() > 4000 then -- If the lyrics are REALLY long, trim them so they'll
- -- fit in a single message (this is only a temporary solution)
- output = output:sub(1, 4000) .. '...'
- end
- output = output:gsub('\\', '')
- output = string.format(
- '<b>%s</b> %s\n\n%s',
- mattata.escape_html(json.decode(data).track),
- mattata.escape_html(json.decode(data).artist),
- mattata.escape_html(output)
- )
- local keyboard = lyrics.get_keyboard(
- json.decode(data).artist,
- json.decode(data).track,
- language
- )
- if keyboard
- and keyboard.inline_keyboard
- then
- keyboard = json.encode(keyboard)
- end
- redis:del('lyrics:' .. callback_query.data)
- return mattata.edit_message_text(
- nil,
- nil,
- output,
- 'html',
- true,
- keyboard,
- callback_query.inline_message_id
- )
-end
-
-function lyrics:on_message(message, _, language)
- local input = mattata.input(message.text)
- if not input
- then
- local success = mattata.send_force_reply(
- message,
- language['lyrics']['3']
- )
- if success
- then
- redis:set(
- string.format(
- 'action:%s:%s',
- message.chat.id,
- success.result.message_id
- ),
- '/lyrics'
- )
- end
- return
- end
- mattata.send_chat_action(message.chat.id)
- local output, artist, track = lyrics.send_request(input)
- if not output
- then
- return mattata.send_reply(
- message,
- language['errors']['results']
- )
- end
- local keyboard = lyrics.get_keyboard(
- artist,
- track,
- language
- )
- return mattata.send_message(
- message.chat.id,
- output,
- 'html',
- true,
- false,
- nil,
- keyboard
- )
-end
-
-return lyrics
\ No newline at end of file
diff --git a/plugins/medium.lua b/plugins/medium.lua
deleted file mode 100644
index 9c74039..0000000
--- a/plugins/medium.lua
+++ /dev/null
@@ -1,35 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local medium = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local json = require('dkjson')
-
-function medium:init()
- medium.commands = mattata.commands(self.info.username):command('medium'):command('m').table
- medium.help = '/medium <query> - Returns Medium posts matching the given search query. Alias: /m.'
-end
-
-function medium.on_message(_, message, _, language)
- local input = mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, medium.help)
- end
- local jstr, res = https.request('https://medium.com/search?q=' .. url.escape(input))
- if res ~= 200 then
- return mattata.send_reply(message, language.errors.connection)
- end
- jstr = jstr:match('<!%[CDATA%[\nwindow%["obvInit"%]%(({.-}})%)\n// %]%]>')
- if not jstr then
- return mattata.send_reply(message, language.errors.results)
- end
- local jdat = json.decode(jstr)
- mattata.save_to_file(json.encode(jdat.posts[1], {indent=true}), '/home/matt/matticatebot/medium.json')
- return
-end
-
-return medium
\ No newline at end of file
diff --git a/plugins/meme.lua b/plugins/meme.lua
deleted file mode 100644
index 8b72e08..0000000
--- a/plugins/meme.lua
+++ /dev/null
@@ -1,656 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local meme = {}
-local mattata = require('mattata')
-
-function meme:init()
- meme.commands = mattata.commands(self.info.username)
- :command('meme')
- :command('memegen').table
- meme.help = '/meme <top line> | <bottom line> - Generates an image macro with the given text, on your choice of the available selection of templates. This command can only be used inline. Alias: /memegen.'
-end
-
-function meme.escape(str)
- if not str
- or type(str) ~= 'string'
- then
- return str
- end
- str = str:lower()
- return str
- :gsub('%s', '_')
- :gsub('%?', '~q')
- :gsub('%%', '~p')
- :gsub('#', '~h')
- :gsub('/', '~s')
- :gsub('"', '\'\'')
-end
-
-meme.memes = {
- 'ggg',
- 'elf',
- 'fwp',
- 'yuno',
- 'aag',
- 'badchoice',
- 'happening',
- 'scc',
- 'sad-obama',
- 'fbf',
- 'ants',
- 'ive',
- 'biw',
- 'crazypills',
- 'remembers',
- 'oag',
- 'ski',
- 'oprah',
- 'wonka',
- 'regret',
- 'fa',
- 'keanu',
- 'kermit',
- 'both',
- 'awkward',
- 'dodgson',
- 'bad',
- 'mmm',
- 'ch',
- 'live',
- 'firsttry',
- 'noidea',
- 'sad-biden',
- 'buzz',
- 'blb',
- 'fry',
- 'morpheus',
- 'cbg',
- 'xy',
- 'rollsafe',
- 'yodawg',
- 'fetch',
- 'sarcasticbear',
- 'cb',
- 'hipster',
- 'success',
- 'bd',
- 'bender',
- 'fine',
- 'bs',
- 'toohigh',
- 'mw',
- 'money',
- 'interesting',
- 'sb',
- 'doge',
- 'ermg',
- 'fmr',
- 'sparta',
- 'older',
- 'philosoraptor',
- 'awkward-awesome',
- 'awesome',
- 'chosen',
- 'alwaysonbeat',
- 'ackbar',
- 'sadfrog',
- 'sohot',
- 'imsorry',
- 'tenguy',
- 'winter',
- 'red',
- 'awesome-awkward',
- 'jw',
- 'sf',
- 'ss',
- 'patrick',
- 'center',
- 'boat',
- 'saltbae',
- 'tried',
- 'mb',
- 'hagrid',
- 'mordor',
- 'snek',
- 'sad-bush',
- 'nice',
- 'sad-clinton',
- 'afraid',
- 'stew',
- 'icanhas',
- 'away',
- 'dwight',
- 'facepalm',
- 'yallgot',
- 'jetpack',
- 'captain',
- 'inigo',
- 'iw',
- 'dsm',
- 'sad-boehner',
- 'll',
- 'joker',
- 'sohappy',
- 'officespace'
-}
-
-meme.meme_info = {
- ['tenguy'] = {
- ['width'] = 600,
- ['height'] = 544
- },
- ['afraid'] = {
- ['width'] = 600,
- ['height'] = 588
- },
- ['older'] = {
- ['width'] = 600,
- ['height'] = 255
- },
- ['aag'] = {
- ['width'] = 600,
- ['height'] = 502
- },
- ['tried'] = {
- ['width'] = 600,
- ['height'] = 600
- },
- ['biw'] = {
- ['width'] = 600,
- ['height'] = 450
- },
- ['stew'] = {
- ['width'] = 600,
- ['height'] = 448
- },
- ['blb'] = {
- ['width'] = 600,
- ['height'] = 600
- },
- ['kermit'] = {
- ['width'] = 600,
- ['height'] = 421
- },
- ['bd'] = {
- ['width'] = 600,
- ['height'] = 597
- },
- ['ch'] = {
- ['width'] = 600,
- ['height'] = 450
- },
- ['cbg'] = {
- ['width'] = 600,
- ['height'] = 368
- },
- ['wonka'] = {
- ['width'] = 600,
- ['height'] = 431
- },
- ['cb'] = {
- ['width'] = 600,
- ['height'] = 626
- },
- ['keanu'] = {
- ['width'] = 600,
- ['height'] = 597
- },
- ['dsm'] = {
- ['width'] = 600,
- ['height'] = 900
- },
- ['live'] = {
- ['width'] = 600,
- ['height'] = 405
- },
- ['ants'] = {
- ['width'] = 600,
- ['height'] = 551
- },
- ['doge'] = {
- ['width'] = 600,
- ['height'] = 600
- },
- ['alwaysonbeat'] = {
- ['width'] = 600,
- ['height'] = 337
- },
- ['ermg'] = {
- ['width'] = 600,
- ['height'] = 901
- },
- ['facepalm'] = {
- ['width'] = 600,
- ['height'] = 529
- },
- ['firsttry'] = {
- ['width'] = 600,
- ['height'] = 440
- },
- ['fwp'] = {
- ['width'] = 600,
- ['height'] = 423
- },
- ['fa'] = {
- ['width'] = 600,
- ['height'] = 600
- },
- ['fbf'] = {
- ['width'] = 600,
- ['height'] = 597
- },
- ['fmr'] = {
- ['width'] = 600,
- ['height'] = 385
- },
- ['fry'] = {
- ['width'] = 600,
- ['height'] = 449
- },
- ['ggg'] = {
- ['width'] = 600,
- ['height'] = 375
- },
- ['hipster'] = {
- ['width'] = 600,
- ['height'] = 899
- },
- ['icanhas'] = {
- ['width'] = 600,
- ['height'] = 874
- },
- ['crazypills'] = {
- ['width'] = 600,
- ['height'] = 408
- },
- ['mw'] = {
- ['width'] = 600,
- ['height'] = 441
- },
- ['noidea'] = {
- ['width'] = 600,
- ['height'] = 382
- },
- ['regret'] = {
- ['width'] = 600,
- ['height'] = 536
- },
- ['boat'] = {
- ['width'] = 600,
- ['height'] = 441
- },
- ['hagrid'] = {
- ['width'] = 600,
- ['height'] = 446
- },
- ['sohappy'] = {
- ['width'] = 600,
- ['height'] = 700
- },
- ['captain'] = {
- ['width'] = 600,
- ['height'] = 439
- },
- ['bender'] = {
- ['width'] = 600,
- ['height'] = 445
- },
- ['inigo'] = {
- ['width'] = 600,
- ['height'] = 326
- },
- ['iw'] = {
- ['width'] = 600,
- ['height'] = 600
- },
- ['ackbar'] = {
- ['width'] = 600,
- ['height'] = 777
- },
- ['happening'] = {
- ['width'] = 600,
- ['height'] = 364
- },
- ['joker'] = {
- ['width'] = 600,
- ['height'] = 554
- },
- ['ive'] = {
- ['width'] = 600,
- ['height'] = 505
- },
- ['ll'] = {
- ['width'] = 600,
- ['height'] = 399
- },
- ['away'] = {
- ['width'] = 600,
- ['height'] = 337
- },
- ['morpheus'] = {
- ['width'] = 600,
- ['height'] = 363
- },
- ['mb'] = {
- ['width'] = 600,
- ['height'] = 534
- },
- ['badchoice'] = {
- ['width'] = 600,
- ['height'] = 478
- },
- ['mmm'] = {
- ['width'] = 600,
- ['height'] = 800
- },
- ['jetpack'] = {
- ['width'] = 600,
- ['height'] = 450
- },
- ['imsorry'] = {
- ['width'] = 600,
- ['height'] = 337
- },
- ['red'] = {
- ['width'] = 600,
- ['height'] = 557
- },
- ['mordor'] = {
- ['width'] = 600,
- ['height'] = 353
- },
- ['oprah'] = {
- ['width'] = 600,
- ['height'] = 449
- },
- ['oag'] = {
- ['width'] = 600,
- ['height'] = 450
- },
- ['remembers'] = {
- ['width'] = 600,
- ['height'] = 458
- },
- ['philosoraptor'] = {
- ['width'] = 600,
- ['height'] = 600
- },
- ['jw'] = {
- ['width'] = 600,
- ['height'] = 401
- },
- ['patrick'] = {
- ['width'] = 600,
- ['height'] = 1056
- },
- ['rollsafe'] = {
- ['width'] = 600,
- ['height'] = 335
- },
- ['sad-obama'] = {
- ['width'] = 600,
- ['height'] = 600
- },
- ['sad-clinton'] = {
- ['width'] = 600,
- ['height'] = 542
- },
- ['sadfrog'] = {
- ['width'] = 600,
- ['height'] = 600
- },
- ['sad-bush'] = {
- ['width'] = 600,
- ['height'] = 455
- },
- ['sad-biden'] = {
- ['width'] = 600,
- ['height'] = 600
- },
- ['sad-boehner'] = {
- ['width'] = 600,
- ['height'] = 479
- },
- ['saltbae'] = {
- ['width'] = 600,
- ['height'] = 603
- },
- ['sarcasticbear'] = {
- ['width'] = 600,
- ['height'] = 450
- },
- ['dwight'] = {
- ['width'] = 600,
- ['height'] = 393
- },
- ['sb'] = {
- ['width'] = 600,
- ['height'] = 421
- },
- ['ss'] = {
- ['width'] = 600,
- ['height'] = 604
- },
- ['sf'] = {
- ['width'] = 600,
- ['height'] = 376
- },
- ['dodgson'] = {
- ['width'] = 600,
- ['height'] = 559
- },
- ['money'] = {
- ['width'] = 600,
- ['height'] = 337
- },
- ['snek'] = {
- ['width'] = 600,
- ['height'] = 513
- },
- ['sohot'] = {
- ['width'] = 600,
- ['height'] = 480
- },
- ['nice'] = {
- ['width'] = 600,
- ['height'] = 432
- },
- ['awesome-awkward'] = {
- ['width'] = 600,
- ['height'] = 601
- },
- ['awesome'] = {
- ['width'] = 600,
- ['height'] = 600
- },
- ['awkward-awesome'] = {
- ['width'] = 600,
- ['height'] = 600
- },
- ['awkward'] = {
- ['width'] = 600,
- ['height'] = 600
- },
- ['fetch'] = {
- ['width'] = 600,
- ['height'] = 450
- },
- ['success'] = {
- ['width'] = 600,
- ['height'] = 578
- },
- ['scc'] = {
- ['width'] = 600,
- ['height'] = 326
- },
- ['ski'] = {
- ['width'] = 600,
- ['height'] = 404
- },
- ['officespace'] = {
- ['width'] = 600,
- ['height'] = 501
- },
- ['interesting'] = {
- ['width'] = 600,
- ['height'] = 759
- },
- ['toohigh'] = {
- ['width'] = 600,
- ['height'] = 408
- },
- ['bs'] = {
- ['width'] = 600,
- ['height'] = 600
- },
- ['fine'] = {
- ['width'] = 600,
- ['height'] = 582
- },
- ['sparta'] = {
- ['width'] = 600,
- ['height'] = 316
- },
- ['center'] = {
- ['width'] = 600,
- ['height'] = 370
- },
- ['both'] = {
- ['width'] = 600,
- ['height'] = 600
- },
- ['winter'] = {
- ['width'] = 600,
- ['height'] = 460
- },
- ['xy'] = {
- ['width'] = 600,
- ['height'] = 455
- },
- ['buzz'] = {
- ['width'] = 600,
- ['height'] = 455
- },
- ['yodawg'] = {
- ['width'] = 600,
- ['height'] = 399
- },
- ['yuno'] = {
- ['width'] = 600,
- ['height'] = 450
- },
- ['yallgot'] = {
- ['width'] = 600,
- ['height'] = 470
- },
- ['bad'] = {
- ['width'] = 600,
- ['height'] = 450
- },
- ['elf'] = {
- ['width'] = 600,
- ['height'] = 369
- },
- ['chosen'] = {
- ['width'] = 600,
- ['height'] = 342
- }
-}
-
-function meme.get_memes(offset, first_line, last_line)
- local first = (
- offset
- and type(offset) == 'number'
- )
- and offset + 1
- or 1
- local last = first + 49
- if first >= last
- then
- return
- elseif last > #meme.memes
- then
- last = #meme.memes
- end
- local output = {}
- local id = first
- for i = first, last
- do
- local image = 'https://memegen.link/' .. meme.memes[i] .. '/' .. meme.escape(first_line)
- if last_line
- then
- image = image .. '/' .. meme.escape(last_line)
- end
- image = image .. '.jpg?font=impact'
- table.insert(
- output,
- mattata.inline_result()
- :type('photo')
- :id(
- tostring(id)
- )
- :photo_url(image)
- :thumb_url(image)
- :photo_width(
- tostring(meme.meme_info[meme.memes[i]]['width'])
- )
- :photo_height(
- tostring(meme.meme_info[meme.memes[i]]['height'])
- )
- )
- id = id + 1
- end
- if last == #meme.memes
- then
- last = false
- end
- return output, last
-end
-
-function meme:on_inline_query(inline_query)
- local input = mattata.input(inline_query.query)
- if not input
- then
- return false
- end
- input = input:gsub('\n', ' | ')
- local first_line, last_line = input, false
- if input:match('^.- | .-$')
- then
- first_line, last_line = input:match('^(.-) | (.-)$')
- end
- first_line = first_line:gsub(' | ', ' ')
- if last_line
- then
- last_line = last_line:gsub(' | ', ' ')
- end
- local offset = inline_query.offset
- and tonumber(inline_query.offset)
- or 0
- local output, next_offset = meme.get_memes(
- offset,
- first_line,
- last_line
- )
- return mattata.answer_inline_query(
- inline_query.id,
- output,
- 0,
- false,
- next_offset
- and tostring(next_offset)
- or nil
- )
-end
-
-function meme:on_message(message)
- return mattata.send_message(
- message.chat.id,
- 'This command can only be used inline!'
- )
-end
-
-return meme
\ No newline at end of file
diff --git a/plugins/meta.lua b/plugins/meta.lua
deleted file mode 100644
index 4688564..0000000
--- a/plugins/meta.lua
+++ /dev/null
@@ -1,34 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local meta = {}
-local mattata = require('mattata')
-
-function meta:init()
- meta.commands = mattata.commands(self.info.username):command('meta').table
- meta.help = '/meta - Instructs users not to ask to ask, but just to ask.'
-end
-
-function meta.on_message(_, message)
- local send_as_reply = false
- local original_message = message.message_id
- if message.reply then
- message.message_id = message.reply.message_id
- send_as_reply = true
- end
- local method = send_as_reply == true and mattata.send_reply or mattata.send_message
- mattata.delete_message(message.chat.id, original_message)
- local output = [[Please don't ask meta-questions, like:
-
-`"Any user of $x here?"`
-`"Anyone used technology $y?"`
-`"Hello I need help on $z"`
-
-Just ask a *direct question* about your problem, and the probability that someone will help is pretty high.
-[Read more.](http://catb.org/~esr/faqs/smart-questions.html)]]
- return method(message, output, true)
-end
-
-return meta
\ No newline at end of file
diff --git a/plugins/minecraft.lua b/plugins/minecraft.lua
deleted file mode 100644
index b034b93..0000000
--- a/plugins/minecraft.lua
+++ /dev/null
@@ -1,321 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local minecraft = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local json = require('dkjson')
-local redis = require('libs.redis')
-
-function minecraft:init()
- minecraft.commands = mattata.commands(self.info.username)
- :command('minecraft')
- :command('mc').table
- minecraft.help = '/minecraft <Minecraft username> - Sends information about the given Minecraft user. Alias: /mc.'
-end
-
-function minecraft.get_uuid(username)
- local jstr, res = https.request('https://api.mojang.com/users/profiles/minecraft/' .. url.escape(username))
- if res ~= 200
- then
- return false
- end
- local jdat = json.decode(jstr)
- if not jdat.id
- then
- return false
- end
- return jdat.id
-end
-
-function minecraft.username_change_date(date)
- local format_date = io.popen('date -d @' .. date):read('*all')
- format_date = format_date
- :gsub(' ', ' 0')
- :gsub('\n', '')
- local month, day, time, year = format_date:match('^%a+ (%a+) (%d+) (%d%d:%d%d):%d%d %a+ (%d%d%d%d)$')
- if day == 1
- or day == 21
- or day == 31
- then
- day = day .. 'st'
- elseif day == 2
- or day == 22
- then
- day = day .. 'nd'
- elseif day == 3
- or day == 23
- then
- day = day .. 'rd'
- else
- day = day .. 'th'
- end
- return ' <pre>[' .. day:gsub('^0', '') .. ' ' .. month .. ' ' .. year .. ', ' .. time .. ']</pre>'
-end
-
-function minecraft.get_history_page(username_history, username_count, page)
- local page_begins_at = tonumber(page) * 5 - 4
- local page_ends_at = tonumber(page_begins_at) + 4
- if tonumber(page_ends_at) > tonumber(username_count)
- then
- page_ends_at = tonumber(username_count)
- end
- local page_usernames = {}
- for i = tonumber(page_begins_at), tonumber(page_ends_at)
- do
- table.insert(
- page_usernames,
- username_history[i]
- )
- end
- return table.concat(
- page_usernames,
- '\n'
- )
-end
-
-function minecraft.get_username_history(username, language)
- if not minecraft.get_uuid(username)
- then
- return false
- end
- local uuid = minecraft.get_uuid(username)
- local jstr, res = https.request('https://api.mojang.com/user/profiles/' .. url.escape(uuid) .. '/names')
- if res ~= 200
- then
- return false
- end
- local jdat = json.decode(jstr)
- local names = {}
- for n in pairs(jdat)
- do
- local result = jdat[n].name
- if jdat[n].changedToAt
- and tonumber(jdat[n].changedToAt) ~= nil
- then
- result = result .. minecraft.username_change_date(
- math.floor(
- tonumber(jdat[n].changedToAt) / 1000
- )
- )
- end
- table.insert(
- names,
- '• ' .. result
- )
- end
- local output = language['minecraft']['1']
- if #jdat ~= 1
- then
- output = language['minecraft']['2']
- end
- return string.format(
- output,
- username,
- #jdat
- ) .. ':</b>\n' .. table.concat(
- names,
- '\n'
- ), #names, names
-end
-
-function minecraft.get_avatar(username)
- return '<a href="https://mcapi.ca/avatar/' .. url.escape(username) .. '/128">' .. mattata.escape_html(username) .. '</a>'
-end
-
-function minecraft:on_callback_query(callback_query, message, configuration, language)
- if callback_query.data:match('^uuid%:.-$')
- then
- local input = callback_query.data:match('^uuid%:(.-)$')
- local output = minecraft.get_uuid(input)
- if not output
- then
- output = language['errors']['results']
- end
- return mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- output,
- nil,
- true,
- mattata.inline_keyboard():row(
- mattata.row():callback_data_button(
- language['minecraft']['5'],
- 'minecraft:back:' .. input
- )
- )
- )
- elseif callback_query.data:match('^avatar%:.-$')
- then
- local input = callback_query.data:match('^avatar%:(.-)$')
- return mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- minecraft.get_avatar(input),
- 'html',
- false,
- mattata.inline_keyboard():row(
- mattata.row():callback_data_button(
- language['minecraft']['5'],
- 'minecraft:back:' .. input
- )
- )
- )
- elseif callback_query.data:match('^history%:.-%:%d*$')
- then
- local input = callback_query.data:match('^history%:(.-)%:%d*$')
- local output, amount, usernames = minecraft.get_username_history(
- input,
- language
- )
- local keyboard = {}
- keyboard.inline_keyboard = {}
- if not output
- then
- output = language['errors']['results']
- else
- local new_page = callback_query.data:match('^history%:.-%:(%d*)$')
- local page_count = math.floor(tonumber(amount) / 5) + 1
- if tonumber(new_page) > tonumber(page_count)
- then
- new_page = 1
- elseif tonumber(new_page) < 1
- then
- new_page = tonumber(page_count)
- end
- table.insert(
- keyboard.inline_keyboard,
- {
- {
- ['text'] = mattata.symbols.back .. ' ' .. language['minecraft']['3'],
- ['callback_data'] = 'minecraft:history:' .. input .. ':' .. math.floor(tonumber(new_page) - 1)
- },
- {
- ['text'] = new_page .. '/' .. page_count,
- ['callback_data'] = 'minecraft:pages:' .. new_page .. ':' .. page_count
- },
- {
- ['text'] = language['minecraft']['4'] .. ' ' .. mattata.symbols.next,
- ['callback_data'] = 'minecraft:history:' .. input .. ':' .. math.floor(tonumber(new_page) + 1)
- }
- }
- )
- output = minecraft.get_history_page(
- usernames,
- amount,
- new_page
- )
- end
- table.insert(
- keyboard.inline_keyboard,
- {
- {
- ['text'] = language['minecraft']['5'],
- ['callback_data'] = 'minecraft:back:' .. input
- }
- }
- )
- return mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- output,
- 'html',
- true,
- json.encode(keyboard)
- )
- elseif callback_query.data:match('^back%:.-$')
- then
- local input = callback_query.data:match('^back%:(.-)$')
- local keyboard = {}
- keyboard.inline_keyboard = {
- {
- {
- ['text'] = language['minecraft']['6'],
- ['callback_data'] = 'minecraft:uuid:' .. input
- },
- {
- ['text'] = language['minecraft']['7'],
- ['callback_data'] = 'minecraft:avatar:' .. input
- }
- },
- {
- {
- ['text'] = language['minecraft']['8'],
- ['callback_data'] = 'minecraft:history:' .. input .. ':1'
- }
- }
- }
- return mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- language['minecraft']['9'],
- nil,
- true,
- json.encode(keyboard)
- )
- end
-end
-
-function minecraft:on_message(message, configuration, language)
- local input = mattata.input(message.text)
- if not input
- then
- local success = mattata.send_force_reply(
- message,
- language['minecraft']['10']
- )
- if success
- then
- redis:set(
- string.format(
- 'action:%s:%s',
- message.chat.id,
- success.result.message_id
- ),
- '/minecraft'
- )
- end
- return
- elseif input:len() > 16
- or input:len() < 3
- then
- return mattata.send_reply(
- message,
- language['minecraft']['11']
- )
- end
- return mattata.send_message(
- message.chat.id,
- language['minecraft']['9'],
- nil,
- true,
- false,
- message.message_id,
- mattata.inline_keyboard()
- :row(
- mattata.row()
- :callback_data_button(
- language['minecraft']['6'],
- 'minecraft:uuid:' .. input
- )
- :callback_data_button(
- language['minecraft']['7'],
- 'minecraft:avatar:' .. input
- )
- )
- :row(
- mattata.row():callback_data_button(
- language['minecraft']['8'],
- string.format(
- 'minecraft:history:%s:1',
- input
- )
- )
- )
- )
-end
-
-return minecraft
\ No newline at end of file
diff --git a/plugins/mock.lua b/plugins/mock.lua
deleted file mode 100644
index 16fd614..0000000
--- a/plugins/mock.lua
+++ /dev/null
@@ -1,49 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local mock = {}
-local mattata = require('mattata')
-
-function mock:init()
- mock.commands = mattata.commands(self.info.username):command('mock').table
- mock.help = '/mock [text] - Repeats the replied-to message in a moCkINg style. Alternatively, input can be given - but this won\'t override a reply.'
-end
-
-function mock.change_case(str)
- local formatted = ''
- for i = 1, #str do
- local byte = str:sub(i, i)
- if byte:match('%a') then
- if i % 2 == 1 then
- formatted = formatted .. byte:upper()
- else
- formatted = formatted .. byte:lower()
- end
- else -- Support non-alphabetic characters.
- formatted = formatted .. byte
- end
- end
- return formatted
-end
-
-function mock.on_message(_, message)
- local input = message.reply and message.reply.text or mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, mock.help)
- end
- local chars = {}
- for v in input:gmatch('.') do
- chars[#chars + 1] = v
- end
- local output = mock.change_case(input)
- if message.reply then
- mattata.delete_message(message.chat.id, message.message_id)
- message.message_id = message.reply.message_id
- return mattata.send_reply(message, output)
- end
- return mattata.send_message(message.chat.id, output)
-end
-
-return mock
\ No newline at end of file
diff --git a/plugins/movies.lua b/plugins/movies.lua
deleted file mode 100644
index 086a700..0000000
--- a/plugins/movies.lua
+++ /dev/null
@@ -1,58 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local movies = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local http = require('socket.http')
-local url = require('socket.url')
-local json = require('dkjson')
-
-function movies:init(configuration)
- movies.commands = mattata.commands(self.info.username):command('movies?'):command('imdb'):command('films?').table
- movies.help = '/movie <query> - Searches IMDb for the given search query and returns the most relevant result(s). Aliases: /imdb, /film.'
- movies.key = configuration.keys.movies
- movies.url = string.format('http://www.omdbapi.com/?apikey=%s&page=1&s=', movies.key.omdb)
-end
-
-function movies.on_message(_, message, _, language)
- local input = mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, movies.help)
- end
- local jstr_search, res_search = http.request(movies.url .. url.escape(input))
- if res_search ~= 200 then
- return mattata.send_reply(message, language.errors.connection)
- end
- local jdat_search = json.decode(jstr_search)
- if jdat_search.Response ~= 'True' then
- return mattata.send_reply(message, language.errors.results)
- end
- local jstr, res = http.request('http://www.omdbapi.com/?i=' .. jdat_search.Search[1].imdbID .. '&r=json&tomatoes=true&apikey=' .. movies.key.omdb)
- if res ~= 200 then
- return false
- end
- local jdat = json.decode(jstr)
- if jdat.Response ~= 'True' then
- return false
- end
- local poster
- poster, res = https.request('https://www.myapifilms.com/imdb/idIMDB?idIMDB=' .. jdat.imdbID .. '&token=' .. movies.key.poster)
- if res == 200 then
- poster = json.decode(poster)
- if not poster.error and poster.data.movies[1].urlPoster then
- poster = poster.data.movies[1].urlPoster:gsub('(U%a%d*)(_%a%a%d,%d,%d*)(,%d*)', '%10%20%30')
- end
- else -- We'll set it to a placeholder image I've already got stored on Telegram's servers, we can always update this.
- poster = 'AgACAgQAAx0CVClmWQACHGNe-VQxIvsfNMOn5jJceOVhfc4llQACpLAxG0qiyFNNvPCVaco5ZKoWdiNdAAMBAAMCAAN5AAOqagEAARoE'
- end
- local output = string.format('<a href="https://imdb.com/title/%s">%s</a> (%s)\n%s/10 | %s | %s\n\n<em>%s</em>', jdat_search.Search[1].imdbID, mattata.escape_html(jdat.Title), jdat.Year, jdat.imdbRating, jdat.Runtime, jdat.Genre, mattata.escape_html(jdat.Plot))
- if not poster or not output then
- return mattata.send_reply(message, language.errors.results)
- end
- return mattata.send_photo(message.chat.id, poster, output, 'html', false)
-end
-
-return movies
\ No newline at end of file
diff --git a/plugins/myspotify.lua b/plugins/myspotify.lua
deleted file mode 100644
index 7a7631f..0000000
--- a/plugins/myspotify.lua
+++ /dev/null
@@ -1,788 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local myspotify = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local json = require('dkjson')
-local redis = require('libs.redis')
-local ltn12 = require('ltn12')
-
-function myspotify:init(configuration)
- myspotify.commands = mattata.commands(self.info.username):command('myspotify').table
- myspotify.help = '/myspotify - View information about your Spotify account.'
- myspotify.client_id = configuration.keys.spotify.client_id
- myspotify.client_secret = configuration.keys.spotify.client_secret
-end
-
-function myspotify.on_new_message(_, message, configuration)
- if redis:get('spotify:' .. message.from.id .. ':refresh_token') and not redis:get('spotify:' .. message.from.id .. ':access_token') then
- local success = myspotify.reauthorise_account(message.from.id, configuration)
- if success then
- redis:set('spotify:' .. message.from.id .. ':access_token', success.access_token)
- redis:expire('spotify:' .. message.from.id .. ':access_token', 3600)
- end
- end
-end
-
-function myspotify.get_keyboard(user_id, language, force_playing_state)
- local is_playing = myspotify.get_current_state(user_id, true)
- if force_playing_state then
- is_playing = true
- end
- return mattata.inline_keyboard():row(
- mattata.row()
- :callback_data_button(language['myspotify']['1'], 'myspotify:profile:' .. user_id)
- :callback_data_button(language['myspotify']['2'], 'myspotify:following:' .. user_id)
- :callback_data_button(language['myspotify']['3'], 'myspotify:recentlyplayed:' .. user_id)
- ):row(
- mattata.row():callback_data_button(
- language['myspotify']['4'],
- 'myspotify:currentlyplaying:' .. user_id
- ):callback_data_button(
- language['myspotify']['5'],
- 'myspotify:toptracks:' .. user_id
- )
- ):row(
- mattata.row():callback_data_button(
- language['myspotify']['6'],
- 'myspotify:topartists:' .. user_id
- ):callback_data_button(
- 'Playlists',
- 'myspotify:playlists:' .. user_id
- )
- ):row(
- mattata.row():callback_data_button(
- myspotify.get_current_track(user_id),
- 'myspotify:currentlyplaying:' .. user_id
- )
- ):row(
- mattata.row():callback_data_button(
- utf8.char(9198),
- 'myspotify:previous:' .. user_id
- ):callback_data_button(
- is_playing and utf8.char(9208) or utf8.char(9654),
- 'myspotify:' .. (is_playing and 'pause:' or 'play:') .. user_id
- ):callback_data_button(
- utf8.char(9197),
- 'myspotify:next:' .. user_id
- ):callback_data_button(
- utf8.char(128256),
- 'myspotify:shuffle:' .. user_id
- )
- ):row(
- mattata.row():switch_inline_query_current_chat_button(
- 'Use Inline Mode',
- '/myspotify'
- ):callback_data_button(
- 'Lyrics',
- 'myspotify:lyrics:' .. user_id
- )
- )
-end
-
-function myspotify.reauthorise_account(user_id)
- local refresh_token = redis:get('spotify:' .. user_id .. ':refresh_token')
- if not refresh_token then
- return false
- end
- local query = string.format('grant_type=refresh_token&refresh_token=%s&client_id=%s&client_secret=%s', url.escape(refresh_token), myspotify.client_id, myspotify.client_secret)
- local response = {}
- local _, res = https.request({
- ['url'] = 'https://accounts.spotify.com/api/token',
- ['method'] = 'POST',
- ['headers'] = {
- ['Content-Type'] = 'application/x-www-form-urlencoded',
- ['Content-Length'] = query:len()
- },
- ['source'] = ltn12.source.string(query),
- ['sink'] = ltn12.sink.table(response)
- })
- local jdat = json.decode(table.concat(response))
- if res ~= 200 or not jdat or jdat.error then
- return false
- end
- return jdat
-end
-
-function myspotify.get_top_artists(user_id, language, only_count, only_artists)
- if not user_id or tonumber(user_id) == nil then
- return false
- end
- local response = {}
- local _, res = https.request({
- ['url'] = 'https://api.spotify.com/v1/me/top/artists',
- ['method'] = 'GET',
- ['headers'] = {
- ['Authorization'] = 'Bearer ' .. redis:get('spotify:' .. user_id .. ':access_token')
- },
- ['sink'] = ltn12.sink.table(response)
- })
- if res ~= 200 then
- return false
- end
- local jdat = json.decode(table.concat(response))
- if not jdat.total or not jdat.items or tonumber(jdat.total) == nil or tonumber(jdat.total) < 1 then
- return language['myspotify']['7']
- elseif only_count then
- return tostring(jdat.total)
- end
- local output = {}
- if not only_artists then
- table.insert(output, '<b>' .. language['myspotify']['8'] .. '</b>')
- end
- for i = 1, tonumber(jdat.total) do
- if jdat.items[i] then
- if jdat.items[i].external_urls then
- jdat.items[i].spotify = jdat.items[i].external_urls.spotify
- end
- local link = mattata.create_link(jdat.items[i].name, jdat.items[i].spotify, 'html')
- table.insert(output, mattata.symbols.bullet .. ' ' .. link)
- end
- end
- return table.concat(output, '\n')
-end
-
-function myspotify.get_top_tracks(user_id, language, only_count, only_tracks)
- if not user_id or tonumber(user_id) == nil then
- return false
- end
- local response = {}
- local _, res = https.request({
- ['url'] = 'https://api.spotify.com/v1/me/top/tracks',
- ['method'] = 'GET',
- ['headers'] = {
- ['Authorization'] = 'Bearer ' .. redis:get('spotify:' .. user_id .. ':access_token')
- },
- ['sink'] = ltn12.sink.table(response)
- })
- if res ~= 200 then
- return false
- end
- local jdat = json.decode(table.concat(response))
- if not jdat.total or tonumber(jdat.total) == nil or tonumber(jdat.total) < 1 then
- return language['myspotify']['9']
- elseif only_count then
- return tostring(jdat.total)
- end
- local output = {}
- if not only_tracks then
- table.insert(output, '<b>' .. language['myspotify']['10'] .. '</b>')
- end
- for _, v in pairs(jdat.items) do
- local artists = {}
- for n, artist in pairs(v.artists) do
- local separator = ' — '
- if #v.artists > 1 then
- separator = '\n ├ '
- if n == #v.artists then
- separator = '\n └ '
- end
- end
- if artist.external_urls.spotify then
- artist.spotify = artist.external_urls.spotify
- end
- local link = mattata.create_link(artist.name, artist.spotify, 'html')
- table.insert(artists, separator .. link)
- end
- if v.external_urls then
- v.spotify = v.external_urls.spotify
- end
- local link = mattata.create_link(v.name, v.spotify, 'html')
- table.insert(output, mattata.symbols.bullet .. ' ' .. link .. table.concat(artists))
- end
- return table.concat(output, '\n')
-end
-
-function myspotify.get_following(user_id, language, only_count, only_followers)
- if not user_id or tonumber(user_id) == nil then
- return false
- end
- local response = {}
- local _, res = https.request({
- ['url'] = 'https://api.spotify.com/v1/me/following?type=artist',
- ['method'] = 'GET',
- ['headers'] = {
- ['Authorization'] = 'Bearer ' .. redis:get('spotify:' .. user_id .. ':access_token')
- },
- ['sink'] = ltn12.sink.table(response)
- })
- if res ~= 200 then
- return false
- end
- local jdat = json.decode(table.concat(response))
- if not jdat.artists or tonumber(jdat.artists.total) == nil or tonumber(jdat.artists.total) < 1 then
- return language['myspotify']['11']
- elseif only_count then
- return tostring(jdat.artists.total)
- end
- local output = {}
- if not only_followers then
- table.insert(output, '<b>' .. language['myspotify']['12'] .. '</b>')
- end
- for _, v in pairs(jdat.artists.items) do
- if v.external_urls then
- v.spotify = v.external_urls.spotify
- end
- local link = mattata.create_link(v.name, v.spotify, 'html')
- local total = string.format(' [%s]', v.followers.total or 0)
- table.insert(output, mattata.symbols.bullet .. ' ' .. link .. total)
- end
- return table.concat(output, '\n')
-end
-
-function myspotify.get_recently_played(user_id, language, only_count)
- if not user_id or tonumber(user_id) == nil then
- return false
- end
- local response = {}
- local _, res = https.request({
- ['url'] = 'https://api.spotify.com/v1/me/player/recently-played',
- ['method'] = 'GET',
- ['headers'] = {
- ['Authorization'] = 'Bearer ' .. redis:get('spotify:' .. user_id .. ':access_token')
- },
- ['sink'] = ltn12.sink.table(response)
- })
- if res ~= 200 then
- return false
- end
- local jdat = json.decode(table.concat(response))
- if not jdat.items or #jdat.items < 1 then
- return language['myspotify']['13']
- elseif only_count then
- return tostring(#jdat.items)
- end
- local artists = {}
- for _, v in pairs(jdat.items[1].track.artists) do
- if v.external_urls.spotify then
- v.spotify = v.external_urls.spotify
- end
- local link = mattata.create_link(v.name, v.spotify)
- table.insert(artists, link)
- end
- if jdat.items[1].track.external_urls.spotify then
- jdat.items[1].track.spotify = jdat.items[1].track.external_urls.spotify
- end
- local year, month, day, hours, minutes = jdat.items[1].played_at:match('^(%d%d%d%d)%-(%d%d)%-(%d%d)T(%d%d):(%d%d):%d%d%.%d%d%dZ$')
- return string.format(language['myspotify']['14'], utf8.char(127925),
- mattata.create_link(
- jdat.items[1].track.name,
- jdat.items[1].track.spotify
- ),
- utf8.char(127897),
- #artists == 0
- and '—'
- or table.concat(
- artists,
- ', '
- ),
- utf8.char(128338),
- tostring(hours),
- tostring(minutes),
- tostring(day),
- tostring(month),
- tostring(year)
- )
-end
-
-function myspotify.get_currently_playing(user_id, language)
- if not user_id
- or tonumber(user_id) == nil
- or not redis:get('spotify:' .. user_id .. ':access_token')
- then
- return false
- end
- local response = {}
- local _, res = https.request(
- {
- ['url'] = 'https://api.spotify.com/v1/me/player/currently-playing',
- ['method'] = 'GET',
- ['headers'] = {
- ['Authorization'] = 'Bearer ' .. redis:get('spotify:' .. user_id .. ':access_token')
- },
- ['sink'] = ltn12.sink.table(response)
- }
- )
- if res ~= 200
- then
- if res == 202
- then
- return language['myspotify']['15']
- end
- return false
- end
- local jdat = json.decode(
- table.concat(response)
- )
- if not jdat
- or not jdat.is_playing
- or tostring(jdat.is_playing) ~= 'true'
- then
- return language['myspotify']['16']
- end
- local artists = {}
- for _, v in pairs(jdat.item.artists)
- do
- if v.external_urls.spotify
- then
- v.spotify = v.external_urls.spotify
- end
- table.insert(
- artists,
- mattata.create_link(
- v.name,
- v.spotify
- )
- )
- end
- if jdat.item.external_urls.spotify
- then
- jdat.item.spotify = jdat.item.external_urls.spotify
- end
- return '<b>' .. language['myspotify']['17'] .. '</b>\n' .. mattata.create_link(
- '💽',
- jdat.item.album.images[1].url
- ) .. ' ' .. mattata.create_link(
- jdat.item.name,
- jdat.item.spotify
- ) .. '\n🎙 ' .. table.concat(
- artists,
- ', '
- )
-end
-
-function myspotify.get_devices(user_id, language)
- if not user_id or tonumber(user_id) == nil or not redis:get('spotify:' .. user_id .. ':access_token') then
- return false
- end
- local response = {}
- local _, res = https.request({
- ['url'] = 'https://api.spotify.com/v1/me/player/devices',
- ['method'] = 'GET',
- ['headers'] = {
- ['Authorization'] = 'Bearer ' .. redis:get('spotify:' .. user_id .. ':access_token')
- },
- ['sink'] = ltn12.sink.table(response)
- })
- if res ~= 200 then
- if res == 202 then
- return language['myspotify']['15']
- end
- return false
- end
- local jdat = json.decode(table.concat(response))
- if not jdat or not jdat.devices or not jdat.devices[1] then
- return 'No devices were found.'
- end
- local devices = {}
- for _, v in pairs(jdat.devices) do
- local device = string.format('%s %s [%s]', mattata.symbols.bullet, v.name, v.type)
- table.insert(devices, device)
- end
- return table.concat(devices, '\n')
-end
-
-function myspotify.get_playlists(user_id, language, only_count, only_playlists)
- if not user_id or tonumber(user_id) == nil then
- return false
- end
- local response = {}
- local _, res = https.request({
- ['url'] = 'https://api.spotify.com/v1/me/playlists',
- ['method'] = 'GET',
- ['headers'] = {
- ['Authorization'] = 'Bearer ' .. redis:get('spotify:' .. user_id .. ':access_token')
- },
- ['sink'] = ltn12.sink.table(response)
- })
- if res ~= 200 then
- return false
- end
- local jdat = json.decode(table.concat(response))
- if not jdat or not jdat.items or not jdat.items[1] then
- return 'You don\'t appear to have any playlists.'
- elseif only_count then
- return tostring(jdat.total)
- end
- local output = {}
- if not only_playlists then
- table.insert(output, '<b>Your Playlists</b>')
- end
- for _, v in pairs(jdat.items) do
- if v.external_urls then
- v.spotify = v.external_urls.spotify
- end
- local link = mattata.create_link(v.name, v.spotify, 'html')
- local tracks = string.format(' [%s tracks]', v.tracks.total or 0)
- table.insert(output, mattata.symbols.bullet .. ' ' .. link .. tracks)
- end
- return table.concat(output, '\n')
-end
-
-function myspotify.get_user_info(user_id, language)
- if not user_id or not redis:get('spotify:' .. user_id .. ':access_token') then
- return false
- end
- local response = {}
- local _, res = https.request({
- ['url'] = 'https://api.spotify.com/v1/me',
- ['method'] = 'GET',
- ['headers'] = {
- ['Authorization'] = 'Bearer ' .. redis:get('spotify:' .. user_id .. ':access_token')
- },
- ['sink'] = ltn12.sink.table(response)
- })
- if res ~= 200 then
- return false
- end
- local jdat = json.decode(table.concat(response))
- if not jdat or jdat.error then
- return false
- end
- local name = jdat.display_name or jdat.id
- name = mattata.create_link(name, jdat.external_urls.spotify, 'html')
- local followers = mattata.create_link(jdat.followers.total, jdat.followers.href, 'html')
- if jdat.images and jdat.images[#jdat.images] then
- jdat.images = jdat.images[#jdat.images].url
- end
- local product = jdat.product:gsub('^%l', string.upper)
- local devices = myspotify.get_devices(user_id, language)
- local avatar = mattata.create_link(utf8.char(128100), jdat.images)
- return string.format('%s %s [%s]\nSpotify %s user\n\n<b>Devices:</b>\n%s', avatar, name, followers, product, devices)
-end
-
-function myspotify.get_current_state(user_id, is_playing)
- local response = {}
- local _, res = https.request({
- ['url'] = 'https://api.spotify.com/v1/me/player',
- ['method'] = 'GET',
- ['headers'] = {
- ['Authorization'] = 'Bearer ' .. redis:get('spotify:' .. user_id .. ':access_token')
- },
- ['sink'] = ltn12.sink.table(response)
- })
- if res ~= 200 then
- return false
- end
- local jdat = json.decode(table.concat(response))
- if not jdat or jdat.error then
- return false
- elseif is_playing then
- is_playing = tostring(jdat.is_playing)
- if is_playing == 'true' then
- return true
- end
- return false
- end
- return jdat
-end
-
-function myspotify.previous_track(user_id)
- local _, res = https.request({
- ['url'] = 'https://api.spotify.com/v1/me/player/previous',
- ['method'] = 'POST',
- ['headers'] = {
- ['Content-Length'] = 0,
- ['Authorization'] = 'Bearer ' .. redis:get('spotify:' .. user_id .. ':access_token')
- }
- })
- if res == 200 or res == 204 then
- return 'Playing previous track...'
- elseif res == 403 then
- return 'You are not a premium user!'
- elseif res == 202 then
- return 'I could not find any devices.'
- end
- return false
-end
-
-function myspotify.next_track(user_id)
- if not user_id or not redis:get('spotify:' .. user_id .. ':access_token') then
- return false
- end
- local _, res = https.request({
- ['url'] = 'https://api.spotify.com/v1/me/player/next',
- ['method'] = 'POST',
- ['headers'] = {
- ['Content-Length'] = 0,
- ['Authorization'] = 'Bearer ' .. redis:get('spotify:' .. user_id .. ':access_token')
- }
- })
- if res == 200 or res == 204 then
- return 'Playing next track...'
- elseif res == 403 then
- return 'You are not a premium user!'
- elseif res == 202 then
- return 'I could not find any devices.'
- end
- return false
-end
-
-function myspotify.play(user_id)
- local _, res = https.request({
- ['url'] = 'https://api.spotify.com/v1/me/player/play',
- ['method'] = 'PUT',
- ['headers'] = {
- ['Content-Length'] = 0,
- ['Authorization'] = 'Bearer ' .. redis:get('spotify:' .. user_id .. ':access_token')
- }
- })
- if res == 200 or res == 204 then
- return 'Resuming track...'
- elseif res == 403 then
- return 'You are not a premium user!'
- elseif res == 202 then
- return 'Your device is temporarily unavailable...'
- elseif res == 404 then
- return 'No devices were found!'
- end
- return false
-end
-
-function myspotify.pause(user_id)
- local _, res = https.request({
- ['url'] = 'https://api.spotify.com/v1/me/player/pause',
- ['method'] = 'PUT',
- ['headers'] = {
- ['Content-Length'] = 0,
- ['Authorization'] = 'Bearer ' .. redis:get('spotify:' .. user_id .. ':access_token')
- }
- })
- if res == 200 or res == 204 then
- return 'Pausing track...'
- elseif res == 403 then
- return 'You are not a premium user!'
- elseif res == 202 then
- return 'Your device is temporarily unavailable...'
- elseif res == 404 then
- return 'No devices were found!'
- end
- return false
-end
-
-function myspotify.get_current_artist(user_id)
- local current = myspotify.get_current_state(user_id)
- if not current or not current.item or not current.item.artists or not current.is_playing then
- return false
- end
- return current.item.artists[1].name
-end
-
-function myspotify.get_current_track(user_id, language, only_track)
- local current = myspotify.get_current_state(user_id)
- if not current or not current.item or tostring(current.is_playing) == 'false' then
- if only_track then
- return '—'
- end
- return 'Now playing: —'
- end
- if only_track then
- return current.item.name
- end
- local artist = myspotify.get_current_artist(user_id)
- if artist then
- current.item.name = artist .. ' – ' .. current.item.name
- end
- return current.item.name
-end
-
-function myspotify.get_username(user_id)
- local response = {}
- local _, res = https.request({
- ['url'] = 'https://api.spotify.com/v1/me',
- ['method'] = 'GET',
- ['headers'] = {
- ['Authorization'] = 'Bearer ' .. redis:get('spotify:' .. user_id .. ':access_token')
- },
- ['sink'] = ltn12.sink.table(response)
- })
- if res ~= 200 then
- return false
- end
- local jdat = json.decode(table.concat(response))
- if not jdat or jdat.error then
- return false
- end
- return jdat.id
-end
-
-function myspotify.shuffle(user_id)
- local _, res = https.request({
- ['url'] = 'https://api.spotify.com/v1/me/player/shuffle?state=true',
- ['method'] = 'PUT',
- ['headers'] = {
- ['Content-Length'] = 0,
- ['Authorization'] = 'Bearer ' .. redis:get('spotify:' .. user_id .. ':access_token')
- }
- })
- if res == 200 or res == 204 then
- return 'Shuffling your music...'
- elseif res == 403 then
- return 'You are not a premium user!'
- elseif res == 202 then
- return 'Your device is temporarily unavailable...'
- elseif res == 404 then
- return 'No devices were found!'
- end
- return false
-end
-
-function myspotify.set_volume(user_id, volume)
- if not volume or tonumber(volume) == nil or tonumber(volume) < 0 or tonumber(volume) > 100 then
- return 'That\'s not a valid volume. Please specify a number between 0 and 100.'
- end
- local _, res = https.request({
- ['url'] = 'https://api.spotify.com/v1/me/player/volume?volume_percent=' .. volume,
- ['method'] = 'PUT',
- ['headers'] = {
- ['Content-Length'] = 0,
- ['Authorization'] = 'Bearer ' .. redis:get('spotify:' .. user_id .. ':access_token')
- }
- })
- if res == 200 or res == 204 then
- return 'The volume has been set to ' .. volume .. '%!'
- elseif res == 403 then
- return 'You are not a premium user!'
- elseif res == 202 then
- return 'Your device is temporarily unavailable...'
- elseif res == 404 then
- return 'No devices were found!'
- end
- return 'An error occured, meaning I was unable to set the volume.'
-end
-
-function myspotify.on_inline_query(_, inline_query, _, language)
- if not redis:get('spotify:' .. inline_query.from.id .. ':access_token') and redis:get('spotify:' .. inline_query.from.id .. ':refresh_token') then
- local success = myspotify.reauthorise_account(inline_query.from.id)
- if not success then
- return false
- end
- redis:set('spotify:' .. inline_query.from.id .. ':access_token', success.access_token)
- redis:expire('spotify:' .. inline_query.from.id .. ':access_token', 3600)
- end
- local output = myspotify.get_user_info(inline_query.from.id, language)
- if not output then
- return false
- end
- local description = myspotify.help:match('%- (.-)$')
- local title = '@' .. myspotify.get_username(inline_query.from.id)
- local keyboard = myspotify.get_keyboard(inline_query.from.id, language)
- return mattata.send_inline_article(inline_query.id, title, description, output, 'html', keyboard)
-end
-
-function myspotify.on_callback_query(_, callback_query, message, configuration, language)
- local action, user_id = callback_query.data:match('^(.-):(%d+)$')
- if not user_id then
- return mattata.answer_callback_query(callback_query.id, 'This message is using an old version of this plugin, please request a new one by sending /myspotify!', true)
- end
- user_id = tonumber(user_id)
- callback_query.data = action
- if callback_query.from.id ~= user_id then
- return mattata.answer_callback_query(callback_query.id, 'You are not allowed to use this!')
- elseif callback_query.data == 'nil' then
- return mattata.answer_callback_query(callback_query.id)
- elseif not redis:get('spotify:' .. user_id .. ':access_token') then
- local success = myspotify.reauthorise_account(user_id, configuration)
- if not success then
- return mattata.answer_callback_query(callback_query.id, language['myspotify']['18'])
- end
- redis:set('spotify:' .. user_id .. ':access_token', success.access_token)
- redis:expire('spotify:' .. user_id .. ':access_token', 3600)
- mattata.answer_callback_query(callback_query.id, language['myspotify']['19'], true)
- end
- local output
- if callback_query.data == 'profile' then
- output = myspotify.get_user_info(user_id, language)
- elseif callback_query.data == 'following' then
- output = myspotify.get_following(user_id, language)
- elseif callback_query.data == 'toptracks' then
- output = myspotify.get_top_tracks(user_id, language)
- elseif callback_query.data == 'topartists' then
- output = myspotify.get_top_artists(user_id, language)
- elseif callback_query.data == 'recentlyplayed' then
- output = myspotify.get_recently_played(user_id, language)
- elseif callback_query.data == 'currentlyplaying' then
- output = myspotify.get_currently_playing(user_id, language)
- elseif callback_query.data == 'playlists' then
- output = myspotify.get_playlists(user_id, language)
- elseif callback_query.data == 'previous' then
- output = myspotify.previous_track(user_id, language) or language.errors.generic
- mattata.answer_callback_query(callback_query.id, output)
- elseif callback_query.data == 'next' then
- output = myspotify.next_track(user_id, language) or language.errors.generic
- mattata.answer_callback_query(callback_query.id, output)
- elseif callback_query.data == 'play' then
- output = myspotify.play(user_id, language) or language.errors.generic
- mattata.answer_callback_query(callback_query.id, output)
- elseif callback_query.data == 'pause' then
- output = myspotify.pause(user_id, language) or language.errors.generic
- mattata.answer_callback_query(callback_query.id, output)
- elseif callback_query.data == 'shuffle' then
- output = myspotify.shuffle(user_id, language)
- if output then
- myspotify.next_track(user_id, language)
- else
- output = language.errors.generic
- end
- mattata.answer_callback_query(callback_query.id, output)
- elseif callback_query.data == 'lyrics' then
- local artist = myspotify.get_current_artist(user_id)
- local track = myspotify.get_current_track(user_id, language, true)
- if artist then
- track = artist .. ' - ' .. track
- end
- local lyrics = require('plugins.lyrics')
- output = lyrics.send_request(track)
- end
- output = output or language.errors.generic
- local preview = callback_query.data == 'currentlyplaying' and false or true
- local keyboard = myspotify.get_keyboard(user_id, language)
- return mattata.edit_message_text(message.chat.id, message.message_id, output, 'html', preview, keyboard)
-end
-
-function myspotify.on_message(_, message, configuration, language)
- local input = mattata.input(message.text)
- if input and (input:lower() == 'reset' or input:lower() == 'revoke') then
- redis:del('spotify:' .. message.from.id .. ':access_token')
- redis:del('spotify:' .. message.from.id .. ':refresh_token')
- return mattata.send_reply(message, 'I have cleared your current account! Use /myspotify to link a new account.')
- elseif not redis:get('spotify:' .. message.from.id .. ':access_token') then
- if redis:get('spotify:' .. message.from.id .. ':refresh_token') then
- local wait_message = mattata.send_message(message.chat.id, language['myspotify']['20'])
- local success = myspotify.reauthorise_account(message.from.id, configuration)
- if not success then
- return mattata.edit_message_text(message.chat.id, wait_message.result.message_id, language['myspotify']['18'])
- end
- redis:set('spotify:' .. message.from.id .. ':access_token', success.access_token)
- redis:expire('spotify:' .. message.from.id .. ':access_token', 3600)
- mattata.edit_message_text(message.chat.id, wait_message.result.message_id, language['myspotify']['19'])
- else
- local success = mattata.send_force_reply(
- message,
- string.format(
- language['myspotify']['21'],
- url.escape(myspotify.client_id),
- url.escape(myspotify.redirect_uri),
- myspotify.redirect_uri
- ),
- 'markdown'
- )
- if success then
- mattata.set_command_action(message.chat.id, success.result.message_id, '/authspotify')
- end
- return
- end
- end
- local output = myspotify.get_user_info(message.from.id, language)
- if not output then
- return mattata.send_reply(message, language.errors.connection)
- end
- local keyboard = myspotify.get_keyboard(message.from.id, language)
- return mattata.send_message(message.chat.id, output, 'html', true, false, nil, keyboard)
-end
-
-return myspotify
\ No newline at end of file
diff --git a/plugins/needsmorejpeg.lua b/plugins/needsmorejpeg.lua
deleted file mode 100644
index 6518896..0000000
--- a/plugins/needsmorejpeg.lua
+++ /dev/null
@@ -1,42 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local needsmorejpeg = {}
-local mattata = require('mattata')
-
-function needsmorejpeg:init()
- needsmorejpeg.commands = mattata.commands(self.info.username, { '^[Nn][Ee][Ee][Dd][Ss] [Mm][Oo][Rr][Ee] [Jj][Pp][Ee]?[Gg]$', '^[Mm][Oo][AaRr][RrEe]$'}):command('needsmorejpeg').table
- needsmorejpeg.help = '/needsmorejpeg - Dreadfully reduces the quality of the replied-to photo.'
-end
-
-function needsmorejpeg.on_message(_, message, configuration)
- if not message.reply then
- return false
- elseif not message.reply.photo then
- return false
- end
- mattata.send_chat_action(message.chat.id, 'upload_photo')
- local file_id = message.reply.photo[#message.reply.photo].file_id
- local file = mattata.get_file(file_id)
- if not file then
- return false
- end
- local file_name = file.result.file_path
- local file_path = string.format('https://api.telegram.org/file/bot%s/%s', configuration.bot_token, file_name)
- file = mattata.download_file(file_path, file_name:match('/(.-)$'), '/home/matt/matticatebot')
- if not file then
- return false
- end
- local command = string.format('/home/matt/matticatebot/magick %s -quality 4 %s', file, file)
- os.execute(command)
- local success = mattata.send_photo(message.chat.id, file)
- if not success then
- return false
- end
- os.execute('rm ' .. file)
- return success
-end
-
-return needsmorejpeg
\ No newline at end of file
diff --git a/plugins/netflix.lua b/plugins/netflix.lua
deleted file mode 100644
index bc55eca..0000000
--- a/plugins/netflix.lua
+++ /dev/null
@@ -1,80 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local netflix = {}
-local mattata = require('mattata')
-local http = require('socket.http')
-local url = require('socket.url')
-local json = require('dkjson')
-
-function netflix:init()
- netflix.commands = mattata.commands(self.info.username)
- :command('netflix')
- :command('nf').table
- netflix.help = '/netflix <query> - Searches Netflix for the given search query and returns the most relevant result. Alias: /nf.'
-end
-
-function netflix.send_request(input, language)
- local jstr, res = http.request('http://netflixroulette.net/api/api.php?title=' .. url.escape(input))
- if res ~= 200
- then
- return false
- end
- local jdat = json.decode(jstr)
- if jdat.errorcode
- then
- return false
- end
- local output = {}
- table.insert(
- output,
- '<b>' .. mattata.escape_html(jdat.show_title) .. '</b>\n'
- )
- table.insert(
- output,
- '📅 ' .. jdat.release_year .. ' | ⭐ ' .. jdat.rating .. ' | ' .. mattata.escape_html(jdat.show_cast)
- )
- table.insert(
- output,
- '\n<i>' .. mattata.escape_html(jdat.summary) .. '</i>'
- )
- table.insert(
- output,
- '\n<a href="https://www.netflix.com/title/' .. jdat.show_id .. '">' .. language['netflix']['1'] .. '</a>'
- )
- return table.concat(
- output,
- '\n'
- )
-end
-
-function netflix:on_message(message, configuration, language)
- local input = mattata.input(message.text)
- if not input
- then
- return mattata.send_reply(
- message,
- netflix.help
- )
- end
- local output = netflix.send_request(
- input,
- language
- )
- if not output
- then
- return mattata.send_reply(
- message,
- language['errors']['results']
- )
- end
- return mattata.send_message(
- message.chat.id,
- output,
- 'html'
- )
-end
-
-return netflix
\ No newline at end of file
diff --git a/plugins/newchat.lua b/plugins/newchat.lua
deleted file mode 100644
index fd0ab54..0000000
--- a/plugins/newchat.lua
+++ /dev/null
@@ -1,76 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local newchat = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-local json = require('dkjson')
-
-function newchat:init()
- newchat.commands = mattata.commands(self.info.username):command('newchat').table
-end
-
-function newchat:on_message(message, configuration, language)
- if not mattata.is_global_admin(message.from.id)
- then
- return false
- end
- local input = mattata.input(message.text)
- if not input
- then
- return false
- end
- local link, title = input:match('^(.-) (.-)$')
- if not title
- then
- link = input
- title = link
- end
- if not link
- then
- return mattata.send_reply(
- message,
- 'Please specify a link to add to the list shown when /groups is sent. You need to use the following syntax: /newchat <link> [title]. If a title isn\'t given, the link will be used as the title too.'
- )
- elseif not link:match('https?://t%.me/.-$')
- then
- return mattata.send_reply(
- message,
- 'The link must begin with "https://t.me/"!'
- )
- end
- local entry = json.encode(
- {
- ['link'] = tostring(link),
- ['title'] = tostring(title)
- }
- )
- local entries = redis:smembers('mattata:configuration:chats')
- for k, v in pairs(entries)
- do
- if not v
- or not json.decode(v).link
- or not json.decode(v).title
- then
- return false
- elseif json.decode(v).link == link
- then
- return mattata.send_reply(
- message,
- 'That link already exists in the database, under the name "' .. json.decode(v).title .. '"!'
- )
- end
- end
- redis:sadd(
- 'mattata:configuration:chats',
- entry
- )
- return mattata.send_reply(
- message,
- 'I have added that link to the list shown when /groups is sent, under the name "' .. title .. '"!'
- )
-end
-
-return newchat
\ No newline at end of file
diff --git a/plugins/news.lua b/plugins/news.lua
deleted file mode 100644
index 77d8030..0000000
--- a/plugins/news.lua
+++ /dev/null
@@ -1,219 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local news = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local json = require('dkjson')
-local redis = require('libs.redis')
-
-function news:init()
- news.commands = mattata.commands(self.info.username)
- :command('news')
- :command('nsources')
- :command('setnews').table
- news.help = '/news <news source> - Sends the current top story from the given news source. Use /nsources to view a list of available sources. Use /setnews <news source> to set your preferred news source, and be able to use /news without giving any arguments.'
-end
-
-function news.send_sources(message, language)
- local input = mattata.input(message.text:lower())
- if not input then
- input = false
- else
- local success = pcall(function()
- return input:match(input)
- end)
- if not success then
- return mattata.send_reply(
- message,
- string.format(language['news']['1'], mattata.escape_html(input)),
- 'html'
- )
- end
- end
- local sources = news.get_sources(input)
- if not sources then
- return mattata.send_reply(message, language['news']['2'])
- end
- sources = table.concat(sources, ', ')
- if input then
- sources = string.format(
- language['news']['3'],
- mattata.escape_html(input),
- sources
- )
- else
- sources = string.format(language['news']['4'], sources)
- end
- return mattata.send_message(message.chat.id, sources, 'html')
-end
-
-function news.set_news(message, language)
- local input = mattata.input(
- message.text:lower()
- )
- if input
- then
- input = input:gsub('%-', ' ')
- end
- local preferred_source = redis:get(
- string.format(
- 'user:%s:news',
- message.from.id
- )
- )
- if not preferred_source
- and not input
- then
- return mattata.send_reply(
- message,
- language['news']['5']
- )
- elseif not input
- then
- return mattata.send_reply(
- message,
- string.format(
- language['news']['6'],
- preferred_source
- )
- )
- elseif preferred_source == input
- then
- return mattata.send_reply(
- message,
- string.format(
- language['news']['7'],
- input
- )
- )
- end
- if not news.is_valid(input)
- then
- return mattata.send_reply(
- message,
- language['news']['8']
- )
- end
- redis:set(
- string.format(
- 'user:%s:news',
- message.from.id
- ),
- input
- )
- return mattata.send_reply(
- message,
- string.format(
- language['news']['9'],
- input
- )
- )
-end
-
-function news.is_valid(source)
- local sources = news.get_sources()
- for k, v in pairs(sources)
- do
- if v == source
- then
- return true
- end
- end
- return false
-end
-
-function news.get_sources(input)
- local jstr, res = https.request('https://newsapi.org/v1/sources')
- if res ~= 200
- then
- return false
- end
- local jdat = json.decode(jstr)
- if jdat.status ~= 'ok'
- then
- return false
- end
- local sources = {}
- for k, v in pairs(jdat.sources)
- do
- v.id = v.id:gsub('%-', ' ')
- if input
- then
- if v.id:match(input)
- then
- table.insert(
- sources,
- v.id
- )
- end
- else
- table.insert(
- sources,
- v.id
- )
- end
- end
- table.sort(sources)
- return sources
-end
-
-function news:on_message(message, configuration, language)
- if message.text:match('^[/!#]nsources')
- then
- return news.send_sources(
- message,
- language
- )
- elseif message.text:match('^[/!#]setnews')
- then
- return news.set_news(
- message,
- language
- )
- end
- local input = mattata.input(
- message.text:lower()
- )
- if not input
- then
- local user = string.format('user:%s:news', message.from.id)
- local preferred_source = redis:get(user)
- if preferred_source then
- input = preferred_source
- else
- return mattata.send_reply(message, news.help)
- end
- end
- input = input:gsub('-', ' ')
- if not news.is_valid(input) then
- return mattata.send_reply(message, language['news']['10'])
- end
- input = input:gsub('%s', '-')
- local jstr, res = https.request('https://newsapi.org/v1/articles?apiKey=' .. configuration.keys.news .. '&source=' .. input .. '&sortBy=top')
- if res ~= 200 then
- return mattata.send_reply(message, language['errors']['connection'])
- end
- local jdat = json.decode(jstr)
- if not jdat.articles[1]
- then
- return mattata.send_reply(
- message,
- language['errors']['results']
- )
- end
- jdat.articles[1].publishedAt = jdat.articles[1].publishedAt:gsub('T.-$', '')
- local output = string.format(
- '<b>%s</b> <code>[%s]</code>\n%s\n<a href="%s">%s</a>\n<i>Powered by NewsAPI.</i>',
- jdat.articles[1].title,
- mattata.escape_html(jdat.articles[1].publishedAt),
- jdat.articles[1].description,
- jdat.articles[1].url,
- language['news']['11']
- )
- return mattata.send_message(message.chat.id, output, 'html')
-end
-
-return news
\ No newline at end of file
diff --git a/plugins/nick.lua b/plugins/nick.lua
deleted file mode 100644
index 549f3e6..0000000
--- a/plugins/nick.lua
+++ /dev/null
@@ -1,34 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local nick = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function nick:init(configuration)
- nick.commands = mattata.commands(self.info.username):command('nick'):command('nickname'):command('nn'):command('setnick').table
- nick.help = '/nick <text> - Sets your nickname to the given text. Your nickname can\'t be longer than ' .. configuration.limits.nick .. ' characters in length. Aliases: /nickname, /nn, /setnick.'
-end
-
-function nick.on_message(_, message, configuration)
- local input = mattata.input(message.text)
- if not input then
- local current = redis:hget('user:' .. message.from.id .. ':info', 'nickname')
- local output, parse_mode = nick.help
- if current then
- current = mattata.get_formatted_user(message.from.id, current, 'html')
- output = 'You are currently known as ' .. current .. '! To change this, send <code>/nick &lt;text&gt;</code>'
- parse_mode = 'html'
- end
- return mattata.send_reply(message, output, parse_mode)
- elseif input:len() > configuration.limits.nick then
- return mattata.send_reply(message, 'Your nickname can\'t be longer than ' .. configuration.limits.nick .. ' characters in length!')
- end
- redis:hset('user:' .. message.from.id .. ':info', 'nickname', input)
- local user = mattata.get_formatted_user(message.from.id, input, 'html')
- return mattata.send_message(message.chat.id, string.format('You\'ll now be known as %s!', user), 'html')
-end
-
-return nick
\ No newline at end of file
diff --git a/plugins/paste.lua b/plugins/paste.lua
deleted file mode 100644
index e055163..0000000
--- a/plugins/paste.lua
+++ /dev/null
@@ -1,161 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local paste = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local http = require('socket.http')
-local url = require('socket.url')
-local ltn12 = require('ltn12')
-local mime = require('mime')
-local multipart = require('multipart-post')
-local json = require('dkjson')
-local configuration = require('configuration')
-local redis = require('libs.redis')
-
-function paste:init()
- paste.commands = mattata.commands(self.info.username):command('paste').table
- paste.help = '/paste <text> - Uploads the given text, or replied-to text to a pasting service and returns the result URL.'
-end
-
-function paste.get_keyboard(current_time)
- current_time = current_time or 0
- return mattata.inline_keyboard()
- :row(
- mattata.row()
- :callback_data_button(
- 'paste.ee',
- 'paste:pasteee:' .. current_time
- )
- :callback_data_button(
- 'pastebin.com',
- 'paste:pastebin:' .. current_time
- )
- :callback_data_button(
- 'hastebin.com',
- 'paste:hastebin:' .. current_time
- )
- )
-end
-
-function paste.pasteee(input, id)
- input = '{"description":"' .. id .. ' via mattata","sections":[{"name":"Paste","syntax":"autodetect","contents":"' .. url.escape(input) .. '"}]}'
- local response = {}
- local _, res = https.request(
- {
- ['url'] = 'https://api.paste.ee/v1/pastes',
- ['method'] = 'POST',
- ['headers'] = {
- ['Content-Type'] = 'application/json',
- ['Content-Length'] = input:len(),
- ['Authorization'] = 'Basic ' .. mime.b64(configuration.keys.pasteee .. ':')
- },
- ['source'] = ltn12.source.string(input),
- ['sink'] = ltn12.sink.table(response)
- }
- )
- if res ~= 201 then
- return false
- end
- local jstr = table.concat(response)
- local jdat = json.decode(jstr)
- if not jdat or not jdat.success then
- return false
- end
- return jdat.link
-end
-
-function paste.pastebin(input)
- local parameters = {
- ['api_dev_key'] = configuration.keys.pastebin,
- ['api_option'] = 'paste',
- ['api_paste_code'] = input
- }
- local response = {}
- local body, boundary = multipart.encode(parameters)
- local _, res = http.request(
- {
- ['url'] = 'http://pastebin.com/api/api_post.php',
- ['method'] = 'POST',
- ['headers'] = {
- ['Content-Type'] = 'multipart/form-data; boundary=' .. boundary,
- ['Content-Length'] = #body
- },
- ['source'] = ltn12.source.string(body),
- ['sink'] = ltn12.sink.table(response)
- }
- )
- if res ~= 200
- then
- return false
- end
- return table.concat(response)
-end
-
-function paste.hastebin(input)
- local parameters = {
- ['data'] = input
- }
- local response = {}
- local body, boundary = multipart.encode(parameters)
- local _, res, head = https.request(
- {
- ['url'] = 'https://hasteb.in/documents',
- ['method'] = 'POST',
- ['headers'] = {
- ['Content-Type'] = 'multipart/form-data; boundary=' .. boundary,
- ['Content-Length'] = #body
- },
- ['redirect'] = false,
- ['source'] = ltn12.source.string(body),
- ['sink'] = ltn12.sink.table(response)
- }
- )
- if res ~= 200
- then
- return false
- end
- local jdat = json.decode(table.concat(response))
- if not jdat
- or not jdat.key
- then
- return false
- end
- return 'https://hasteb.in/' .. jdat.key
-end
-
-function paste:on_callback_query(callback_query, message, configuration, language)
- local input = mattata.input(message.reply.text)
- if not input then
- input = redis:get('paste:' .. callback_query.data:match(':(%d+)$'))
- redis:del('paste:' .. callback_query.data:match(':(%d+)$'))
- callback_query.data = callback_query.data:match('^(%a+):')
- end
- local output
- if callback_query.data == 'pasteee' then
- output = paste.pasteee(input, callback_query.from.id)
- elseif callback_query.data == 'pastebin' then
- output = paste.pastebin(input)
- elseif callback_query.data == 'hastebin' then
- output = paste.hastebin(input)
- end
- if not output then
- return mattata.answer_callback_query(callback_query.id, language['errors']['generic'])
- end
- return mattata.edit_message_text(message.chat.id, message.message_id, output, nil, true, paste.get_keyboard())
-end
-
-function paste:on_message(message, configuration, language)
- local current_time = os.time()
- local input = message.reply and message.reply.text or mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, paste.help)
- elseif message.reply then
- redis:set('paste:' .. current_time, input)
- end
- return mattata.send_message(message.chat.id, language['paste']['1'], nil, true, false, message.message_id, paste.get_keyboard(message.reply and current_time or false))
-end
-
-return paste
\ No newline at end of file
diff --git a/plugins/ping.lua b/plugins/ping.lua
deleted file mode 100644
index b598845..0000000
--- a/plugins/ping.lua
+++ /dev/null
@@ -1,21 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local ping = {}
-local mattata = require('mattata')
-
-function ping:init()
- ping.commands = mattata.commands(self.info.username):command('ping'):command('pong').table
- ping.help = '/ping - PONG!'
-end
-
-function ping.on_message(_, message)
- if message.text:match('^[/!#]pong') then
- return mattata.send_reply(message, 'You really have to go the extra mile, don\'t you?')
- end
- return mattata.send_sticker(message.chat.id, 'CAADBAAD1QIAAlAYNw2Pr-ymr7r8TgI')
-end
-
-return ping
diff --git a/plugins/place.lua b/plugins/place.lua
deleted file mode 100644
index c0ea5e8..0000000
--- a/plugins/place.lua
+++ /dev/null
@@ -1,81 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local place = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local json = require('dkjson')
-local redis = require('libs.redis')
-local configuration = require('configuration')
-
-function place:init()
- place.commands = mattata.commands(self.info.username):command('place').table
- place.help = '/place <name/phone> - Finds a place on Google Maps.'
-end
-
-function place:on_inline_query(inline_query, configuration)
- local input = mattata.input(inline_query.query)
- local is_phone = false
- if not input then
- return false, 'Please specify a location!'
- elseif input:match('^%+') then
- is_phone = true
- end
- local jdat, lat, lng = place.get(input, is_phone, configuration.keys.maps)
- if not jdat then
- return false, lat
- end
- return mattata.answer_inline_query(
- inline_query.id,
- json.encode({{
- ['type'] = 'location',
- ['id'] = '1',
- ['latitude'] = tonumber(jdat.latitude),
- ['longitude'] = tonumber(jdat.longitude),
- ['title'] = input
- }
- }))
-end
-
-function place.get(location, is_phone, api_key)
- local input_type = is_phone and 'phonenumber' or 'textquery'
- if input_type == 'phonenumber' then
- location = location:gsub(' ', '') -- get rid of any spaces in the phone number to prevent api issues
- end
- local jstr, res = https.request('https://maps.googleapis.com/maps/api/place/findplacefromtext/json?key=' .. api_key .. '&input=' .. url.escape(location) .. '&inputtype=' .. input_type)
- if res ~= 200 then
- return false, configuration.errors.connection
- end
- local jdat = json.decode(jstr)
- if jdat.status == 'ZERO_RESULTS' then
- return false, configuration.errors.results
- end
- local place_id = jdat.candidates[1].place_id
- jstr, res = https.request('https://maps.googleapis.com/maps/api/place/details/json?key=' .. api_key .. '&place_id=' .. place_id .. '&fields=address_component,name,geometry')
- jdat = json.decode(jstr)
- return true, jdat.result.geometry.location.lat, jdat.result.geometry.location.lng
-end
-
-function place:on_message(message, configuration)
- local input = mattata.input(message.text)
- local is_phone = false
- if not input then
- return mattata.send_reply(
- message,
- 'Please specify a place by its name or phone number!'
- )
- elseif input:match('^%+') then
- is_phone = true
- end
- local success, lat, lng = place.get(input, is_phone, configuration.keys.maps)
- if not success then
- mattata.send_reply(message, lat)
- return false
- end
- mattata.send_location(message.chat.id, lat, lng)
-end
-
-return place
\ No newline at end of file
diff --git a/plugins/plugins.lua b/plugins/plugins.lua
deleted file mode 100644
index d733098..0000000
--- a/plugins/plugins.lua
+++ /dev/null
@@ -1,316 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local plugins = {}
-local mattata = require('mattata')
-local json = require('dkjson')
-local redis = require('libs.redis')
-local configuration = require('configuration')
-
-function plugins:init()
- plugins.commands = mattata.commands(self.info.username):command('plugins').table
- plugins.help = '/plugins - Toggle the plugins you want to use in your chat with a slick inline keyboard, paginated and neatly formatted.'
-end
-
-function plugins:refresh(chat_id)
- local new = redis:smembers('disabled_plugins:' .. chat_id)
- if #new == 0 then
- new = nil
- end
- if not self.chats[tostring(chat_id)] then
- self.chats[tostring(chat_id)] = {}
- end
- self.chats[tostring(chat_id)].disabled_plugins = new
-end
-
-function plugins.get_toggleable_plugins()
- local toggleable = {}
- for _, v in pairs(configuration.plugins) do
- if v ~= 'plugins' and v ~= 'about' and v ~= 'bash' and v ~= 'lua' and v ~= 'reboot' and v ~= 'administration' then
- v = v:gsub('_', ' ')
- table.insert(toggleable, v)
- end
- end
- table.sort(toggleable)
- return toggleable
-end
-
-function plugins:get_keyboard(chat, page, columns, per_page)
- page = page or 1
- local toggleable = plugins.get_toggleable_plugins()
- local page_count = math.floor(#toggleable / per_page)
- if page_count < #toggleable / per_page then
- page_count = page_count + 1
- end
- if page < 1 then
- page = page_count
- elseif page > page_count then
- page = 1
- end
- local start_res = (page * per_page) - (per_page - 1)
- local end_res = start_res + (per_page - 1)
- if end_res > #toggleable then
- end_res = #toggleable
- end
- local plugin = 0
- local output = {}
- for _, v in pairs(toggleable) do
- v = v:lower()
- plugin = plugin + 1
- if plugin >= start_res and plugin <= end_res then
- local status
- if not redis:sismember('disabled_plugins:' .. chat, v) then
- status = utf8.char(9989)
- else
- status = utf8.char(10060)
- end
- table.insert(output, {
- ['plugin'] = v,
- ['status'] = status
- })
- end
- end
- local keyboard = {
- ['inline_keyboard'] = {
- {}
- }
- }
- local rows_per_page = math.floor(#output / columns)
- if rows_per_page < (#output / columns) then
- rows_per_page = rows_per_page + 1
- end
- local columns_per_page = math.floor(#output / rows_per_page)
- if columns_per_page < (#output / rows_per_page) then
- columns_per_page = columns_per_page + 1
- end
- local current_row = 1
- local count = 0
- for n in pairs(output) do
- count = count + 1
- if count == (columns_per_page * current_row) + 1 then
- current_row = current_row + 1
- table.insert(
- keyboard.inline_keyboard,
- {}
- )
- end
- table.insert(
- keyboard.inline_keyboard[current_row],
- {
- ['text'] = output[n].plugin:gsub('^%l', string.upper),
- ['callback_data'] = string.format(
- 'plugins:%s:%s:%s',
- chat,
- output[n].plugin,
- page
- )
- }
- )
- table.insert(
- keyboard.inline_keyboard[current_row],
- {
- ['text'] = output[n].status,
- ['callback_data'] = string.format(
- 'plugins:%s:%s:%s',
- chat,
- output[n].plugin,
- page
- )
- }
- )
- end
- table.insert(
- keyboard.inline_keyboard,
- {
- {
- ['text'] = utf8.char(8592) .. ' Previous',
- ['callback_data'] = string.format(
- 'plugins:%s:page:%s',
- chat,
- page - 1
- )
- },
- {
- ['text'] = string.format(
- '%s/%s',
- page,
- page_count
- ),
- ['callback_data'] = 'plugins:nil'
- },
- {
- ['text'] = 'Next ' .. utf8.char(8594),
- ['callback_data'] = string.format(
- 'plugins:%s:page:%s',
- chat,
- page + 1
- )
- }
- }
- )
- table.insert(
- keyboard.inline_keyboard,
- {
- {
- ['text'] = 'Disable All',
- ['callback_data'] = string.format(
- 'plugins:%s:disable_all:%s',
- chat,
- page
- )
- },
- {
- ['text'] = 'Enable All',
- ['callback_data'] = string.format(
- 'plugins:%s:enable_all:%s',
- chat,
- page
- )
- }
- }
- )
- table.insert(
- keyboard.inline_keyboard,
- {
- {
- ['text'] = 'Back',
- ['callback_data'] = 'help:settings'
- }
- }
- )
- return keyboard
-end
-
-function plugins:on_callback_query(callback_query, message, configuration)
- if not callback_query.data:match('^.-:.-:.-$') then
- return
- end
- local chat, callback_type, page = callback_query.data:match('^(.-):(.-):(.-)$')
- if (
- mattata.get_chat(chat) and mattata.get_chat(chat).result.type ~= 'private'
- ) and not mattata.is_group_admin(
- chat,
- callback_query.from.id
- ) then
- return mattata.answer_callback_query(
- callback_query.id,
- 'You must be an administrator to use this!'
- )
- end
- local toggle_status
- if callback_type ~= 'page' then
- local toggleable = plugins.get_toggleable_plugins()
- if callback_type == 'enable_all' then
- for _, v in pairs(toggleable) do
- redis:srem('disabled_plugins:' .. chat, v)
- end
- toggle_status = 'All plugins enabled!'
- elseif callback_type == 'disable_all' then
- for _, v in pairs(toggleable) do
- redis:sadd('disabled_plugins:' .. chat, v)
- end
- toggle_status = 'All plugins disabled!'
- elseif callback_type == 'enable_via_message' or callback_type == 'enable' then
- redis:srem('disabled_plugins:' .. chat, page)
- return mattata.answer_callback_query(
- callback_query.id,
- page:gsub('^%l', string.upper) .. ' has been enabled!'
- )
- elseif callback_type == 'dismiss_disabled_message' then
- redis:set(
- string.format(
- 'chat:%s:dismiss_disabled_message:%s',
- chat,
- page
- ),
- true
- )
- return mattata.answer_callback_query(
- callback_query.id,
- 'You will no longer be notified about this plugin!'
- )
- else
- if redis:sismember('disabled_plugins:' .. chat, callback_type) then
- redis:srem('disabled_plugins:' .. chat, callback_type)
- toggle_status = callback_type:gsub('^%l', string.upper) .. ' enabled!'
- else
- redis:sadd('disabled_plugins:' .. chat, callback_type)
- toggle_status = callback_type:gsub('^%l', string.upper) .. ' disabled!'
- end
- end
- end
- local keyboard = plugins.get_keyboard(self, chat, tonumber(page), configuration.limits.plugins.columns, configuration.limits.plugins.per_page)
- mattata.edit_message_reply_markup(message.chat.id, message.message_id, nil, keyboard)
- plugins.refresh(self, chat)
- return mattata.answer_callback_query(callback_query.id, toggle_status)
-end
-
-function plugins:on_message(message, configuration)
- if message.chat.type ~= 'private' and not mattata.is_group_admin(
- message.chat.id,
- message.from.id
- ) then
- return mattata.send_reply(
- message,
- 'You must be an administrator to use this!'
- )
- elseif message.chat.type == 'private' then
- local input = mattata.input(message.text)
- if input then
- if tonumber(input) == nil and not input:match('^%@') then
- input = '@' .. input
- end
- local resolved = mattata.get_chat(input)
- if resolved and mattata.is_group_admin(
- resolved.result.id,
- message.from.id
- ) then
- message.chat = resolved.result
- elseif not resolved then
- return mattata.send_reply(
- message,
- 'That\'s not a valid chat!'
- )
- else
- return mattata.send_reply(
- message,
- 'You don\'t appear to be an administrator in that chat!'
- )
- end
- end
- end
- local keyboard = plugins.get_keyboard(self, message.chat.id, 1, configuration.limits.plugins.columns, configuration.limits.plugins.per_page)
- local success = mattata.send_message(
- message.from.id,
- string.format(
- 'Toggle the plugins for <b>%s</b> using the keyboard below:',
- message.chat.title and mattata.escape_html(message.chat.title) or mattata.escape_html(message.chat.first_name)
- ),
- 'html',
- true,
- false,
- nil,
- json.encode(keyboard)
- )
- if message.chat.type == 'private' then
- return
- elseif not success then
- return mattata.send_reply(
- message,
- string.format(
- 'I couldn\'t send you the plugin management menu, you need to send me a [private message](https://t.me/%s?start=plugins%%20' .. message.chat.id .. ') first, then try using /plugins again.',
- self.info.username:lower()
- ),
- 'markdown',
- true
- )
- end
- return mattata.send_reply(
- message,
- 'I have sent you the plugin management menu via private chat.'
- )
-end
-
-return plugins
\ No newline at end of file
diff --git a/plugins/pokedex.lua b/plugins/pokedex.lua
deleted file mode 100644
index f6459f2..0000000
--- a/plugins/pokedex.lua
+++ /dev/null
@@ -1,206 +0,0 @@
---[[
- Based on a plugin by topkecleon. Licensed under GNU AGPLv3
- https://github.com/topkecleon/otouto/blob/master/LICENSE.
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local pokedex = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local json = require('dkjson')
-
-function pokedex:init()
- pokedex.commands = mattata.commands(self.info.username):command('pokedex'):command('pokemon'):command('dex').table
- pokedex.help = '/pokedex [name|ID] - If no input is given, an interactive Pokédex is sent. If input is given, information about the given Pokémon (either specified by name or ID) is returned. Results are provided by PokéAPI. Aliases: /pokemon, /dex.'
-end
-
-function pokedex.get_next_chain(evolution)
- if not evolution then
- return false
- end
- return evolution.species.name:gsub('^l', string.upper), evolution.evolves_to[1]
-end
-
-function pokedex.get_chain(id)
- local jstr, res = https.request('https://pokeapi.co/api/v2/pokemon-species/' .. id)
- if res ~= 200 then
- return false
- end
- local jdat = json.decode(jstr)
- if not jdat.evolution_chain then
- return '<em>This Pokémon doesn\'t evolve to/from anything...</em>'
- end
- jstr, res = https.request(jdat.evolution_chain.url)
- if res ~= 200 then
- return false
- end
- jdat = json.decode(jstr)
- local name, evolves_to = pokedex.get_next_chain(jdat.chain)
- local chain = name
- repeat
- name, evolves_to = pokedex.get_next_chain(evolves_to)
- if name then
- chain = chain .. string.format(' %s %s', mattata.symbols.next, name)
- end
- until not name
- if not chain:match(mattata.symbols.next) then
- return '<em>This Pokémon doesn\'t evolve to/from anything...</em>'
- end
- return 'Evolution chain: <code>' .. chain .. '</code>'
-end
-
-function pokedex.get_keyboard(page, columns, per_page)
- page = page or 1
- local offset = math.floor((page - 1) * per_page)
- local jstr, res = https.request('https://pokeapi.co/api/v2/pokemon?offset=' .. offset .. '&limit=' .. per_page)
- if res ~= 200 then
- return false
- end
- local jdat = json.decode(jstr)
- local all = jdat.results
- local page_count = math.floor(jdat.count / per_page)
- if page_count < jdat.count / per_page then
- page_count = page_count + 1
- end
- if page < 1 then
- page = page_count
- elseif page > page_count then
- page = 1
- end
- local start_res = 1
- local end_res = per_page
- if end_res > #all then
- end_res = #all
- end
- local pokemon = 0
- local output = {}
- for _, v in pairs(all) do
- v.name = v.name:lower()
- pokemon = pokemon + 1
- if pokemon >= start_res and pokemon <= end_res then
- table.insert(output, {
- ['name'] = v.name,
- ['id'] = v.url:match('pokemon/(%d*)/$')
- })
- end
- end
- local keyboard = {
- ['inline_keyboard'] = {{}}
- }
- local rows_per_page = math.floor(#output / columns)
- if rows_per_page < (#output / columns) then
- rows_per_page = rows_per_page + 1
- end
- local columns_per_page = math.floor(#output / rows_per_page)
- if columns_per_page < (#output / rows_per_page) then
- columns_per_page = columns_per_page + 1
- end
- local current_row = 1
- local count = 0
- for n in pairs(output) do
- count = count + 1
- if count == (columns_per_page * current_row) + 1 then
- current_row = current_row + 1
- table.insert(keyboard.inline_keyboard, {})
- end
- table.insert(keyboard.inline_keyboard[current_row], {
- ['text'] = '#' .. output[n].id .. ': ' .. output[n].name:gsub('^.', string.upper),
- ['callback_data'] = string.format('pokedex:%s:%s', output[n].name, page)
- })
- end
- local previous_page = page - 1
- if previous_page < 1 then
- previous_page = page_count
- end
- local next_page = page + 1
- if next_page > page_count then
- next_page = 1
- end
- table.insert(keyboard.inline_keyboard, {{
- ['text'] = utf8.char(8592) .. ' Previous',
- ['callback_data'] = string.format('pokedex:page:%s', previous_page)
- }, {
- ['text'] = string.format('%s/%s', page, page_count),
- ['callback_data'] = 'pokedex:nil'
- }, {
- ['text'] = 'Next ' .. utf8.char(8594),
- ['callback_data'] = string.format('pokedex:page:%s', next_page)
- }})
- return keyboard
-end
-
-function pokedex.on_callback_query(_, callback_query, message, _, language)
- local callback_type, page = callback_query.data:match('^(.-):(.-)$')
- if not callback_type or not page then
- return mattata.answer_callback_query(callback_query.id)
- elseif callback_type == 'page' then
- local keyboard = pokedex.get_keyboard(tonumber(page), 3, 21)
- return mattata.edit_message_text(message.chat.id, message.message_id, '<em>Select a Pokémon to view more information about it</em>', 'html', true, keyboard)
- end
- local output = pokedex.get_pokemon(callback_type, language)
- local keyboard = mattata.inline_keyboard():row(
- mattata.row():callback_data_button(mattata.symbols.back .. ' Back', 'pokedex:page:' .. page)
- )
- return mattata.edit_message_text(message.chat.id, message.message_id, output, 'html', false, keyboard)
-end
-
-function pokedex.get_pokemon(pokemon, language)
- if not pokemon then
- return language.errors.results
- end
- local jstr, res = https.request('https://pokeapi.co/api/v2/pokemon/' .. url.escape(pokemon))
- if res ~= 200 then
- return 'Please make sure you\'ve specified the Pokémon by its correct name. Alternatively, you can specify it by its Pokédex ID.'
- end
- local jdat = json.decode(jstr)
- local name = jdat.name:gsub('^%l', string.upper)
- local id = '#' .. jdat.id
- local descriptions = {}
- local description = 'Description unavailable'
- jstr, res = https.request('https://pokeapi.co/api/v2/pokemon-species/' .. jdat.id)
- if res == 200 then
- description = json.decode(jstr)
- for _, v in pairs(description.flavor_text_entries) do
- if v.language.name == 'en' then
- table.insert(descriptions, v)
- end
- end
- if next(descriptions) then
- description = descriptions[#descriptions].flavor_text:gsub('[\n\f]', ' ')
- end
- end
- description = description:gsub('[Pp][Oo][Kk][Eeé]?[Mm][Oo][Nn]', 'Pokémon')
- local poke_type
- for _, v in pairs(jdat.types) do
- local type_name = v.type.name:gsub('^%l', string.upper)
- if not poke_type then
- poke_type = type_name
- else
- poke_type = poke_type .. ' / ' .. type_name
- end
- end
- poke_type = poke_type .. ' type'
- local output = '<a href="%s">%s</a> <b>%s</b>\n%s\n\n<em>%s</em>'
- output = string.format(output, 'https://img.pokemondb.net/artwork/' .. name:gsub('^%u', string.lower) .. '.jpg', id, name, poke_type, description)
- if jdat.species then
- local species = jdat.species.url:match('species/(%d*)/$')
- species = pokedex.get_chain(species)
- if species then
- output = output .. '\n\n' .. species
- end
- end
- return output
-end
-
-function pokedex.on_message(_, message, _, language)
- local input = mattata.input(message.text:lower())
- if not input then
- return mattata.send_reply(message, 'Please select a Pokémon:', nil, false, pokedex.get_keyboard(1, 3, 21))
- end
- local output = pokedex.get_pokemon(input, language)
- return mattata.send_message(message.chat.id, output, 'html', false, false)
-end
-
-return pokedex
\ No newline at end of file
diff --git a/plugins/pun.lua b/plugins/pun.lua
deleted file mode 100644
index f6ae14a..0000000
--- a/plugins/pun.lua
+++ /dev/null
@@ -1,149 +0,0 @@
---[[
- Based on a plugin by topkecleon. Licensed under GNU AGPLv3
- https://github.com/topkecleon/otouto/blob/master/LICENSE.
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local pun = {}
-local mattata = require('mattata')
-
-function pun:init()
- pun.commands = mattata.commands(self.info.username):command('pun').table
- pun.help = '/pun - Generates a random pun.'
-end
-
-local puns = {
- 'The person who invented the door-knock won the No-bell prize.',
- 'I couldn\'t work out how to fasten my seatbelt. Then it clicked.',
- 'Never trust atoms; they make up everything.',
- 'Singing in the shower is all fun and games until you get shampoo in your mouth - Then it becomes a soap opera.',
- 'I can\'t believe I got fired from the calendar factory. All I did was take a day off.',
- 'To the guy who invented zero: Thanks for nothing!',
- 'Enough with the cripple jokes! I just can\'t stand them.',
- 'I\'ve accidentally swallowed some Scrabble tiles. My next crap could spell disaster.',
- 'How does Moses make his tea? Hebrews it.',
- 'Did you hear about the guy who got hit in the head with a can of soda? He was lucky it was a soft drink.',
- 'When William joined the army he disliked the phrase \'fire at will\'.',
- 'There was a sign on the lawn at a rehab center that said \'Keep off the Grass\'.',
- 'I wondered why the baseball was getting bigger. Then it hit me.',
- 'I can hear music coming out of my printer. I think the paper\'s jamming again.',
- 'I have a few jokes about unemployed people, but none of them work',
- 'Want to hear a construction joke? I\'m working on it',
- 'I always take a second pair of pants when I go golfing, in case I get a hole in one.',
- 'I couldn\'t remember how to catch a boomerang, but then it came back to me.',
- 'I\'ve decided that my Wi-Fi router will be my valentine this year. I don\'t know why, we just have this connection.',
- 'A prisoner\'s favourite punctuation mark is the period. It marks the end of his sentence.',
- 'I used to go fishing with Skrillex, but he kept dropping the bass.',
- 'Two antennae met on a roof and got married. The wedding was okay, but the reception was incredible.',
- 'A book just fell on my head. I\'ve only got my shelf to blame.',
- 'I dropped my steak on the floor. Now it\'s ground beef.',
- 'I used to have a fear of hurdles, but I got over it.',
- 'The outcome of war does not prove who is right, but only who is left.',
- 'Darth Vader tries not to burn his food, but it always comes out a little on the dark side.',
- 'The store keeps calling me to buy more furniture, but all I wanted was a one night stand.',
- 'This girl said she recognized me from the vegetarian club, but I\'d never met herbivore.',
- 'Police arrested two kids yesterday, one was drinking battery acid, the other was eating fireworks. They charged one and let the other one off...',
- 'No more Harry Potter jokes guys. I\'m Sirius.',
- 'It was hard getting over my addiction to hokey pokey, but I\'ve turned myself around.',
- 'It takes a lot of balls to golf the way I do.',
- 'Why did everyone want to hang out with the mushroom? Because he was a fungi.',
- 'How much does a hipster weigh? An instagram.',
- 'I used to be addicted to soap, but I\'m clean now.',
- 'When life gives you melons, you\'re probably dyslexic.',
- 'What\'s with all the blind jokes? I just don\'t see the point.',
- 'If Apple made a car, would it have Windows?',
- 'Need an ark? I Noah guy.',
- 'The scarecrow won an award because he was outstanding in his field.',
- 'What\'s the difference between a man in a tux on a bicycle, and a man in a sweatsuit on a trycicle? A tire.',
- 'What do you do with a sick chemist? If you can\'t helium, and you can\'t curium, you\'ll just have to barium.',
- 'I\'m reading a book about anti-gravity. It\'s impossible to put down.',
- 'Trying to write with a broken pencil is pointless.',
- 'When TVs go on vacation, they travel to remote islands.',
- 'I was going to tell a midget joke, but it\'s too short.',
- 'Jokes about German sausages are the wurst.',
- 'How do you organize a space party? You planet.',
- 'Sleeping comes so naturally to me, I could do it with my eyes closed.',
- 'I\'m glad I learned sign language; it\'s pretty handy.',
- 'Atheism is a non-prophet organization.',
- 'Velcro: What a rip-off!',
- 'If they made a Minecraft movie, it would be a blockbuster.',
- 'I don\'t trust people with graph paper. They\'re always plotting something',
- 'I had a friend who was addicted to brake fluid. He says he can stop anytime.',
- 'The form said I had Type A blood, but it was a Type O.',
- 'I went to to the shop to buy eight Sprites - I came home and realised I\'d picked 7-Up.',
- 'There was an explosion at a pie factory. 3.14 people died.',
- 'A man drove his car into a tree and found out how a Mercedes bends.',
- 'The experienced carpenter really nailed it, but the new guy screwed everything up.',
- 'I didn\'t like my beard at first, but then it grew on me.',
- 'Smaller babies may be delivered by stork, but the heavier ones need a crane.',
- 'What\'s the definition of a will? It\'s a dead giveaway.',
- 'I was going to look for my missing watch, but I could never find the time.',
- 'I hate elevators, and I often take steps to avoid them.',
- 'Did you hear about the guy whose whole left side was cut off? He\'s all right now.',
- 'It\'s not that the man did not know how to juggle, he just didn\'t have the balls to do it.',
- 'I used to be a loan shark, but I lost interest',
- 'I don\'t trust these stairs; they\'re always up to something.',
- 'My friend\'s bakery burned down last night. Now his business is toast.',
- 'Don\'t trust people that perform acupuncture; they\'re back stabbers.',
- 'The man who survived mustard gas and pepper spray is now a seasoned veteran.',
- 'Police were called to a daycare where a three-year-old was resisting a rest.',
- 'When Peter Pan punches, they Neverland',
- 'The shoemaker did not deny his apprentice anything he needed. He gave him his awl.',
- 'I did a theatrical performance about puns. It was a play on words.',
- 'Show me a piano falling down a mineshaft and I\'ll show you A-flat minor.',
- 'Have you ever tried to eat a clock? It\'s very time consuming.',
- 'There was once a cross-eyed teacher who couldn\'t control his pupils.',
- 'A new type of broom came out and it is sweeping the nation.',
- 'I relish the fact that you\'ve mustard the strength to ketchup to me.',
- 'I knew a woman who owned a taser. Man, was she stunning!',
- 'What did the grape say when it got stepped on? Nothing - but it let out a little whine.',
- 'It was an emotional wedding. Even the cake was in tiers.',
- 'When a clock is hungry it goes back four seconds.',
- 'The dead batteries were given out free of charge.',
- 'Why are there no knock-knock jokes about America? Because freedom rings.',
- 'When the cannibal showed up late to dinner, they gave him the cold shoulder.',
- 'I should have been sad when my flashlight died, but I was delighted.',
- 'Why don\'t tennis players ever get married? Love means nothing to them.',
- 'Pterodactyls can\'t be heard going to the bathroom because the P is silent.',
- 'Mermaids make calls on their shell phones.',
- 'What do you call an aardvark with three feet? A yaardvark.',
- 'Captain Kirk has three ears: A right ear, a left ear, and a final front ear.',
- 'How do celebrities stay cool? They have a lot of fans.',
- 'Without geometry, life is pointless.',
- 'Did you hear about the cow who tried to jump over a barbed-wire fence? It ended in udder destruction.',
- 'The truth may ring like a bell, but it is seldom ever tolled.',
- 'I used to work for the IRS, but my job was too taxing.',
- 'I used to be a programmer, but then I lost my drive.',
- 'Pediatricians are doctors with little patients.',
- 'I finally fired my masseuse today. She always rubbed me the wrong way.',
- 'I stayed up all night wondering where the sun went. Then it dawned on me.',
- 'What\'s the difference between a man and his dog? The man wears a suit; the dog just pants.',
- 'A psychic midget who escapes from prison is a small medium at large.',
- 'I\'ve been to the dentist several times, so I know the drill.',
- 'The roundest knight at King Arthur\'s round table was Sir Cumference. He acquired his size from too much pi.',
- 'She was only a whiskey maker, but he loved her still.',
- 'Male deer have buck teeth.',
- 'Whiteboards are remarkable.',
- 'Visitors in Cuba are always Havana good time.',
- 'Why does electricity shock people? It doesn\'t know how to conduct itself.',
- 'Lancelot had a scary dream about his horse. It was a knight mare.',
- 'A tribe of cannibals captured a missionary and ate him. Afterwards, they all had violent food poisoning. This just goes to show that you can\'t keep a good man down.',
- 'Heaven for gamblers is a paradise.',
- 'Old wheels aren\'t thrown away, they\'re just retired.',
- 'Horses are very stable animals.',
- 'Bankers don\'t crash, they just lose their balance.',
- 'The career of a skier can go downhill very fast.',
- 'In democracy, it\'s your vote that counts. In feudalism, it\'s your count that votes.',
- 'A sea lion is nothing but an ionized seal.',
- 'The vegetables from my garden aren\'t that great. I guess you could say they\'re mediokra.'
-}
-
-function pun:on_message(message)
- return mattata.send_message(
- message.chat.id,
- puns[math.random(#puns)]
- )
-end
-
-return pun
\ No newline at end of file
diff --git a/plugins/quote.lua b/plugins/quote.lua
deleted file mode 100644
index b2c356c..0000000
--- a/plugins/quote.lua
+++ /dev/null
@@ -1,53 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local quote = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function quote:init()
- quote.commands = mattata.commands(self.info.username):command('quote'):command('q').table
- quote.help = '/quote - Returns a randomly-selected, quoted message from the replied-to user. Quoted messages are stored when a user uses /save in reply to the said user\'s message(s). Alias: /q.'
-end
-
-function quote.on_message(_, message, _, language)
- if not message.reply then
- local quotes = redis:keys('user:*:quotes')
- if #quotes == 0 then
- return false
- end
- local selected = quotes[math.random(#quotes)]
- local user = selected:match('^user:(%d+):quotes$')
- local all = redis:smembers('user:' .. user .. ':quotes')
- local random = all[math.random(#all)]
- if random:match('^%$voice:.-$') then
- mattata.send_voice(message.chat.id, random:match('^%$voice:(.-)$'))
- random = '[Voice Message]'
- end
- return mattata.send_reply(message, string.format('<i>%s</i>\n– Anonymous', mattata.escape_html(random)), 'html')
- elseif redis:get('user:' .. message.reply.from.id .. ':opt_out') then
- redis:del('user:' .. message.reply.from.id .. ':quotes')
- return mattata.send_reply(message, language['quote']['1'])
- end
- local quotes = redis:smembers('user:' .. message.reply.from.id .. ':quotes')
- local user = mattata.get_formatted_user(message.reply.from.id, message.reply.from.name, 'html')
- if #quotes == 0 then
- return mattata.send_reply(message, string.format(language['quote']['2'], user), 'html')
- end
- local random = quotes[math.random(#quotes)]
- if random:match('^%$voice:.-$') then
- mattata.send_voice(message.chat.id, random:match('^%$voice:(.-)$'))
- random = '[Voice Message]'
- end
- return mattata.send_reply(
- message, string.format(
- '<i>%s</i>\n– %s',
- mattata.escape_html(random),
- user
- ), 'html'
- )
-end
-
-return quote
\ No newline at end of file
diff --git a/plugins/quotes.lua b/plugins/quotes.lua
deleted file mode 100644
index 27e7857..0000000
--- a/plugins/quotes.lua
+++ /dev/null
@@ -1,258 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local quotes = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function quotes:init()
- quotes.commands = mattata.commands(self.info.username):command('quotes').table
- quotes.help = '/quotes - Edit which quotes are saved in the database under your name.'
-end
-
-function quotes.get_quote(user, quote_number)
- quote_number = tonumber(quote_number)
- local all = redis:smembers('user:' .. user .. ':quotes')
- if not all then
- return 'You don\'t have any quotes!'
- end
- if #all < quote_number then
- return 'Invalid quote number!'
- end
- local output = all[quote_number]
- local voice = false
- if output:match('^%$voice:.-$') then
- output = output:match('^%$voice:(.-)$')
- voice = true
- end
- return output, voice
-end
-
-function quotes.get_confirmation_keyboard(user, quote_number, page)
- quote_number = tonumber(quote_number)
- local all = redis:smembers('user:' .. user .. ':quotes')
- if not all then
- return {}
- elseif not all[quote_number] then
- return {}
- end
- return mattata.inline_keyboard():row(
- mattata.row()
- :callback_data_button(
- mattata.symbols.back .. ' Back',
- 'quotes:' .. user .. ':back:' .. page
- )
- :callback_data_button(
- 'Delete',
- 'quotes:' .. user .. ':delete:' .. quote_number
- )
- )
-end
-
-function quotes.get_quotes(user)
- local all = redis:smembers('user:' .. user .. ':quotes')
- if not all then
- return false
- end
- return all
-end
-
-function quotes.get_pages(user, per_page)
- local all = quotes.get_quotes(user)
- if not all then
- return false
- end
- local page_count = math.floor(#all / per_page)
- if page_count < #all / per_page then
- page_count = page_count + 1
- end
- return all, page_count
-end
-
-function quotes.get_keyboard(all, user, page, columns, per_page)
- page = page or 1
- if not all then
- return false
- end
- local page_count = math.floor(#all / per_page)
- if page_count < #all / per_page then
- page_count = page_count + 1
- end
- if page < 1 then
- page = page_count
- elseif page > page_count then
- page = 1
- end
- local start_res = (page * per_page) - (per_page - 1)
- local end_res = start_res + (per_page - 1)
- if end_res > #all then
- end_res = #all
- end
- local quote = 0
- local output = {}
- for k, v in pairs(all) do
- quote = quote + 1
- if v:match('^%$voice:.-$') then
- v = '[Voice Message]'
- end
- if quote >= start_res and quote <= end_res then
- table.insert(output, {
- ['quote_number'] = k,
- ['quote_text'] = v
- })
- end
- end
- local keyboard = {
- ['inline_keyboard'] = {
- {}
- }
- }
- local columns_per_page = math.floor(#output / columns)
- if columns_per_page < (#output / columns) then
- columns_per_page = columns_per_page + 1
- end
- local rows_per_page = math.floor(#output / columns_per_page)
- if rows_per_page < (#output / columns_per_page) then
- rows_per_page = rows_per_page + 1
- end
- local current_row = 1
- local count = 0
- for n in pairs(output) do
- count = count + 1
- if count == (rows_per_page * current_row) + 1 then
- current_row = current_row + 1
- table.insert(keyboard.inline_keyboard, {})
- end
- table.insert(keyboard.inline_keyboard[current_row], {
- ['text'] = tostring(output[n].quote_number) .. ': ' .. output[n].quote_text,
- ['callback_data'] = string.format(
- 'quotes:%s:%s:%s', user,
- output[n].quote_number, page
- )
- })
- end
- if page_count > 1 then
- table.insert(keyboard.inline_keyboard, {{
- ['text'] = mattata.symbols.back .. ' Previous',
- ['callback_data'] = string.format(
- 'quotes:%s:page:%s',
- user,
- page - 1
- )
- }, {
- ['text'] = string.format(
- '%s/%s',
- page,
- page_count
- ),
- ['callback_data'] = 'quotes:nil'
- }, {
- ['text'] = 'Next ' .. mattata.symbols.next,
- ['callback_data'] = string.format(
- 'quotes:%s:page:%s',
- user,
- page + 1
- )
- }})
- end
- if count <= 0 then
- return false
- end
- return keyboard
-end
-
-function quotes.on_callback_query(_, callback_query, message)
- if not callback_query.data:match('^.-:.-:.-$') then
- return
- end
- local user, callback_type, page = callback_query.data:match('^(.-):(.-):(.-)$')
- if tostring(callback_query.from.id) ~= tostring(user) then
- return mattata.answer_callback_query(callback_query.id, 'You are not allowed to use this!')
- end
- local all, page_count = quotes.get_pages(callback_query.from.id, 10)
- page_count = page_count or 1
- if callback_type == 'back' or callback_type == 'page' then
- page = tonumber(page)
- if page > page_count then
- page = 1
- elseif page < 1 then
- page = page_count
- end
- local success = mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- 'Please select a quote:',
- nil, false,
- quotes.get_keyboard(
- all, callback_query.from.id,
- tonumber(page), 2, 10
- )
- )
- if not success then
- return mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- 'All quotes saved under your database entry have already been deleted!'
- )
- end
- return mattata.answer_callback_query(callback_query.id)
- elseif callback_type == 'delete' then
- if #all == 0 then
- return mattata.answer_callback_query(callback_query.id, 'All quotes saved under your database entry have already been deleted!')
- end
- page = tonumber(page)
- local quote = all[page]
- if not quote then
- return mattata.answer_callback_query(callback_query.id, 'This quote no longer exists!')
- end
- redis:srem('user:' .. callback_query.from.id .. ':quotes', quote)
- mattata.answer_callback_query(callback_query.id, 'That quote has been deleted from my database!')
- all = quotes.get_quotes(callback_query.from.id) -- Update the quotes.
- return mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- 'Please select a quote:',
- nil, false,
- quotes.get_keyboard(
- all, callback_query.from.id,
- tonumber(page), 2, 10
- )
- )
- elseif callback_type == 'back' then
- return mattata.edit_message_reply_markup(
- message.chat.id, message.message_id, nil,
- quotes.get_keyboard(all, callback_query.from.id, tonumber(page), 2, 10)
- )
- end
- local keyboard = quotes.get_confirmation_keyboard(
- callback_query.from.id,
- callback_type,
- page
- )
- local quote, voice = quotes.get_quote(callback_query.from.id, callback_type)
- if voice then
- local success = mattata.send_voice(message.chat.id, quote)
- if success then
- quote = 'Please listen to the voice message below:'
- else
- quote = 'I couldn\'t send that voice message as it\'s no longer on Telegram\'s servers. You might as well delete this!'
- end
- end
- local success = mattata.edit_message_text(message.chat.id, message.message_id, quote, nil, false, keyboard)
- if not success then
- return mattata.edit_message_text(message.chat.id, message.message_id, 'All quotes saved under your database entry have been deleted!')
- end
-end
-
-function quotes.on_message(_, message)
- local all = quotes.get_pages(message.from.id, 10)
- local keyboard = quotes.get_keyboard(all, message.from.id, 1, 2, 10)
- if not keyboard then
- return mattata.send_reply(message, 'You don\'t have any quotes saved in my database! Use /save in reply to one of your messages to save it!')
- end
- return mattata.send_message(message.chat.id, 'Please select a quote:', nil, true, false, nil, keyboard)
-end
-
-return quotes
\ No newline at end of file
diff --git a/plugins/reboot.lua b/plugins/reboot.lua
deleted file mode 100644
index 54b2eed..0000000
--- a/plugins/reboot.lua
+++ /dev/null
@@ -1,55 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local reboot = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function reboot:init()
- reboot.commands = mattata.commands(self.info.username):command('reboot'):command('shutdown'):command('reload').table
-end
-
-function reboot:on_new_message(message)
- if not mattata.is_global_admin(message.from.id) then
- return false
- elseif not message.text then
- return false
- elseif message.text:match('^.- && .-$') then
- local first, second = message.text:match('^(.-) && (.-)$')
- if not first:match('^[/!#]') then
- message.text = first
- mattata.on_message(self, message)
- end
- message.text = second
- return mattata.on_message(self, message)
- end
- return
-end
-
-function reboot:on_message(message)
- if not mattata.is_global_admin(message.from.id) or message.date < (os.time() - 2) then
- return false
- end
- if message.text:match('^[/!#]reload') then
- local success = mattata.send_message(message.chat.id, 'Reloading...')
- for pkg, _ in pairs(package.loaded) do -- Disable all of mattata's plugins and languages.
- if pkg:match('^plugins%.') or pkg:match('^languages%.') then
- package.loaded[pkg] = nil
- end
- end
- package.loaded['libs.utils'] = nil
- package.loaded['configuration'] = nil
- mattata.is_reloading = true
- mattata.init(self)
- return mattata.edit_message_text(message.chat.id, success.result.message_id, 'Successfully reloaded')
- end
- package.loaded['mattata'] = require('mattata')
- mattata.is_running = false
- local success = mattata.send_message(message.chat.id, 'Shutting down...')
- redis:set('mattata:shutdown', tostring(message.chat.id) .. ':' .. tostring(success.result.message_id))
- return success
-end
-
-return reboot
\ No newline at end of file
diff --git a/plugins/reddit.lua b/plugins/reddit.lua
deleted file mode 100644
index 5143f35..0000000
--- a/plugins/reddit.lua
+++ /dev/null
@@ -1,92 +0,0 @@
---[[
- Based on a plugin by topkecleon. Licensed under GNU AGPLv3
- https://github.com/topkecleon/otouto/blob/master/LICENSE.
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local reddit = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local json = require('dkjson')
-
-function reddit:init()
- reddit.commands = mattata.commands(self.info.username, { '^/r/' }):command('r/'):command('reddit').table
- reddit.help = '/r/subreddit - Returns the latest posts from the given subreddit.'
-end
-
-function reddit.format_results(posts, limit)
- local output = {}
- if #posts == 0 then
- return false
- end
- local count = 0
- for _, v in pairs(posts) do
- count = count + 1
- if count > limit then
- break
- end
- local post = v.data
- local title = post.title
- if title:len() > 250 then
- title = mattata.trim(title:sub(1, 250)) .. '...'
- end
- local short_url = 'redd.it/' .. post.id
- local result = '<a href="' .. mattata.escape_html(short_url) .. '">' .. mattata.escape_html(title) .. '</a>'
- if post.domain and not post.is_self then
- post.url = mattata.escape_html(post.url)
- post.domain = mattata.escape_html(post.domain)
- result = mattata.symbols.bullet .. ' <code>[</code><a href="' .. post.url .. '">' .. post.domain .. '</a><code>]</code> ' .. result
- else
- result = mattata.symbols.bullet .. ' ' .. result
- end
- table.insert(output, result)
- end
- return table.concat(output, '\n')
-end
-
-function reddit.on_message(_, message, configuration, language)
- local limit = message.chat.type ~= 'private' and configuration.limits.reddit.public or configuration.limits.reddit.private
- local input = mattata.input(message.text)
- local subreddit = message.text:match('^/r/([%w][%w_]+)%s?')
- if input and not subreddit then
- subreddit = input
- elseif not input and not subreddit then
- return mattata.send_reply(message, reddit.help)
- end
- if not subreddit or subreddit:len() > 21 or subreddit:len() < 2 then
- return mattata.send_reply(message, 'That\'s not a valid subreddit!')
- end
- local request_url = 'https://www.reddit.com/.json?limit=' .. limit
- local old_timeout = https.TIMEOUT
- https.TIMEOUT = 1
- if subreddit == 'random' or subreddit == 'randnsfw' then
- if message.chat.type ~= 'private' and subreddit == 'randnsfw' then
- subreddit = 'random'
- end
- local _, _, headers = https.request({
- ['url'] = 'https://www.reddit.com/r/' .. subreddit .. '.json?limit=1',
- ['redirect'] = false
- })
- subreddit = headers.location and headers.location:match('r/(.-)/%.json') or 'all'
- end
- if subreddit ~= 'all' then
- request_url = 'https://www.reddit.com/r/' .. subreddit .. '/.json?limit=' .. limit
- end
- local output = '<b>/r/' .. subreddit .. '</b>\n'
- local jstr, res = https.request(request_url)
- https.TIMEOUT = old_timeout
- if res == 404 or res == 'wantread' then
- return mattata.send_reply(message, language['errors']['results'])
- elseif res ~= 200 then
- return mattata.send_reply(message, language['errors']['connection'])
- end
- local jdat = json.decode(jstr)
- if not jdat or not jdat.data or #jdat.data.children < 1 then
- return mattata.send_reply(message, language['errors']['results'])
- end
- output = output .. reddit.format_results(jdat.data.children, limit)
- return mattata.send_message(message.chat.id, output, 'html', true)
-end
-
-return reddit
\ No newline at end of file
diff --git a/plugins/remind.lua b/plugins/remind.lua
deleted file mode 100644
index 9adb7f9..0000000
--- a/plugins/remind.lua
+++ /dev/null
@@ -1,193 +0,0 @@
---[[
- Based on a plugin by topkecleon. Licensed under GNU AGPLv3
- https://github.com/topkecleon/otouto/blob/master/LICENSE.
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local remind = {}
-local mattata = require('mattata')
-local json = require('dkjson')
-local redis = require('libs.redis')
-
-function remind:init()
- remind.commands = mattata.commands(self.info.username):command('remind'):command('reminders').table
- remind.help = '/remind <duration> <message> - Repeats a message after a duration of time, in the format 2d3h. The maximum number of reminders at one time is 4 per chat, and each reminder must be between 1 hour and 182 days in duration. Reminders cannot be any more than 256 characters in length. Use /reminders to view your current reminders. An example use of this command would be: /remind 21d3h test, which would remind you in 21 days and 3 hours.'
-end
-
-function remind.get_reminders(message)
- local reminders = {}
- if redis:get('reminders') then
- reminders = json.decode(
- redis:get('reminders')
- )
- end
- local this_chat = {}
- local count = 0
- for _, v in pairs(reminders) do
- if v.chat and v.chat.id == message.chat.id then
- table.insert(
- this_chat,
- string.format(
- utf8.char(8226) .. ' %s <code>[Added by %s, expires in approx. %s hour%s]</code>',
- mattata.escape_html(v.reminder),
- mattata.escape_html(v.name),
- mattata.round(
- (
- tonumber(v.expires) - os.time()
- ) / 3600,
- 2
- ),
- mattata.round(
- (
- tonumber(v.expires) - os.time()
- ) / 3600,
- 2
- ) == 1 and '' or 's'
- )
- )
- count = count + 1
- end
- end
- if count == 0 then
- return mattata.send_reply(
- message,
- 'You don\'t have any reminders set up in this chat!'
- )
- end
- return mattata.send_reply(
- message,
- string.format(
- 'You currently have %s reminder%s set up for %s:\n%s',
- count,
- count == 1 and '' or 's',
- mattata.escape_html(message.chat.title),
- table.concat(
- this_chat,
- '\n'
- )
- ),
- 'html'
- )
-end
-
-function remind.on_message(_, message)
- if message.text:match('^[%/%!%$%^%?%&%%]reminders') then
- return remind.get_reminders(message)
- end
- local input = mattata.input(message.text)
- if not input or not input:match('^.- .-$') then
- return mattata.send_reply(
- message,
- remind.help
- )
- end
- local duration, reminder = input:match('^(.-) (.-)$')
- -- Convert each unit of time into seconds.
- local weeks = 0
- if duration:match('%d[Ww]') then
- weeks = tonumber(
- duration:match('(%d*)[Ww]')
- ) * 604800
- end
- local days = 0
- if duration:match('%d[Dd]') then
- days = tonumber(
- duration:match('(%d*)[Dd]')
- ) * 86400
- end
- local hours = 0
- if duration:match('%d[Hh]') then
- hours = tonumber(
- duration:match('(%d*)[Hh]')
- ) * 3600
- end
- duration = weeks + days + hours
- if duration <= 0 then
- return mattata.send_reply(
- message,
- 'The duration you specified isn\'t in a valid format. The duration of your reminder must be between 1 hour and 6 months, and in the format 5m1w12d3h, which would remind you in 5 months, 1 week, 12 days and 3 hours.'
- )
- elseif duration > 31620000 or duration < 1 then
- return mattata.send_reply(
- message,
- 'The duration of your reminder must be between 1 hour and 366 days.'
- )
- end
- if utf8.len(reminder) > 256 then
- return mattata.send_reply(
- message,
- 'Your reminder must not be any longer than 256 characters.'
- )
- end
- local reminders = {}
- if redis:get('reminders') then
- reminders = json.decode(
- redis:get('reminders')
- )
- end
- local count = 0
- for k, v in pairs(reminders) do
- if v.chat and v.chat.id == message.chat.id then
- count = count + 1
- end
- end
- if count >= 4 then
- return mattata.send_reply(
- message,
- 'You already have 4 reminders set up in this chat. Please wait for one to expire before you add any more!'
- )
- end
- table.insert(
- reminders,
- {
- ['reminder'] = reminder,
- ['expires'] = os.time() + duration,
- ['chat'] = {
- ['id'] = message.chat.id,
- ['title'] = message.chat.title
- },
- ['name'] = message.from.name or message.chat.title
- }
- )
- redis:set(
- 'reminders',
- json.encode(reminders)
- )
- duration = duration / 3600 -- Convert back to hours.
- return mattata.send_reply(
- message,
- string.format(
- 'I will remind you in %s hour%s!',
- mattata.round(duration),
- tonumber(duration) == 1 and '' or 's'
- )
- )
-end
-
-function remind:cron()
- local current_time = os.time()
- local reminders = redis:get('reminders')
- if not reminders then return false end
- reminders = json.decode(reminders)
- if not next(reminders) then return false end
- for k, v in pairs(reminders) do
- if current_time > v.expires then
- mattata.send_message(
- v.chat.id,
- 'Reminder: ' .. v.reminder
- )
- table.remove(
- reminders,
- k
- )
- end
- end
- redis:set(
- 'reminders',
- json.encode(reminders)
- )
- return
-end
-
-return remind
\ No newline at end of file
diff --git a/plugins/responses.lua b/plugins/responses.lua
deleted file mode 100644
index 0dce47b..0000000
--- a/plugins/responses.lua
+++ /dev/null
@@ -1,72 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local responses = {}
-local mattata = require('mattata')
-
-function responses:init()
- responses.all = {
- ['night'] = {
- '^go?o?d? ?night$',
- '^g?night$',
- '^gn$'
- },
- ['morning'] = {
- '^go?o?d ?morning?$',
- '^morning?$',
- '^just woken? up'
- },
- ['yesno'] = {
- '^' .. self.info.name .. ',? do .-%??$',
- '^' .. self.info.name .. ',? [sc]h?ould .-%??$',
- '^' .. self.info.name .. ',? are .-%??$',
- '^' .. self.info.name .. ',? is .-%??$',
- ' y/n$'
- },
- ['iam'] = {
- '^[Ii][\'' .. utf8.char(8217) .. '%s]?[AaMm][Mm]?[\n ](%a+)$'
- }
- }
-end
-
-function responses:on_new_message(message)
- if not message.text or self.is_ai then return false end
- for category, response in pairs(responses.all) do
- for _, trigger in pairs(response) do
- if message.text:lower():match(trigger) then
- local yesno = {
- 'Yes',
- 'No',
- 'Maybe',
- 'Ask again later',
- 'Definitely',
- 'Definitely not',
- 'I don\'t know'
- }
- local output = yesno[math.random(#yesno)]
- if category == 'night' then
- output = 'Good night, ' .. message.from.first_name .. '!'
- elseif category == 'morning' then
- output = 'Good morning, ' .. message.from.first_name .. '!'
- elseif category == 'iam' and message.text:len() < 50 then
- local name = message.text:match(trigger)
- if name:lower() ~= 'back' and name:lower() ~= 'here' then
- output = 'Hello ' .. name .. ', I\'m ' .. self.info.first_name
- end
- end
- if output then
- return mattata.send_reply(message, output)
- end
- return
- end
- end
- end
- if message.text:lower():match('feeling? sexy') then
- return mattata.send_voice(message.chat.id, 'AwACAgQAAxkBAAIYwV7ZmESphxCW9E0ZSH4st2WY9ladAAJWOAACuxlkB_VheSVS_OpcGgQ', utf8.char(128521), nil, 9)
- end
- return false
-end
-
-return responses
\ No newline at end of file
diff --git a/plugins/runescape.lua b/plugins/runescape.lua
deleted file mode 100644
index e797fb8..0000000
--- a/plugins/runescape.lua
+++ /dev/null
@@ -1,200 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local runescape = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local json = require('dkjson')
-
-function runescape:init()
- runescape.commands = mattata.commands(self.info.username):command('runescape').table
- runescape.help = '/runescape <player name> - Displays skill-related information about the given RuneScape player.'
-end
-
-function runescape.errors(error_message, language)
- local errors = {
- ['NO_PROFILE'] = 'This player does not have a RuneMetrics profile!',
- ['PROFILE_PRIVATE'] = 'This player appears to have privacy mode enabled on their RuneMetrics profile!',
- ['Unable to fetch profile'] = 'This player appears to have privacy mode enabled on their RuneMetrics profile!'
- }
- return errors[error_message]
- or language['errors']['generic']
-end
-
-function runescape.get_skill_info(jdat)
- local skills = {
- ['0'] = 'Attack',
- ['1'] = 'Defence',
- ['2'] = 'Strength',
- ['3'] = 'Constitution',
- ['4'] = 'Ranged',
- ['5'] = 'Prayer',
- ['6'] = 'Magic',
- ['7'] = 'Cooking',
- ['8'] = 'Woodcutting',
- ['9'] = 'Fletching',
- ['10'] = 'Fishing',
- ['11'] = 'Firemaking',
- ['12'] = 'Crafting',
- ['13'] = 'Smithing',
- ['14'] = 'Mining',
- ['15'] = 'Herblore',
- ['16'] = 'Agility',
- ['17'] = 'Thieving',
- ['18'] = 'Slayer',
- ['19'] = 'Farming',
- ['20'] = 'Runecrafting',
- ['21'] = 'Hunter',
- ['22'] = 'Construction',
- ['23'] = 'Summoning',
- ['24'] = 'Dungeoneering',
- ['25'] = 'Divination',
- ['26'] = 'Invention',
- ['27'] = 'Archaeology'
- }
- local output = {}
- local longest_skill = 0
- local longest_rank = 0
- local longest_xp = 0
- local skill, rank, xp
- for _, v in pairs(jdat) do
- v.rank = v.rank or 'N/A'
- if v.id then
- skill = tostring(v.id)
- skill = skills[skill]
- if skill:len() > longest_skill then
- longest_skill = skill:len()
- end
- end
- if v.rank then
- rank = v.rank
- if rank ~= 'N/A' then
- rank = tonumber(rank)
- rank = mattata.comma_value(rank)
- end
- rank = tostring(rank)
- if rank:len() > longest_rank then
- longest_rank = rank:len()
- end
- end
- if v.xp then
- v.xp = tonumber(v.xp) / 10
- xp = mattata.comma_value(v.xp)
- xp = tostring(xp)
- if xp:len() > longest_xp then
- longest_xp = xp:len()
- end
- end
- end
- if longest_skill < 5 then
- longest_skill = 5
- end
- if longest_rank < 4 then
- longest_rank = 4
- end
- if longest_xp < 2 then
- longest_xp = 2
- end
- local separator = '|-'
- for _ = 1, longest_skill do
- separator = separator .. '-'
- end
- separator = separator .. '-|-------|-'
- for _ = 1, longest_rank do
- separator = separator .. '-'
- end
- separator = separator .. '-|-'
- for _ = 1, longest_xp do
- separator = separator .. '-'
- end
- separator = separator .. '-|'
- table.insert(output, separator)
- local heading = ''
- for k, v in pairs(jdat) do
- v.rank = v.rank or 'N/A'
- if v.id and v.level and v.rank and v.xp then
- local id = tostring(v.id)
- skill = skills[id]
- if skill:len() < longest_skill then
- repeat
- skill = skill .. ' '
- until skill:len() == longest_skill
- end
- local level = tostring(v.level)
- repeat
- level = level .. ' '
- until level:len() == 5
- rank = v.rank
- if rank ~= 'N/A' then
- rank = tonumber(rank)
- rank = mattata.comma_value(rank)
- end
- rank = tostring(rank)
- if rank:len() < longest_rank then
- repeat
- rank = rank .. ' '
- until rank:len() == longest_rank
- end
- xp = mattata.comma_value(v.xp)
- xp = tostring(xp)
- if xp:len() < longest_xp then
- repeat
- xp = xp .. ' '
- until xp:len() == longest_xp
- end
- local row = '| ' .. skill .. ' | ' .. level .. ' | ' .. rank .. ' | ' .. xp .. ' |'
- table.insert(output, row)
- if k < #jdat then
- table.insert(output, separator)
- else
- skill = 'Skill'
- if skill:len() < longest_skill then
- repeat
- skill = skill .. ' '
- until skill:len() == longest_skill
- end
- level = 'Level'
- rank = 'Rank'
- if rank:len() < longest_rank then
- repeat
- rank = rank .. ' '
- until rank:len() == longest_rank
- end
- xp = 'XP'
- if xp:len() < longest_xp then
- repeat
- xp = xp .. ' '
- until xp:len() == longest_xp
- end
- heading = '| ' .. skill .. ' | ' .. level .. ' | ' .. rank .. ' | ' .. xp .. ' |'
- end
- end
- end
- table.insert(output, separator)
- output = table.concat(output, '\n')
- return output, heading
-end
-
-function runescape.on_message(_, message, _, language)
- local input = mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, runescape.help)
- end
- local jstr, res = https.request('https://apps.runescape.com/runemetrics/profile/profile?user=' .. url.escape(input))
- if res ~= 200 then
- return mattata.send_reply(message, language.errors.connection)
- end
- local jdat = json.decode(jstr)
- if jdat.error or not jdat.skillvalues then
- local error_message = runescape.errors(jdat.error, language)
- return mattata.send_reply(message, error_message)
- end
- local output, heading = runescape.get_skill_info(jdat.skillvalues)
- output = string.format('<pre>%s\n%s</pre>', mattata.escape_html(heading), mattata.escape_html(output))
- return mattata.send_message(message.chat.id, output, 'html')
-end
-
-return runescape
\ No newline at end of file
diff --git a/plugins/sed.lua b/plugins/sed.lua
deleted file mode 100644
index a9781c9..0000000
--- a/plugins/sed.lua
+++ /dev/null
@@ -1,161 +0,0 @@
---[[
- Based on a plugin by topkecleon. Licensed under GNU AGPLv3
- https://github.com/topkecleon/otouto/blob/master/LICENSE.
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local sed = {}
-local mattata = require('mattata')
-local re = require('re')
-local regex = require('rex_pcre')
-
-function sed:init()
- sed.commands = { '^[sS]/.-/.-/?.?$' }
- sed.help = 's/pattern/substitution - Replaces all occurences, of text matching a given Lua pattern, with the given substitution.'
-end
-
-local compiled = re.compile[[
-invocation <- 's/' {~ pcre ~} '/' {~ replace ~} ('/' modifiers)? !.
-pcre <- ( [^\/] / slash / '\' )*
-replace <- ( [^\/%$] / percent / slash / capture / '\' / '$' )*
-
-modifiers <- { flags? } {~ matches? ~} {~ probability? ~}
-
-flags <- ('i' / 'm' / 's' / 'x' / 'U' / 'X')+
-matches <- ('#' {[0-9]+}) -> '%1'
-probability <- ('%' {[0-9]+}) -> '%1'
-
-slash <- ('\' '/') -> '/'
-percent <- '%' -> '%%%%'
-capture <- ('$' {[0-9]+}) -> '%%%1'
-]]
-
-function sed:on_callback_query(callback_query, message, configuration, language)
- if not message.reply then
- return mattata.delete_message(message.chat.id, message.message_id)
- elseif mattata.is_global_admin(callback_query.from.id) then -- we'll pull a sneaky on them
- callback_query.from = message.reply.from
- elseif message.reply.from.id ~= callback_query.from.id then
- return mattata.answer_callback_query(callback_query.id, 'That\'s not your place to say!')
- end
- local output = string.format(
- '<b>%s:</b>\n%s',
- message.text:match('^(.-):'),
- message.text:match(':\n(.-)$')
- )
- if callback_query.data:match('^no$') then
- output = string.format(
- language['sed']['1'],
- output,
- mattata.escape_html(callback_query.from.first_name)
- )
- elseif callback_query.data:match('^yes$') then
- output = string.format(
- language['sed']['2'],
- output,
- mattata.escape_html(callback_query.from.first_name)
- )
- elseif callback_query.data:match('^maybe$') then
- output = string.format(
- language['sed']['3'],
- output,
- mattata.escape_html(callback_query.from.first_name)
- )
- end
- return mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- output,
- 'html'
- )
-end
-
-function sed:on_message(message, _, language)
- if not message.reply then
- return false
- elseif message.reply.from.id == self.info.id then
- return mattata.send_reply(message, language['sed']['4'], 'html')
- elseif message.reply.from.id == message.from.id then
- return mattata.send_reply(message, language['sed']['10'])
- end
- local input = message.reply.text
- local text = message.text:match('^[sS]/(.*)$')
- if not text then
- return false
- end
- text = 's/' .. text
- local pattern, replace, flags, matches, probability = compiled:match(text)
- if not pattern then
- return false
- end
- if matches then matches = tonumber(matches) end
- if probability then probability = tonumber(probability) end
- if probability then
- if not matches then
- matches = function()
- return math.random() * 100 < probability
- end
- else
- local remaining = matches
- matches = function()
- local temp
- if remaining > 0 then
- temp = nil
- else
- temp = 0
- end
- remaining = remaining - 1
- return math.random() * 100 < probability, temp
- end
- end
- end
- local success, result, matched = pcall(function ()
- return regex.gsub(input, pattern, replace, matches, flags)
- end)
- if success == false then
- return mattata.send_reply(
- message,
- string.format(
- '%s is invalid PCRE regex syntax!',
- mattata.escape_html(text)
- ),
- 'html'
- )
- elseif matched == 0 then
- return
- end
- result = mattata.trim(result)
- if not result or result == '' then
- return false
- end
- local user = mattata.get_formatted_user(message.reply.from.id, message.reply.from.first_name, 'html')
- local from = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
- return mattata.send_message(
- message.chat.id,
- string.format(
- language['sed']['6'],
- user,
- from,
- mattata.escape_html(result)
- ),
- 'html',
- true,
- false,
- message.reply.message_id,
- mattata.inline_keyboard():row(
- mattata.row():callback_data_button(
- utf8.char(128077),
- 'sed:yes'
- ):callback_data_button(
- utf8.char(128078),
- 'sed:no'
- ):callback_data_button(
- '¯\\_(ツ)_/¯',
- 'sed:maybe'
- )
- )
- )
-end
-
-return sed
\ No newline at end of file
diff --git a/plugins/setlang.lua b/plugins/setlang.lua
deleted file mode 100644
index 00dd3e1..0000000
--- a/plugins/setlang.lua
+++ /dev/null
@@ -1,159 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local setlang = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-local json = require('dkjson')
-
-function setlang:init()
- setlang.commands = mattata.commands(self.info.username):command('setlang').table
- setlang.help = '/setlang - Allows you to select your language.'
-end
-
-setlang.languages = {
- ['ar_ar'] = 'Arabic 🇸🇦',
- ['en_gb'] = 'British English 🇬🇧',
- ['en_us'] = 'American English 🇺🇸',
- ['de_de'] = 'Deutsch 🇩🇪',
- ['scottish'] = 'Scottish 🏴',
- ['pl_pl'] = 'Polski 🇵🇱',
- ['pt_br'] = 'Português do Brasil 🇧🇷',
- ['pt_pt'] = 'Português 🇵🇹',
- ['tr_tr'] = 'Türkçe 🇹🇷'
-}
-
-setlang.languages_short = {
- ['ar_ar'] = '🇸🇦',
- ['en_gb'] = '🇬🇧',
- ['en_us'] = '🇺🇸',
- ['de_de'] = '🇩🇪',
- ['scottish'] = '🏴',
- ['pl_pl'] = '🇵🇱',
- ['pt_br'] = '🇧🇷',
- ['pt_pt'] = '🇵🇹',
- ['tr_tr'] = '🇹🇷'
-}
-
-function setlang.get_keyboard(user_id)
- local keyboard = {
- ['inline_keyboard'] = {
- {}
- }
- }
- local total = 0
- for _, v in pairs(setlang.languages_short)
- do
- total = total + 1
- end
- local count = 0
- local rows = math.floor(total / 2)
- if rows ~= total
- then
- rows = rows + 1
- end
- local row = 1
- for k, v in pairs(setlang.languages_short)
- do
- count = count + 1
- if count == rows * row
- then
- row = row + 1
- table.insert(
- keyboard.inline_keyboard,
- {}
- )
- end
- table.insert(
- keyboard.inline_keyboard[row],
- {
- ['text'] = v,
- ['callback_data'] = 'setlang:' .. user_id .. ':' .. k
- }
- )
- end
- return keyboard
-end
-
-function setlang.set_lang(user_id, locale, lang, language)
- redis:hset(
- 'chat:' .. user_id .. ':settings',
- 'language',
- locale
- )
- return string.format(
- language['setlang']['1'],
- lang
- )
-end
-
-function setlang.get_lang(user_id, language)
- local lang = redis:hget(
- 'chat:' .. user_id .. ':settings',
- 'language'
- )
- or 'en_gb'
- for k, v in pairs(setlang.languages)
- do
- if k == lang
- then
- lang = v
- break
- end
- end
- return string.format(
- language['setlang']['2'],
- lang
- )
-end
-
-function setlang:on_callback_query(callback_query, message, configuration, language)
- if not message
- or (
- message
- and message.date <= 1493668000
- )
- then
- return -- We don't want to process requests from messages before the language
- -- functionality was re-implemented, it could cause issues!
- end
- local user_id, new_language = callback_query.data:match('^(.-)%:(.-)$')
- if not user_id
- or not new_language
- or tostring(callback_query.from.id) ~= user_id
- then
- return
- end
- return mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- setlang.set_lang(
- user_id,
- new_language,
- setlang.languages[new_language],
- language
- ),
- nil,
- true,
- setlang.get_keyboard(user_id)
- )
-end
-
-function setlang:on_message(message, configuration, language)
- return mattata.send_message(
- message.chat.id,
- setlang.get_lang(
- message.from.id,
- language
- ),
- nil,
- true,
- false,
- nil,
- setlang.get_keyboard(message.from.id)
- )
-end
-
-return setlang
\ No newline at end of file
diff --git a/plugins/setlmgtfy.lua b/plugins/setlmgtfy.lua
deleted file mode 100644
index e58f1f5..0000000
--- a/plugins/setlmgtfy.lua
+++ /dev/null
@@ -1,27 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local setlmgtfy = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function setlmgtfy:init()
- setlmgtfy.commands = mattata.commands(self.info.username):command('setlmgtfy'):command('sl').table
- setlmgtfy.help = '/setlmgtfy <response text> - Sets the response text for the LMGTFY plugin. Alias: /sl.'
-end
-
-function setlmgtfy:on_message(message)
- if not mattata.is_group_admin(message.chat.id, message.from.id) or message.chat.type == 'private' then
- return false
- end
- local input = mattata.input(message.text)
- if not input or input:len() > 128 then
- return mattata.send_reply(message, 'Please specify some text to reply to the user with. No longer than 128 characters please!')
- end
- redis:set('chat:' .. message.chat.id .. ':lmgtfy', input)
- return mattata.send_reply(message, 'Successfully set that text as the LMGTFY response!')
-end
-
-return setlmgtfy
\ No newline at end of file
diff --git a/plugins/setloc.lua b/plugins/setloc.lua
deleted file mode 100644
index ef15c3c..0000000
--- a/plugins/setloc.lua
+++ /dev/null
@@ -1,68 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local setloc = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local json = require('dkjson')
-local redis = require('libs.redis')
-local configuration = require('configuration')
-
-function setloc:init(configuration)
- assert(configuration.keys.location, 'You must set your configuration key for plugins/setloc.mattata! This can be done in configuration.lua')
- setloc.commands = mattata.commands(self.info.username):command('setloc').table
- setloc.help = '/setloc <location> - Sets your location to the given value.'
- setloc.url = 'https://api.opencagedata.com/geocode/v1/json?key='
- setloc.api_key = configuration.keys.location
-end
-
-function setloc.check_loc(location, language)
- local jstr, res = https.request(setloc.url .. setloc.api_key .. '&pretty=0&q=' .. url.escape(location))
- if res ~= 200 then
- return false, language.errors.connection
- end
- local jdat = json.decode(jstr)
- if jdat.total_results == 0 then
- return false, language.errors.results
- end
- return true, jdat.results[1].geometry.lat .. ':' .. jdat.results[1].geometry.lng .. ':' .. jdat.results[1].formatted
-end
-
-function setloc.set_loc(user_id, location, language)
- local val, res = setloc.check_loc(location, language)
- if not val then
- return res
- end
- local latitude, longitude, address = res:match('^(.-):(.-):(.-)$')
- local user_location = json.encode(
- {
- ['latitude'] = latitude,
- ['longitude'] = longitude,
- ['address'] = address
- }
- )
- redis:hset('user:' .. user_id .. ':info', 'location', user_location)
- return 'Your location has been updated to: ' .. address .. '\nYou can now use commands such as /weather and /location, without needing to specify a location - your location will be used by default. Giving a different location as the command argument will override this.'
-end
-
-function setloc.get_loc(user_id)
- return redis:hget('user:' .. user_id .. ':info', 'location')
-end
-
-function setloc:on_message(message, configuration, language)
- local input = mattata.input(message.text)
- if not input then
- local location = setloc.get_loc(message.from.id)
- if not location then
- return mattata.send_reply(message, 'You don\'t have a location set. Use /setloc <location> to set one.')
- end
- return mattata.send_reply(message, 'Your location is currently set to: ' .. json.decode(location).address)
- end
- local output = setloc.set_loc(message.from.id, input, language)
- return mattata.send_message(message.chat.id, output)
-end
-
-return setloc
\ No newline at end of file
diff --git a/plugins/share.lua b/plugins/share.lua
deleted file mode 100644
index 18d55f4..0000000
--- a/plugins/share.lua
+++ /dev/null
@@ -1,45 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local share = {}
-local mattata = require('mattata')
-local url = require('socket.url')
-
-function share:init()
- share.commands = mattata.commands(self.info.username):command('share').table
- share.help = '/share <url> <text> - Share the given URL through an inline button, with the specified text as the caption.'
-end
-
-function share:on_message(message, configuration, language)
- local input = mattata.input(message.text)
- if not input
- or not input:match('^.- .-$')
- then
- return mattata.send_reply(
- message,
- share.help
- )
- end
- return mattata.send_message(
- message.chat.id,
- input:match('^.- (.-)$'),
- nil,
- true,
- false,
- nil,
- mattata.inline_keyboard():row(
- mattata.row():url_button(
- language['share']['1'] .. ' ' .. utf8.char(8618),
- 'https://t.me/share/url?url=' .. url.escape(
- input:match('^(.-) .-$')
- ) .. '&text=' .. url.escape(
- input:match('^.- (.-)$')
- )
- )
- )
- )
-end
-
-return share
\ No newline at end of file
diff --git a/plugins/shorten.lua b/plugins/shorten.lua
deleted file mode 100644
index a5c6f4c..0000000
--- a/plugins/shorten.lua
+++ /dev/null
@@ -1,142 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local shorten = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local ltn12 = require('ltn12')
-local json = require('dkjson')
-local configuration = require('configuration')
-
-function shorten:init()
- shorten.commands = mattata.commands(self.info.username):command('shorten').table
- shorten.help = '/shorten <url> - Shortens the given URL using one of the given URL shorteners.'
-end
-
-function shorten.get_keyboard()
- return mattata.inline_keyboard():row(
- mattata.row()
- :callback_data_button(
- 'goo.gl',
- 'shorten:googl'
- )
- :callback_data_button(
- 'adf.ly',
- 'shorten:adfly'
- )
- )
-end
-
-function shorten.googl(input)
- local body = json.encode(
- {
- ['longUrl'] = tostring(input)
- }
- )
- local response = {}
- local _, res = https.request(
- {
- ['url'] = 'https://www.googleapis.com/urlshortener/v1/url?key=' .. configuration.keys.google.api_key,
- ['method'] = 'POST',
- ['headers'] = {
- ['Content-Type'] = 'application/json',
- ['Content-Length'] = body:len()
- },
- ['source'] = ltn12.source.string(body),
- ['sink'] = ltn12.sink.table(response)
- }
- )
- if res ~= 200
- then
- return false
- end
- local jdat = json.decode(table.concat(response))
- if not jdat.id
- then
- return false
- end
- return jdat.id
-end
-
-function shorten.adfly(input)
- local body = '_api_key=' .. configuration.keys.adfly.api_key .. '&_user_id=' .. configuration.keys.adfly.user_id .. '&domain=adf.ly&url=' .. input .. '&advert_type=1'
- local response = {}
- local _, res = https.request(
- {
- ['url'] = 'https://api.adf.ly/v1/shorten',
- ['method'] = 'POST',
- ['headers'] = {
- ['Content-Type'] = 'application/x-www-form-urlencoded',
- ['Content-Length'] = body:len()
- },
- ['source'] = ltn12.source.string(body),
- ['sink'] = ltn12.sink.table(response)
- }
- )
- if res ~= 200
- then
- return false
- end
- local jdat = json.decode(table.concat(response))
- if not jdat.data[1]
- then
- return false
- end
- return jdat.data[1].short_url
-end
-
-function shorten:on_callback_query(callback_query, message, configuration, language)
- local input = mattata.input(message.reply.text)
- if not input
- then
- return false
- end
- local output
- if callback_query.data == 'googl'
- then
- output = shorten.googl(input)
- elseif callback_query.data == 'adfly'
- then
- output = shorten.adfly(input)
- end
- if not output
- then
- return mattata.answer_callback_query(
- callback_query.id,
- language['errors']['generic']
- )
- end
- return mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- output,
- nil,
- true,
- shorten.get_keyboard()
- )
-end
-
-function shorten:on_message(message, configuration, language)
- local input = mattata.input(message.text)
- if not input
- then
- return mattata.send_reply(
- message,
- shorten.help
- )
- end
- return mattata.send_message(
- message.chat.id,
- language['shorten']['1'],
- nil,
- true,
- false,
- message.message_id,
- shorten.get_keyboard()
- )
-end
-
-return shorten
\ No newline at end of file
diff --git a/plugins/shsh.lua b/plugins/shsh.lua
deleted file mode 100644
index 6274ee8..0000000
--- a/plugins/shsh.lua
+++ /dev/null
@@ -1,60 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local shsh = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-
-function shsh:init()
- shsh.commands = mattata.commands(self.info.username):command('shsh').table
- shsh.help = '/shsh <ecid> - Returns a list of all available SHSH blobs for the given device (specified by its ECID).'
-end
-
-function shsh:on_message(message, configuration, language)
- local input = mattata.input(message.text)
- if not input
- then
- return mattata.send_reply(
- message,
- shsh.help
- )
- end
- local str, res = https.request('https://tsssaver.1conan.com/shsh/' .. url.escape(input) .. '/')
- if res ~= 200
- then
- return mattata.send_reply(
- message,
- language['shsh']['1']
- )
- end
- local versions = {}
- for n in str:gmatch('%<td%>%<a href=".-" title=".-"%>(.-)/%</a%>%</td%>')
- do
- table.insert(
- versions,
- mattata.symbols.bullet .. ' ' .. n
- )
- end
- return mattata.send_message(
- message.chat.id,
- language['shsh']['2'] .. table.concat(
- versions,
- '\n'
- ),
- nil,
- true,
- false,
- nil,
- mattata.inline_keyboard():row(
- mattata.row():url_button(
- language['shsh']['3'],
- 'https://tsssaver.1conan.com/shsh/download.php?ecid=' .. url.escape(input)
- )
- )
- )
-end
-
-return shsh
\ No newline at end of file
diff --git a/plugins/slap.lua b/plugins/slap.lua
deleted file mode 100644
index 732d6bb..0000000
--- a/plugins/slap.lua
+++ /dev/null
@@ -1,60 +0,0 @@
---[[
- Based on a plugin by topkecleon. Licensed under GNU AGPLv3
- https://github.com/topkecleon/otouto/blob/master/LICENSE.
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local slap = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function slap:init()
- slap.commands = mattata.commands(self.info.username):command('slap').table
- slap.help = '/slap [target] - Slaps someone, or something. Can be used in reply to someone.'
-end
-
-function slap:on_message(message, configuration)
- local input = mattata.input(message)
- local victor, victor_id, victim, victim_id
- local slaps = configuration.slaps
- if message.chat.type ~= 'private' then
- local more = redis:smembers('slaps:' .. message.chat.id)
- if #more > 0 then
- for _, v in pairs(more) do
- table.insert(slaps, v)
- end
- end
- end
- if not input then
- if message.reply then
- victor = message.from.first_name:gsub('%%', '%%%%')
- victor_id = message.from.id
- victim = message.reply.from.first_name:gsub('%%', '%%%%')
- victim_id = message.reply.from.id
- else
- victor = self.info.first_name:gsub('%%', '%%%%')
- victor_id = self.info.id
- victim = message.from.first_name:gsub('%%', '%%%%')
- victim_id = message.from.id
- end
- else
- victor = message.from.first_name:gsub('%%', '%%%%')
- victor_id = message.from.id
- victim = input:gsub('%%', '%%%%')
- victim_id = false
- local success = mattata.get_user(input)
- if success and success.result and success.result.type == 'private' then
- victim = success.result.first_name
- victim = victim:gsub('%%', '%%%%')
- victim_id = success.result.id
- end
- end
- victor = mattata.get_formatted_user(victor_id, victor, 'html')
- victim = victim_id and mattata.get_formatted_user(victim_id, victim, 'html') or mattata.escape_html(victim)
- local output = mattata.escape_html(slaps[math.random(#slaps)])
- output = output:gsub('{THEM}', victim):gsub('{ME}', victor)
- return mattata.send_message(message.chat.id, output, 'html')
-end
-
-return slap
\ No newline at end of file
diff --git a/plugins/sonofabitch.lua b/plugins/sonofabitch.lua
deleted file mode 100644
index f6698bd..0000000
--- a/plugins/sonofabitch.lua
+++ /dev/null
@@ -1,96 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local sonofabitch = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function sonofabitch:init()
- sonofabitch.commands = mattata.commands(self.info.username, { '^[Ss][Oo][Nn] [Oo][Ff] [Aa] [Bb][Ii][Tt][Cc][Hh]$'}):command('sonofabitch').table
- sonofabitch.help = '/sonofabitch - Gracefully creates a clickbait ad using the replied-to person\'s photo.'
-end
-
-function sonofabitch:on_inline_query(inline_query, configuration, language)
- local input = mattata.input(inline_query.query) or inline_query.from.id
- local success = true
- if tonumber(input) == nil then
- input = mattata.get_user(input)
- if not input then
- success = false
- input = inline_query.from.id
- else
- input = input.result.id
- end
- end
- local output = redis:get('sonofabitch:' .. input)
- if not output then
- if success then
- success = mattata.get_user_profile_photos(input)
- end
- if not success or success.result.total_count == 0 then
- return mattata.send_inline_article(inline_query.id, language.errors.generic, 'That user doesn\'t have a profile picture, or I just don\'t have permission to see it!')
- end
- local file_id = success.result.photos[1][#success.result.photos[1]].file_id
- local file = mattata.get_file(file_id)
- if not file then
- return false
- end
- local file_name = file.result.file_path
- local file_path = string.format('https://api.telegram.org/file/bot%s/%s', configuration.bot_token, file_name)
- file = mattata.download_file(file_path, file_name:match('/(.-)$'), configuration.bot_directory)
- if not file then
- return false
- end
- local command = string.format('convert soab.png %s -gravity northwest -geometry +100+250 -composite output.png', file)
- os.execute(command)
- local validate = mattata.send_photo(configuration.log_chat, configuration.bot_directory .. '/output.png')
- if not validate then
- return false
- end
- mattata.delete_message(configuration.log_chat, validate.result.message_id)
- output = validate.result.photo[#validate.result.photo].file_id
- redis:set('sonofabitch:' .. input, output)
- redis:expire('sonofabitch:' .. input, 86400)
- os.execute('rm ' .. file .. ' && rm output.png')
- end
- return mattata.send_inline_cached_photo(inline_query.id, output)
-end
-
-function sonofabitch.on_message(_, message, configuration)
- if not message.reply then
- return false
- end
- local exists = redis:get('sonofabitch:' .. message.reply.from.id)
- if exists then
- return mattata.send_photo(message.chat.id, exists)
- end
- local success = mattata.get_user_profile_photos(message.reply.from.id)
- if not success or success.result.total_count == 0 then
- return mattata.send_reply(message, 'That user doesn\'t have a profile picture, or I just don\'t have permission to see it!')
- end
- local file_id = success.result.photos[1][#success.result.photos[1]].file_id
- local file = mattata.get_file(file_id)
- if not file then
- return false
- end
- local file_name = file.result.file_path
- local file_path = string.format('https://api.telegram.org/file/bot%s/%s', configuration.bot_token, file_name)
- file = mattata.download_file(file_path, file_name:match('/(.-)$'), '/home/matt/matticatebot')
- if not file then
- return false
- end
- local command = string.format('convert soab.png %s -gravity northwest -geometry +100+250 -composite output.png', file)
- os.execute(command)
- local success = mattata.send_photo(message.chat.id, configuration.bot_directory .. '/output.png')
- if not success then
- return false
- end
- redis:set('sonofabitch:' .. message.reply.from.id, success.result.photo[#success.result.photo].file_id)
- redis:expire('sonofabitch:' .. message.reply.from.id, 86400)
- os.execute('rm ' .. file .. ' && rm output.png')
- return success
-end
-
-return sonofabitch
\ No newline at end of file
diff --git a/plugins/spamwatch.lua b/plugins/spamwatch.lua
deleted file mode 100644
index 94f0da8..0000000
--- a/plugins/spamwatch.lua
+++ /dev/null
@@ -1,51 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local spamwatch = {}
-local mattata = require('mattata')
-
-function spamwatch:init()
- spamwatch.commands = mattata.commands(self.info.username):command('spamwatch'):command('sw').table
- spamwatch.help = '/spamwatch [user] - Returns SpamWatch information for the given user, either specified or replied-to. Alias: /sw.'
-end
-
-function spamwatch:on_new_message(message)
- if message.chat.type ~= 'supergroup' then
- return false
- elseif not mattata.get_setting(message.chat.id, 'ban spamwatch users') then
- return false
- elseif self.is_spamwatch_blocklisted then
- mattata.ban_chat_member(message.chat.id, message.from.id)
- end
- return false
-end
-
-function spamwatch:on_message(message)
- local input = message.reply and message.reply.from.id or mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, spamwatch.help)
- end
- local user = mattata.get_user(input)
- if not user then
- if not input:match('^%d+$') then
- return mattata.send_reply(message, 'I couldn\'t get any information about that user. To teach me who they are, forward a message from them. This will only work if they don\'t have forward privacy enabled!')
- end
- user = { ['result'] = { ['id'] = input:match('^(%d+)$') } }
- end
- user = user.result.id
- local res, jdat = mattata.is_spamwatch_blocklisted(user)
- if not res then
- return mattata.send_reply(message, 'That user isn\'t in the SpamWatch database!')
- end
- local output = {
- '<b>ID:</b> ' .. jdat.id,
- '<b>Reason:</b> ' .. mattata.escape_html(jdat.reason),
- '<b>Date banned:</b> ' .. os.date('%x', jdat.date)
- }
- output = table.concat(output, '\n')
- return mattata.send_reply(message, output, 'html')
-end
-
-return spamwatch
\ No newline at end of file
diff --git a/plugins/spotify.lua b/plugins/spotify.lua
deleted file mode 100644
index 522d2fb..0000000
--- a/plugins/spotify.lua
+++ /dev/null
@@ -1,183 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local spotify = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local json = require('dkjson')
-local redis = require('libs.redis')
-local ltn12 = require('ltn12')
-
-function spotify:init()
- spotify.commands = mattata.commands(self.info.username):command('spotify').table
- spotify.help = '/spotify <query> - Searches Spotify for a track matching the given search query and returns the most relevant result.'
-end
-
-function spotify.get_track(jdat)
- if jdat.tracks.total == 0
- then
- return false
- end
- local output = ''
- if jdat.tracks.items[1].name
- then
- if jdat.tracks.items[1].external_urls.spotify
- then
- output = output .. '<b>Song:</b> <a href="' .. jdat.tracks.items[1].external_urls.spotify .. '">' .. mattata.escape_html(jdat.tracks.items[1].name) .. '</a>\n'
- else
- output = output .. '<b>Song:</b> ' .. mattata.escape_html(jdat.tracks.items[1].name) .. '\n'
- end
- end
- if jdat.tracks.items[1].album.name
- then
- if jdat.tracks.items[1].album.external_urls.spotify
- then
- output = output .. '<b>Album:</b> <a href="' .. jdat.tracks.items[1].album.external_urls.spotify .. '">' .. mattata.escape_html(jdat.tracks.items[1].album.name) .. '</a>\n'
- else
- output = output .. '<b>Album:</b> ' .. mattata.escape_html(jdat.tracks.items[1].album.name) .. '\n'
- end
- end
- if jdat.tracks.items[1].album.artists[1].name
- then
- if jdat.tracks.items[1].album.artists[1].external_urls.spotify
- then
- output = output .. '<b>Artist:</b> <a href="' .. jdat.tracks.items[1].album.artists[1].external_urls.spotify .. '">' .. mattata.escape_html(jdat.tracks.items[1].album.artists[1].name) .. '</a>\n'
- else
- output = output .. '<b>Artist:</b> ' .. mattata.escape_html(jdat.tracks.items[1].album.artists[1].name) .. '\n'
- end
- end
- if jdat.tracks.items[1].disc_number
- then
- output = output .. '<b>Disc:</b> ' .. jdat.tracks.items[1].disc_number .. '\n'
- end
- if jdat.tracks.items[1].track_number
- then
- output = output .. '<b>Track:</b> ' .. jdat.tracks.items[1].track_number .. '\n'
- end
- if jdat.tracks.items[1].popularity
- then
- output = output .. '<b>Popularity:</b> ' .. jdat.tracks.items[1].popularity
- end
- return output ~= ''
- and output
- or false
-end
-
-function spotify:on_message(message, configuration, language)
- local input = mattata.input(message.text)
- if not input
- then
- return mattata.send_reply(
- message,
- spotify.help
- )
- elseif not redis:get('spotify:' .. message.from.id .. ':access_token')
- then
- if redis:get('spotify:' .. message.from.id .. ':refresh_token')
- then
- local query = 'grant_type=refresh_token&refresh_token=' .. url.escape(
- redis:get('spotify:' .. message.from.id .. ':refresh_token')
- ) .. '&client_id=' .. configuration['keys']['spotify']['client_id'] .. '&client_secret=' .. configuration['keys']['spotify']['client_secret']
- local wait_message = mattata.send_message(
- message.chat.id,
- 'Re-authorising your Spotify account, please wait...'
- )
- local response = {}
- local _, res = https.request(
- {
- ['url'] = 'https://accounts.spotify.com/api/token',
- ['method'] = 'POST',
- ['headers'] = {
- ['Content-Type'] = 'application/x-www-form-urlencoded',
- ['Content-Length'] = query:len()
- },
- ['source'] = ltn12.source.string(query),
- ['sink'] = ltn12.sink.table(response)
- }
- )
- local jdat = json.decode(
- table.concat(response)
- )
- if res ~= 200
- or not jdat
- or jdat.error
- then
- return mattata.edit_message_text(
- message.chat.id,
- wait_message.result.message_id,
- 'An error occcured whilst re-authorising your Spotify account. Please try again later.'
- )
- end
- redis:set(
- 'spotify:' .. message.from.id .. ':access_token',
- jdat.access_token
- )
- redis:expire(
- 'spotify:' .. message.from.id .. ':access_token',
- 3600
- )
- mattata.edit_message_text(
- message.chat.id,
- wait_message.result.message_id,
- 'Successfully re-authorised your Spotify account! Processing your original request...'
- )
- else
- local success = mattata.send_force_reply(
- message,
- 'You need to authorise mattata in order to connect your Spotify account. Click [here](https://accounts.spotify.com/en/authorize?client_id=' .. url.escape(configuration['keys']['spotify']['client_id']) .. '&response_type=code&redirect_uri=' .. configuration['keys']['spotify']['redirect_uri'] .. '&scope=user-library-read,playlist-read-private,playlist-read-collaborative,user-read-private,user-read-birthdate,user-read-email,user-follow-read,user-top-read,user-read-playback-state,user-read-recently-played,user-read-currently-playing,user-modify-playback-state) and press the green "OKAY" button to link mattata to your Spotify account. After you\'ve done that, send the link you were redirected to (it should begin with "' .. configuration['keys']['spotify']['redirect_uri'] .. '", followed by a unique code) in reply to this message.',
- 'markdown'
- )
- if success
- then
- redis:set(
- string.format(
- 'action:%s:%s',
- message.chat.id,
- success.result.message_id
- ),
- '/authspotify'
- )
- end
- return
- end
- end
- local response = {}
- local _, res = https.request(
- {
- ['url'] = 'https://api.spotify.com/v1/search?q=' .. url.escape(input) .. '&type=track&limit=1',
- ['method'] = 'GET',
- ['headers'] = {
- ['Authorization'] = 'Bearer ' .. redis:get('spotify:' .. message.from.id .. ':access_token')
- },
- ['sink'] = ltn12.sink.table(response)
- }
- )
- if res ~= 200
- then
- return mattata.send_reply(
- message,
- language['errors']['connection']
- )
- end
- local jdat = json.decode(
- table.concat(response)
- )
- local output = spotify.get_track(jdat)
- if not output
- then
- return mattata.send_reply(
- message,
- language['errors']['results']
- )
- end
- return mattata.send_message(
- message.chat.id,
- output,
- 'html'
- )
-end
-
-return spotify
\ No newline at end of file
diff --git a/plugins/stackoverflow.lua b/plugins/stackoverflow.lua
deleted file mode 100644
index 421f90d..0000000
--- a/plugins/stackoverflow.lua
+++ /dev/null
@@ -1,65 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local stackoverflow = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local json = require('dkjson')
-local ltn12 = require('ltn12')
-local zlib = require('zlib')
-local html = require('htmlEntities')
-
-function stackoverflow:init()
- stackoverflow.commands = mattata.commands(self.info.username):command('stackoverflow'):command('so').table
- stackoverflow.help = '/stackoverflow [query] - Returns the first result for the given search query on Stack Overflow. Query can be given by replying to the message you want to search or specifying it as a parameter. Alias: /so.'
- stackoverflow.url = 'https://api.stackexchange.com/2.2/search/advanced?'
-end
-
-function stackoverflow.on_message(_, message, configuration, language)
- local input = message.reply and message.reply.text or mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, stackoverflow.help)
- elseif message.reply then
- message.message_id = message.reply.message_id
- end
- local query = 'order=desc&sort=relevance&site=stackoverflow&q=' .. url.escape(input)
- local response = {}
- local _, res = https.request({
- ['url'] = stackoverflow.url .. query,
- ['method'] = 'GET',
- ['headers'] = {
- ['Content-Type'] = 'application/json',
- ['Content-Length'] = query:len(),
- ['Accept-Encoding'] = 'gzip'
- },
- ['source'] = ltn12.source.string(input),
- ['sink'] = ltn12.sink.table(response)
- })
- if res ~= 200 then
- return mattata.send_reply(message, language.errors.connection)
- end
- local jstr = table.concat(response)
- jstr = zlib.decompress(jstr, 31)
- local jdat = json.decode(jstr)
- if not jdat.items or not jdat.items[1] then
- return mattata.send_reply(message, language.errors.results)
- end
- local limit = message.chat.type == 'private' and configuration.limits.stackoverflow.private or configuration.limits.stackoverflow.public
- local results = { '<b>Results for:</b> <em>' .. mattata.escape_html(input) .. '</em>' }
- local count = 0
- for i = 1, limit do
- if i > #jdat.items then
- break
- end
- local result = string.format('%s <a href="%s">%s</a>', mattata.symbols.bullet, jdat.items[i].link, mattata.escape_html(html.decode(jdat.items[i].title)))
- table.insert(results, result)
- count = count + 1
- end
- local output = table.concat(results, '\n')
- return mattata.send_reply(message, output, 'html', true)
-end
-
-return stackoverflow
\ No newline at end of file
diff --git a/plugins/statistics.lua b/plugins/statistics.lua
deleted file mode 100644
index 80bed42..0000000
--- a/plugins/statistics.lua
+++ /dev/null
@@ -1,102 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local statistics = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function statistics:init()
- statistics.commands = mattata.commands(self.info.username):command('statistics'):command('stats'):command('morestats').table
- statistics.help = '/statistics - Shows statistical information about the current chat\'s top ten users (ordered by message count). Send /morestats to view the top 50 users. Alias: /stats.'
-end
-
-function statistics.reset_message_statistics(chat_id)
- if not chat_id or tonumber(chat_id) == nil then
- return false
- end
- local messages = redis:keys('messages:*:' .. chat_id)
- if not next(messages) then
- return false
- end
- for _, v in pairs(messages) do
- redis:del(v)
- end
- return true
-end
-
-function statistics.get_user_message_statistics(user_id, chat_id)
- return {
- ['messages'] = tonumber(redis:get('messages:' .. user_id .. ':' .. chat_id)) or 0,
- ['name'] = redis:hget('user:' .. user_id .. ':info', 'first_name'),
- ['id'] = user_id
- }
-end
-
-function statistics.get_message_statistics(message, language, more)
- if not message or not language then
- return language['errors']['generic']
- end
- local users = redis:smembers('chat:' .. message.chat.id .. ':users')
- local user_info = {}
- for i = 1, #users do
- local user = statistics.get_user_message_statistics(users[i], message.chat.id)
- if user.name and user.name ~= '' and user.messages > 0 then
- table.insert(user_info, user)
- end
- end
- table.sort(user_info, function(a, b)
- if a.messages and b.messages then
- return a.messages > b.messages
- end
- end)
- local total = 0
- for n, _ in pairs(user_info) do
- local message_count = user_info[n].messages
- total = total + message_count
- end
- local text = ''
- local output = {}
- local amount = more and 50 or 10
- for i = 1, amount do
- if i <= #user_info then
- table.insert(output, user_info[i])
- else
- break
- end
- end
- local count = 0
- for _, v in pairs(output) do
- count = count + 1
- local message_count = v.messages
- local percent = tostring(mattata.round((message_count / total) * 100, 1))
- text = text .. count .. '. ' .. mattata.get_formatted_user(v.id, v.name, 'html') .. ': <b>' .. mattata.comma_value(message_count) .. '</b> [' .. percent .. '%]\n'
- end
- text = text .. string.format('\n<em>I have seen %s/%s users in this group</em>', #redis:smembers('chat:' .. message.chat.id .. ':users'), mattata.get_chat_members_count(message.chat.id).result)
- return string.format(language['statistics']['2'], mattata.escape_html(message.chat.title), text, mattata.comma_value(total))
-end
-
-function statistics:on_message(message, _, language)
- if message.chat.type == 'private' then
- return false
- end
- local input = mattata.input(message.text)
- local output
- if input and input:lower() == 'reset' and mattata.is_group_admin(message.chat.id, message.from.id, true) then
- output = statistics.reset_message_statistics(message.chat.id) and language['statistics']['3'] or language['statistics']['4']
- return mattata.send_message(message.chat.id, output)
- end
- local more = message.text:match('^[/!#]morestats') and true or false
- output = statistics.get_message_statistics(message, language, more)
- if more then
- local success = mattata.send_message(message.from.id, output, 'html')
- if not success then
- return mattata.send_reply(message, 'Please [start a conversation with me](https://t.me/' .. self.info.username:lower() .. ') and try this command again!', true, true)
- end
- return mattata.send_reply(message, 'I\'ve sent you this information [via private chat](https://t.me/' .. self.info.username:lower() .. ')!', true, true)
- end
- return mattata.send_message(message.chat.id, output, 'html', true, true, true)
-end
-
-return statistics
\ No newline at end of file
diff --git a/plugins/steam.lua b/plugins/steam.lua
deleted file mode 100644
index 9b291aa..0000000
--- a/plugins/steam.lua
+++ /dev/null
@@ -1,191 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local steam = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local http = require('socket.http')
-local url = require('socket.url')
-local json = require('dkjson')
-local redis = require('libs.redis')
-
-function steam:init()
- steam.commands = mattata.commands(self.info.username)
- :command('steam')
- :command('setsteam').table
- steam.help = '/steam [username] - Displays information about the given Steam user. If no username is specified then information about your Steam account (if applicable) is sent.'
-end
-
-function steam.search(input, key)
- local jstr, res = https.request('https://steamcommunity.com/id/' .. url.escape(input))
- if res ~= 200
- then
- return false, true
- end
- jstr = jstr:match('g%_rgProfileData %= (.-)%;')
- if not jstr or not jstr:match('^%{.-%}$')
- then
- return true, false
- end
- local jdat = json.decode(jstr)
- if not jdat
- or not jdat.steamid
- then
- return true, false
- end
- return steam.get_info(
- jdat.steamid,
- key
- ), true
-end
-
-function steam.get_info(id, key)
- local jstr, res = http.request('http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=' .. key .. '&steamids=' .. id)
- if res ~= 200
- then
- return false
- end
- return jstr
-end
-
-function steam.get_username(id)
- return redis:hget(
- 'steam:' .. id,
- 'username'
- )
-end
-
-function steam.set_username(message, language)
- local input = mattata.input(message.text)
- if not input
- then
- return mattata.send_reply(
- message,
- steam.help
- )
- end
- redis:hset(
- 'steam:' .. message.from.id,
- 'username',
- input
- )
- return mattata.send_reply(
- message,
- string.format(
- language['steam']['1'],
- input
- )
- )
-end
-
-function steam.format_output(jdat, language)
- if not jdat.response
- or not jdat.response.players
- or not jdat.response.players[1]
- then
- return false
- end
- local name = mattata.escape_html(jdat.response.players[1].personaname)
- if jdat.response.players[1].realname
- then
- name = mattata.escape_html(jdat.response.players[1].realname)
- end
- name = string.format(
- '<a href="%s">%s</a>',
- jdat.response.players[1].avatarfull,
- name
- )
- if jdat.response.players[1].realname
- and jdat.response.players[1].realname ~= jdat.response.players[1].personaname
- then
- name = string.format(
- language['steam']['4'],
- name,
- jdat.response.players[1].personaname
- )
- end
- local output = string.format(
- language['steam']['3'],
- name,
- os.date('%X', jdat.response.players[1].timecreated),
- os.date('%x', jdat.response.players[1].timecreated),
- os.date('%X', jdat.response.players[1].lastlogoff),
- os.date('%x', jdat.response.players[1].lastlogoff),
- jdat.response.players[1].profileurl
- )
- if not output
- then
- return false
- end
- return output
-end
-
-function steam:on_message(message, configuration, language)
- if message.text:match('^%/se')
- then
- return steam.set_username(
- message,
- language
- )
- end
- local input = mattata.input(message.text)
- if not input
- and not steam.get_username(message.from.id)
- then
- return mattata.send_reply(
- message,
- steam.help
- )
- elseif not input
- then
- input = steam.get_username(message.from.id)
- end
- if input:match('^%@.-$')
- then
- input = input:match('^%@(.-)$')
- end
- local output, res = steam.search(
- input,
- configuration.keys.steam
- )
- if not output
- then
- return mattata.send_reply(
- message,
- language['errors']['connection']
- )
- elseif not res
- then
- return mattata.send_reply(
- message,
- string.format(
- language['steam']['2'],
- input
- )
- )
- end
- output = steam.format_output(
- json.decode(output),
- language
- )
- if not output
- then
- return mattata.send_reply(
- message,
- string.format(
- language['steam']['2'],
- input
- )
- )
- end
- return mattata.send_message(
- message.chat.id,
- output,
- 'html',
- false
- )
-end
-
-return steam
\ No newline at end of file
diff --git a/plugins/time.lua b/plugins/time.lua
deleted file mode 100644
index d832fa6..0000000
--- a/plugins/time.lua
+++ /dev/null
@@ -1,71 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local time = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local json = require('dkjson')
-local setloc = require('plugins.setloc')
-local redis = require('libs.redis')
-
-function time:init()
- time.commands = mattata.commands(self.info.username):command('time'):command('t'):command('d'):command('date').table
- time.help = '/time [query] - Sends your time, or the time for the given location. Aliases: /t, /d, /date.'
-end
-
-function time:on_message(message, configuration, language)
- local input = mattata.input(message.text:lower())
- local location = false
- if message.reply and not input then -- If it's used in reply to someone, we want their time instead.
- message.from = message.reply.from
- end
- if not input and not setloc.get_loc(message.from.id) then
- local success = mattata.send_force_reply(message, 'Please specify the location you would like to get the time for:')
- if success then
- local action = mattata.command_action(message.chat.id, success.result.message_id)
- redis:set(action, '/time')
- end
- return
- elseif not input then
- location = setloc.get_loc(message.from.id)
- if location then
- location = json.decode(location)
- end
- end
- if not location then
- local jstr, res = https.request('https://api.opencagedata.com/geocode/v1/json?key=' .. configuration.keys.location .. '&pretty=0&q=' .. url.escape(input))
- if res ~= 200 then
- return mattata.send_reply(message, language.errors.connection)
- end
- local jdat = json.decode(jstr)
- if jdat.total_results == 0 then
- return mattata.send_reply(message, language.errors.results)
- end
- location = {
- ['latitude'] = jdat.results[1].geometry.lat,
- ['longitude'] = jdat.results[1].geometry.lng,
- ['address'] = jdat.results[1].formatted
- }
- end
- local formatted_location = string.format('%s,%s', location.latitude, location.longitude)
- local jstr, res = https.request('https://maps.googleapis.com/maps/api/timezone/json?location=' .. formatted_location .. '&timestamp=' .. os.time() .. '&key=' .. configuration.keys.maps)
- if res ~= 200 then
- return mattata.send_reply(message, language.errors.connection)
- end
- local jdat = json.decode(jstr)
- if jdat.errorMessage then
- local output = string.format('Error `%s: %s`', jdat.status, jdat.errorMessage)
- return mattata.send_message(message, output, true)
- end
- local offset = os.time() + tonumber(jdat.rawOffset) + tonumber(jdat.dstOffset)
- local current = os.date('%c', offset)
- current = current:gsub('^(%w+ %w+ %d*) (%d*:%d*:%d*) (%d+)$', '%2</b> on <b>%1 %3') -- We want the time first!
- local output = 'It is currently <b>%s</b> <code>[%s]</code> in %s.'
- output = string.format(output, current, jdat.timeZoneName, location.address)
- return mattata.send_reply(message, output, 'html')
-end
-
-return time
diff --git a/plugins/todo.lua b/plugins/todo.lua
deleted file mode 100644
index 9fe2050..0000000
--- a/plugins/todo.lua
+++ /dev/null
@@ -1,111 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local todo = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function todo:init()
- todo.commands = mattata.commands(self.info.username):command('todo').table
- todo.help = '/todo [text] - If no arguments are given, allows you to view your to-do list. Otherwise, it adds the given'
-end
-
-function todo.get_keyboard(all)
- if not all or #all == 0 then
- return false
- end
- local keyboard = {
- ['inline_keyboard'] = {}
- }
- for pos, item in pairs(all) do
- if item:len() > 69 then -- Max text for buttons is 69.
- item = item:sub(1, 69)
- end
- table.insert(keyboard.inline_keyboard, {{
- ['text'] = item,
- ['callback_data'] = 'todo:' .. pos .. ':view'
- }, {
- ['text'] = utf8.char(9989),
- ['callback_data'] = 'todo:' .. pos .. ':done'
- }})
- end
- return keyboard
-end
-
-function todo.on_callback_query(_, callback_query, message, _, language)
- if message.chat.type == 'supergroup' and not mattata.is_group_admin(message.chat.id, callback_query.from.id) then
- return mattata.answer_callback_query(callback_query.id, language.errors.admin)
- end
- local existing = redis:smembers('todo:' .. message.chat.id)
- if not next(existing) then
- return mattata.edit_message_text(message.chat.id, message.message_id, 'You\'ve got nothing to-do! For now...')
- end
- local pos, action = callback_query.data:match('^(%d*):(%a+)$')
- pos = math.floor(tonumber(pos))
- if not existing[pos] then
- mattata.answer_callback_query(callback_query.id, 'It appears this to-do has already been completed!')
- local keyboard = todo.get_keyboard(existing)
- return mattata.edit_message_reply_markup(message.chat.id, message.message_id, nil, keyboard)
- end
- if action == 'view' then
- return mattata.answer_callback_query(callback_query.id, existing[pos], true)
- elseif action == 'done' then
- redis:srem('todo:' .. (message.chat.id or message.from.id), existing[pos])
- mattata.answer_callback_query(callback_query.id, 'I\'ve marked that to-do as completed!')
- if #existing == 1 then
- return mattata.edit_message_text(message.chat.id, message.message_id, 'You don\'t have any to-dos at the moment. Add one using /todo [text].')
- end
- existing = redis:smembers('todo:' .. message.chat.id)
- local keyboard = todo.get_keyboard(existing)
- return mattata.edit_message_reply_markup(message.chat.id, message.message_id, nil, keyboard)
- end
- return false
-end
-
-
-function todo.on_message(_, message, _, language)
- local input = mattata.input(message.text)
- if input then
- input = { input }
- end
- if input and input[1]:match('\n') then
- local new = {}
- for line in input[1]:gmatch('([^\n]*)\n?') do
- if line:gsub('%s', '') ~= '' then
- table.insert(new, line)
- end
- end
- if #new >= 1 then
- input = new
- end
- end
- if message.chat.type == 'supergroup' and not mattata.is_group_admin(message.chat.id, message.from.id) then
- return mattata.send_reply(message, language.errors.admin)
- end
- local existing = redis:smembers('todo:' .. message.chat.id)
- if not input then
- if not next(existing) then
- return mattata.send_reply(message, 'You don\'t have any to-dos at the moment. Add one using /todo [text].')
- end
- local keyboard = todo.get_keyboard(existing)
- local output = 'Here is your current to-do list'
- if message.chat.type == 'supergroup' then
- output = output .. ' for ' .. message.chat.title .. '. To view your personal to-do list, send this command to me in private chat!'
- else output = output .. ':' end
- return mattata.send_message(message.chat.id, output, nil, true, false, nil, keyboard)
- end
- for _, line in pairs(input) do
- if #existing == 50 then
- return mattata.send_reply(message, 'Wow, you\'ve got a lot to do! But I\'m afraid you can\'t have more than 50 to-dos! Mark one as done and try this command again.')
- elseif line:len() > 200 then
- return mattata.send_reply(message, 'To-dos can\'t be longer than 200 characters!')
- end
- redis:sadd('todo:' .. message.chat.id, line)
- existing = redis:smembers('todo:' .. message.chat.id)
- end
- return mattata.send_reply(message, 'I\'ve added that on your to-do list!')
-end
-
-return todo
diff --git a/plugins/totalquotes.lua b/plugins/totalquotes.lua
deleted file mode 100644
index 241a776..0000000
--- a/plugins/totalquotes.lua
+++ /dev/null
@@ -1,28 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local totalquotes = {}
-local mattata = require('mattata')
-local redis = require('libs.redis')
-
-function totalquotes:init()
- totalquotes.commands = mattata.commands(self.info.username):command('totalquotes').table
- totalquotes.help = '/totalquotes - View the total number of quotes saved in the current chat.'
-end
-
-function totalquotes.on_message(_, message)
- if message.chat.type == 'private' then
- return false
- end
- local users = mattata.get_chat_members(message.chat.id)
- local total = 0
- for _, user in pairs(users) do
- local quotes = redis:smembers('user:' .. user .. ':quotes')
- total = total + #quotes
- end
- return mattata.send_reply(message, 'A total of ' .. total .. ' messages have been quoted here! To view your own quotes, send /quotes. To quote someone, use /quote in reply to one of their messages. To add a quote to the database, use /save in reply to one of their messages.')
-end
-
-return totalquotes
\ No newline at end of file
diff --git a/plugins/transcribe.lua b/plugins/transcribe.lua
deleted file mode 100644
index 9396844..0000000
--- a/plugins/transcribe.lua
+++ /dev/null
@@ -1,47 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local transcribe = {}
-local mattata = require('mattata')
-local json = require('dkjson')
-local redis = require('libs.redis')
-
-function transcribe:init()
- transcribe.commands = mattata.commands(self.info.username):command('transcribe'):command('tts').table
- transcribe.help = '/transcribe - Transcribes the replied-to voice message using wit.ai. Alias: /tts.'
-end
-
-function transcribe.is_valid(message)
- local voice = message.reply and message.reply.voice or message.voice
- if voice.mime_type ~= 'audio/ogg' then
- return false
- elseif voice.duration > 20 then
- return false
- elseif voice.file_size >= 20000000 then
- return false
- end
- return true
-end
-
-function transcribe.on_new_message(_, message)
- if message.chat.type == 'private' or not message.voice or not transcribe.is_valid(message) then
- return false
- end
- redis:set('transcribe:' .. message.chat.id .. ':' .. message.message_id, json.encode(message))
- return
- end
-
- function transcribe.on_message(_, message)
- if not message.reply then
- return mattata.send_reply(message, transcribe.help)
- elseif not message.reply.voice then
- return mattata.send_reply(message, 'You can only use this message in reply to voice messages!')
- elseif not transcribe.is_valid(message) then
- return mattata.send_reply(message, 'The voice message must meet the following conditions:\n1. It must be 20 seconds or less in length\n2. It must be 20MB or less in file size\n3. It must be of the audio/ogg MIME type')
- end
- return redis:set('transcribe:' .. message.chat.id .. ':' .. message.message_id, json.encode(message.reply))
-end
-
-return transcribe
\ No newline at end of file
diff --git a/plugins/translate.lua b/plugins/translate.lua
deleted file mode 100644
index 5597985..0000000
--- a/plugins/translate.lua
+++ /dev/null
@@ -1,79 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local translate = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local json = require('dkjson')
-
-function translate:init()
- translate.commands = mattata.commands(self.info.username):command('translate'):command('tl').table
- translate.help = [[/translate [locale] <text> - If a locale is given, the given text is translated into the said locale's language. If no locale is given then the given text is translated into the bot's configured language. If the command is used in reply to a message containing text, then the replied-to text is translated and the translation is returned. Alias: /tl.]]
-end
-
-function translate:on_inline_query(inline_query, configuration)
- local input = mattata.input(inline_query.query)
- if not input then
- return
- end
- local lang
- if not mattata.get_word(input) or mattata.get_word(input):len() > 2 then
- lang = configuration.language
- else
- lang = mattata.get_word(input)
- end
- local jstr, res = https.request('https://translate.yandex.net/api/v1.5/tr.json/translate?key=' .. configuration.keys.translate .. '&lang=' .. lang .. '&text=' .. url.escape(input:gsub(lang .. ' ', '')))
- if res ~= 200 then
- return
- end
- local jdat = json.decode(jstr)
- return mattata.answer_inline_query(
- inline_query.id,
- json.encode(
- {
- {
- ['type'] = 'article',
- ['id'] = '1',
- ['title'] = jdat.text[1],
- ['description'] = 'Click to send your translation.',
- ['input_message_content'] = {
- ['message_text'] = jdat.text[1]
- }
- }
- }
- )
- )
-end
-
-function translate:on_message(message, configuration, language)
- local input = mattata.input(message.text)
- local lang = mattata.get_user_language(message.from.id):match('^(..)')
- if message.reply then
- if input and input:match('^%a%a$') then
- lang = input
- end
- input = message.reply.text
- elseif not input then
- return mattata.send_reply(message, translate.help)
- elseif input:match('^%a%a .-$') then
- lang, input = input:match('^(%a%a) (.-)$')
- end
- local jstr, res = https.request('https://translate.yandex.net/api/v1.5/tr.json/translate?key=' .. configuration.keys.translate .. '&lang=' .. lang .. '&text=' .. url.escape(input))
- if res ~= 200 then
- return mattata.send_reply(message, language.errors.connection)
- elseif message.reply then
- mattata.delete_message(message.chat.id, message.message_id)
- message.message_id = message.reply.message_id
- end
- local jdat = json.decode(jstr)
- return mattata.send_reply(
- message,
- '<b>Translation (from ' .. jdat.lang:gsub('%-', ' to ') .. '):</b>\n' .. mattata.escape_html(jdat.text[1]),
- 'html'
- )
-end
-
-return translate
\ No newline at end of file
diff --git a/plugins/twitch.lua b/plugins/twitch.lua
deleted file mode 100644
index 37f6e6a..0000000
--- a/plugins/twitch.lua
+++ /dev/null
@@ -1,165 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local twitch = {}
-
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local json = require('dkjson')
-local configuration = require('configuration')
-
-function twitch:init()
- twitch.commands = mattata.commands(
- self.info.username
- ):command('twitch').table
- twitch.help = [[/twitch <query> - Searches Twitch for the given search query and returns the most relevant result(s).]]
-end
-
-function twitch.get_result_count(input)
- local jstr, res = https.request('https://api.twitch.tv/kraken/search/streams?q=' .. url.escape(input) .. '&client_id=' .. configuration.keys.twitch)
- if res ~= 200 then
- return 0
- end
- local jdat = json.decode(jstr)
- if jdat._total == 0 then
- return 0
- end
- return #jdat.streams
-end
-
-function twitch.get_result(input, n)
- n = n or 1
- local jstr, res = https.request('https://api.twitch.tv/kraken/search/streams?q=' .. url.escape(input) .. '&client_id=' .. configuration.keys.twitch)
- if res ~= 200 then
- return false
- end
- local jdat = json.decode(jstr)
- if jdat._total == 0 then
- return false
- end
- local output = ''
- if jdat.streams[n].channel.url and jdat.streams[n].channel.display_name then
- output = output .. '<a href="' .. jdat.streams[n].channel.url .. '">' .. mattata.escape_html(jdat.streams[n].channel.display_name) .. '</a>\n'
- end
- if jdat.streams[n].channel.game then
- output = output .. '🎮 ' .. mattata.escape_html(jdat.streams[n].channel.game) .. '\n'
- end
- if jdat.streams[n].viewers then
- output = output .. '👁 ' .. mattata.comma_value(tostring(jdat.streams[n].viewers)) .. '\n'
- end
- if jdat.streams[n].video_height then
- output = output .. '🖥 ' .. jdat.streams[n].video_height .. 'p'
- if jdat.streams[n].average_fps then
- output = output .. ', ' .. mattata.round(jdat.streams[n].average_fps) .. ' FPS'
- end
- end
- return output
-end
-
-function twitch:on_callback_query(callback_query, message, configuration)
- if callback_query.data:match('^results:(.-)$') then
- local result = callback_query.data:match('^results:(.-)$')
- local input = mattata.input(message.reply.text)
- local total_results = twitch.get_result_count(input)
- if tonumber(result) > tonumber(total_results) then
- result = 1
- elseif tonumber(result) < 1 then
- result = tonumber(total_results)
- end
- local output = twitch.get_result(
- input,
- tonumber(result)
- )
- if not output then
- return mattata.answer_callback_query(
- callback_query.id,
- 'An error occured!'
- )
- end
- local previous_result = 'twitch:results:' .. math.floor(tonumber(result) - 1)
- local next_result = 'twitch:results:' .. math.floor(tonumber(result) + 1)
- local keyboard = {}
- keyboard.inline_keyboard = {
- {
- {
- ['text'] = '← Previous',
- ['callback_data'] = previous_result
- },
- {
- ['text'] = result .. '/' .. total_results,
- ['callback_data'] = 'twitch:pages:' .. result
- },
- {
- ['text'] = 'Next →️',
- ['callback_data'] = next_result
- }
- }
- }
- return mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- output,
- 'html',
- true,
- json.encode(keyboard)
- )
- elseif callback_query.data:match('^pages:(.-):(.-)$') then
- local current, total = callback_query.data:match('^pages:(.-):(.-)$')
- return mattata.answer_callback_query(
- callback_query.id,
- string.format(
- 'You are on page %s of %s!',
- tostring(current),
- tostring(total)
- )
- )
- end
-end
-
-function twitch:on_message(message, configuration)
- local input = mattata.input(message.text)
- if not input then
- return mattata.send_reply(
- message,
- twitch.help
- )
- end
- local output = twitch.get_result(input)
- if not output then
- return mattata.send_reply(
- message,
- configuration.errors.results
- )
- end
- local keyboard = {}
- keyboard.inline_keyboard = {
- {
- {
- ['text'] = '← Previous',
- ['callback_data'] = 'twitch:results:0'
- },
- {
- ['text'] = '1/' .. twitch.get_result_count(input),
- ['callback_data'] = 'twitch:pages:1:' .. twitch.get_result_count(input)
- },
- {
- ['text'] = 'Next →️',
- ['callback_data'] = 'twitch:results:2'
- }
- }
- }
- return mattata.send_message(
- message.chat.id,
- output,
- 'html',
- true,
- false,
- message.message_id,
- json.encode(keyboard)
- )
-end
-
-return twitch
\ No newline at end of file
diff --git a/plugins/upload.lua b/plugins/upload.lua
deleted file mode 100644
index f13e3c4..0000000
--- a/plugins/upload.lua
+++ /dev/null
@@ -1,63 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local upload = {}
-local mattata = require('mattata')
-
-function upload:init()
- upload.commands = mattata.commands(self.info.username):command('upload').table
-end
-
-function upload:on_message(message, configuration, language)
- if not mattata.is_global_admin(message.from.id)
- then
- return
- elseif not message.reply
- or not message.reply.document
- then
- return mattata.send_reply(
- message,
- language['upload']['1']
- )
- elseif tonumber(message.reply.document.file_size) > 20971520
- then
- return mattata.send_reply(
- message,
- language['upload']['2']
- )
- end
- local file = mattata.get_file(message.reply.document.file_id)
- if not file
- or not file.result
- or not file.result.file_path
- then
- return mattata.send_reply(
- message,
- language['upload']['3']
- )
- end
- local success = mattata.download_file(
- 'https://api.telegram.org/file/bot' .. configuration.bot_token .. '/' .. file.result.file_path,
- message.reply.document.file_name,
- configuration['download_location']
- )
- if not success
- then
- return mattata.send_reply(
- message,
- language['upload']['4']
- )
- end
- return mattata.send_reply(
- message,
- string.format(
- language['upload']['5'],
- mattata.escape_html(configuration['download_location'] .. message.reply.document.file_name)
- ),
- 'html'
- )
-end
-
-return upload
\ No newline at end of file
diff --git a/plugins/urbandictionary.lua b/plugins/urbandictionary.lua
deleted file mode 100644
index 17d4ea2..0000000
--- a/plugins/urbandictionary.lua
+++ /dev/null
@@ -1,225 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local urbandictionary = {}
-
-local mattata = require('mattata')
-local http = require('socket.http')
-local url = require('socket.url')
-local json = require('dkjson')
-local redis = require('libs.redis')
-
-function urbandictionary:init()
- urbandictionary.commands = mattata.commands(
- self.info.username
- ):command('urbandictionary')
- :command('urban')
- :command('ud').table
- urbandictionary.help = [[/urbandictionary <query> - Searches the Urban Dictionary for the given search query and returns the most relevant result(s). Aliases: /urban, /ud.]]
-end
-
-function urbandictionary:on_inline_query(inline_query, configuration)
- local input = mattata.input(inline_query.query)
- if not input then
- return
- end
- local jstr, res = http.request('http://api.urbandictionary.com/v0/define?term=' .. url.escape(input))
- if res ~= 200 then
- return
- end
- local jdat = json.decode(jstr)
- if #jdat.list == 0 then
- return
- end
- local results = {}
- local id = 1
- for n in pairs(jdat.list) do
- table.insert(
- results,
- {
- ['type'] = 'article',
- ['id'] = tostring(id),
- ['title'] = jdat.list[n].word,
- ['description'] = jdat.list[n].definition,
- ['input_message_content'] = {
- ['message_text'] = '<b>' .. mattata.escape_html(jdat.list[n].word) .. '</b>\n\n' .. mattata.escape_html(jdat.list[n].definition),
- ['parse_mode'] = 'html'
- }
- }
- )
- id = id + 1
- end
- return mattata.answer_inline_query(
- inline_query.id,
- json.encode(results)
- )
-end
-
-function urbandictionary.get_result_count(input)
- local jstr, res = http.request('http://api.urbandictionary.com/v0/define?term=' .. url.escape(input))
- if res ~= 200 then
- return 0
- end
- local jdat = json.decode(jstr)
- if jdat.result_type == 'no_results' then
- return 0
- end
- return #jdat.list
-end
-
-function urbandictionary.get_result(input, n)
- n = n or 1
- local jstr, res = http.request('http://api.urbandictionary.com/v0/define?term=' .. url.escape(input))
- if res ~= 200 then
- return false, false
- end
- local jdat = json.decode(jstr)
- if jdat.result_type == 'no_results' then
- return false, false
- elseif not jdat.list or #jdat.list == 0 then
- return false, false
- elseif not jdat.list[n].example then
- return false, false
- end
- local definition = mattata.escape_html(jdat.list[n].definition)
- definition = definition:gsub('%[word%](.-)%[%/word%]', '<a href="https://www.urbandictionary.com/define.php?term=%1">%1</a>'):gsub('%[(.-)%]', '<a href="https://www.urbandictionary.com/define.php?term=%1">%1</a>')
- local output = '<b>' .. jdat.list[n].word .. '</b>\n\n' .. mattata.trim(definition)
- local example = mattata.escape_html(jdat.list[n].example):gsub('%[word%]', ''):gsub('%[%/word%]', '')
- local thumbs_up = '👍 ' .. jdat.list[n].thumbs_up
- local thumbs_down = '👎 ' .. jdat.list[n].thumbs_down
- local author = '💁 ' .. '<a href="https://www.urbandictionary.com/author.php?author=' .. url.escape(jdat.list[n].author) .. '">' .. mattata.escape_html(jdat.list[n].author) .. '</a>'
- return output .. '\n\n<i>' .. mattata.trim(example) .. '</i>\n\n' .. thumbs_up .. ' | ' .. thumbs_down .. ' | ' .. author, jdat.list[n].defid
-end
-
-function urbandictionary:on_callback_query(callback_query, message, configuration)
- if not message.reply then
- return
- end
- if callback_query.data:match('^results:(%d*)$') then
- local result = callback_query.data:match('^results:(%d*)$')
- local input = mattata.input(message.reply.text)
- local total_results = urbandictionary.get_result_count(input)
- if tonumber(result) > tonumber(total_results) then
- result = 1
- elseif tonumber(result) < 1 then
- result = tonumber(total_results)
- end
- local output, def_id = urbandictionary.get_result(
- input,
- tonumber(result)
- )
- if not output then
- return mattata.answer_callback_query(
- callback_query.id,
- 'An error occured!'
- )
- end
- local previous_result = 'urbandictionary:results:' .. math.floor(tonumber(result) - 1)
- local next_result = 'urbandictionary:results:' .. math.floor(tonumber(result) + 1)
- local keyboard = {}
- keyboard.inline_keyboard = {
- {
- {
- ['text'] = '← Previous',
- ['callback_data'] = previous_result
- },
- {
- ['text'] = result .. '/' .. total_results,
- ['callback_data'] = 'urbandictionary:pages:' .. result .. ':' .. total_results
- },
- {
- ['text'] = 'Next →',
- ['callback_data'] = next_result
- }
- },
- {
- {
- ['text'] = 'Get this definition on a mug!',
- ['url'] = 'https://urbandictionary.store/products/mug?defid=' .. def_id
- }
- }
- }
- return mattata.edit_message_text(
- message.chat.id,
- message.message_id,
- output,
- 'html',
- true,
- json.encode(keyboard)
- )
- elseif callback_query.data:match('^pages:(.-):(.-)$') then
- local current, total = callback_query.data:match('^pages:(.-):(.-)$')
- return mattata.answer_callback_query(
- callback_query.id,
- string.format(
- 'You are on page %s of %s!',
- tostring(current),
- tostring(total)
- )
- )
- end
-end
-
-function urbandictionary:on_message(message, configuration)
- local input = mattata.input(message.text)
- if not input then
- local success = mattata.send_force_reply(
- message,
- 'Please enter a search query (that is, what you want me to search the Urban Dictionary for, i.e. "1337" will return Urban Dictionary\'s definition(s) of 1337).'
- )
- if success then
- redis:set(
- string.format(
- 'action:%s:%s',
- message.chat.id,
- success.result.message_id
- ),
- '/urbandictionary'
- )
- end
- return
- end
- local output, def_id = urbandictionary.get_result(input)
- if not output then
- return mattata.send_reply(
- message,
- configuration.errors.results
- )
- end
- local keyboard = {}
- keyboard.inline_keyboard = {
- {
- {
- ['text'] = '← Previous',
- ['callback_data'] = 'urbandictionary:results:0'
- },
- {
- ['text'] = '1/' .. urbandictionary.get_result_count(input),
- ['callback_data'] = 'urbandictionary:pages:1:' .. urbandictionary.get_result_count(input)
- },
- {
- ['text'] = 'Next →',
- ['callback_data'] = 'urbandictionary:results:2'
- },
- },
- {
- {
- ['text'] = 'Get this definition on a mug!',
- ['url'] = 'https://urbandictionary.store/products/mug?defid=' .. def_id
- }
- }
- }
- return mattata.send_message(
- message.chat.id,
- output,
- 'html',
- true,
- false,
- message.message_id,
- json.encode(keyboard)
- )
-end
-
-return urbandictionary
\ No newline at end of file
diff --git a/plugins/weather.lua b/plugins/weather.lua
deleted file mode 100644
index c868651..0000000
--- a/plugins/weather.lua
+++ /dev/null
@@ -1,100 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local weather = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local json = require('dkjson')
-local setloc = require('plugins.setloc')
-
-function weather:init()
- weather.commands = mattata.commands(self.info.username):command('weather').table
- weather.help = '/weather [location] - If no arguments are given, the weather forecast for your known location is given. If a location is given, then the weather forecast for that location is given instead.'
-end
-
-function weather.format_temperature(temperature, units)
- temperature = tonumber(temperature)
- if units ~= 'us'
- then
- return temperature .. '°C/' .. string.format(
- '%.2f',
- temperature * 9 / 5 + 32
- ) .. '°F'
- else
- return temperature .. '°F/' .. string.format(
- '%.2f',
- (temperature - 32) * 5 / 9
- ) .. '°C'
- end
-end
-
-function weather.get_weather(input, configuration)
- local url = 'https://api.opencagedata.com/geocode/v1/json?key=' .. configuration['keys']['location'] .. '&pretty=0&q=' .. url.escape(input)
- local jstr, res = https.request(url)
- if res ~= 200
- then
- return false, false, false
- end
- local jdat = json.decode(jstr)
- if jdat.total_results == 0 then
- return true, false, false
- end
- return jdat.results[1].geometry.lat, jdat.results[1].geometry.lng, jdat.results[1].formatted
-end
-
-function weather:on_message(message, configuration, language)
- local input = mattata.input(message.text)
- local latitude, longitude, address
- if not input
- then
- local location = setloc.get_loc(message.from.id)
- if not location
- then
- return mattata.send_reply(
- message,
- language['weather']['1']
- )
- end
- latitude, longitude, address = json.decode(location).latitude, json.decode(location).longitude, json.decode(location).address
- else
- latitude, longitude, address = weather.get_weather(input, configuration)
- if not latitude
- or not longitude
- then
- return mattata.send_reply(
- message,
- language['errors']['results']
- )
- end
- end
- local jstr, res = https.request('https://api.darksky.net/forecast/' .. configuration.keys.weather .. '/' .. latitude .. ',' .. longitude .. '?units=auto')
- if res ~= 200
- then
- return mattata.send_reply(
- message,
- language['errors']['connection']
- )
- end
- local jdat = json.decode(jstr)
- return mattata.send_message(
- message.chat.id,
- string.format(
- language['weather']['2'],
- weather.format_temperature(
- jdat.currently.temperature,
- jdat.flags.units
- ),
- weather.format_temperature(
- jdat.currently.apparentTemperature,
- jdat.flags.units
- ),
- address,
- jdat.daily.summary
- )
- )
-end
-
-return weather
\ No newline at end of file
diff --git a/plugins/wikipedia.lua b/plugins/wikipedia.lua
deleted file mode 100644
index 44a8779..0000000
--- a/plugins/wikipedia.lua
+++ /dev/null
@@ -1,108 +0,0 @@
---[[
- Based on a plugin by topkecleon. Licensed under GNU AGPLv3
- https://github.com/topkecleon/otouto/blob/master/LICENSE.
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See ./LICENSE for details.
-]]
-
-local wikipedia = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local json = require('dkjson')
-
-function wikipedia:init()
- wikipedia.commands = mattata.commands(self.info.username)
- :command('wikipedia')
- :command('wiki')
- :command('w').table
- wikipedia.help = '/wikipedia <query> - Searches Wikipedia for the given search query and returns the most relevant article. Aliases: /wiki, /w.'
-end
-
-function wikipedia:on_message(message, configuration, language)
- local input = mattata.input(message.text)
- if not input
- then
- return mattata.send_reply(
- message,
- wikipedia.help
- )
- end
- local jstr, res = https.request('https://en.wikipedia.org/w/api.php?action=query&list=search&format=json&srsearch=' .. url.escape(input))
- if res ~= 200
- then
- return mattata.send_reply(
- message,
- language['errors']['connection']
- )
- end
- local jdat = json.decode(jstr)
- if jdat.query.searchinfo.totalhits == 0
- then
- return mattata.send_reply(
- message,
- language['errors']['results']
- )
- end
- local title
- for _, v in ipairs(jdat.query.search)
- do
- if not v.snippet:match('may refer to:')
- then
- title = v.title
- break
- end
- end
- if not title
- then
- return mattata.send_reply(
- message,
- language['errors']['results']
- )
- end
- local res_jstr, res_code = https.request('https://en.wikipedia.org/w/api.php?action=query&format=json&prop=extracts&exchars=4000&explaintext=&titles=' .. url.escape(title))
- if res_code ~= 200
- then
- return mattata.send_reply(
- message,
- language['errors']['connection']
- )
- end
- local _, text = next(json.decode(res_jstr).query.pages)
- if not text
- then
- return mattata.send_reply(
- message,
- language['errors']['results']
- )
- end
- text = text.extract
- local l = text:find('\n')
- if l
- then
- text = text:sub(1, l - 1)
- end
- local final_url = 'https://en.wikipedia.org/wiki/' .. url.escape(title)
- title = mattata.escape_html(title)
- local short_title = title:gsub('%(.+%)', '')
- local combined_text, count = text:gsub('^' .. short_title, '<b>' .. short_title .. '</b>')
- local output
- if count == 1
- then
- output = combined_text
- else
- output = '<b>' .. title .. '</b>\n' .. text
- end
- return mattata.send_message(
- message.chat.id,
- string.format(
- '%s\n<a href="%s">%s</a>',
- output,
- mattata.escape_html(final_url),
- language['wikipedia']['1']
- ),
- 'html'
- )
-end
-
-return wikipedia
\ No newline at end of file
diff --git a/plugins/xkcd.lua b/plugins/xkcd.lua
deleted file mode 100644
index d70b7f6..0000000
--- a/plugins/xkcd.lua
+++ /dev/null
@@ -1,95 +0,0 @@
---[[
- Based on a plugin by topkecleon. Licensed under GNU AGPLv3
- https://github.com/topkecleon/otouto/blob/master/LICENSE.
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local xkcd = {}
-
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local json = require('dkjson')
-
-function xkcd:init()
- xkcd.commands = mattata.commands(
- self.info.username
- ):command('xkcd').table
- xkcd.help = [[/xkcd [query] - Returns the latest xkcd strip and its alt text. If a number is given, returns that number strip. If 'r' is passed in place of a number, returns a random strip. Any other text passed as the command argument will search Google for a relevant strip and, if applicable, return it.]]
- local jstr = https.request('https://xkcd.com/info.0.json')
- if jstr
- then
- local jdat = json.decode(jstr)
- if jdat
- then
- xkcd.latest = jdat.num
- end
- end
- xkcd.latest = xkcd.latest
-end
-
-function xkcd:on_message(message, configuration, language)
- local input = mattata.input(message.text)
- if not input
- then
- input = xkcd.latest
- end
- if input == 'r'
- then
- input = math.random(xkcd.latest)
- elseif tonumber(input) ~= nil
- then
- input = tonumber(input)
- else
- input = 'inurl:xkcd.com ' .. input
- local search, res = https.request('https://relevantxkcd.appspot.com/process?action=xkcd&query=' .. url.escape(input))
- if res ~= 200
- then
- return mattata.send_reply(
- message,
- language['errors']['results']
- )
- end
- input = tonumber(
- search:match('^.-\n.-\n(%d*) %/')
- )
- end
- local url = string.format(
- 'https://xkcd.com/%s/info.0.json',
- tostring(input)
- )
- local jstr, res = https.request(url)
- if res == 404
- then
- return mattata.send_message(
- message.chat.id,
- '[<a href="https://xkcd.com/404">404</a>] <b>404 Not Found</b>, 1/4/2008',
- 'html'
- )
- elseif res ~= 200
- then
- return mattata.send_reply(
- message,
- language['errors']['connection']
- )
- end
- local jdat = json.decode(jstr)
- return mattata.send_message(
- message.chat.id,
- string.format(
- '[<a href="%s">%s</a>] <b>%s</b>, %s/%s/%s\n<i>%s</i>',
- jdat.img,
- jdat.num,
- mattata.escape_html(jdat.safe_title),
- jdat.day,
- jdat.month,
- jdat.year,
- mattata.escape_html(jdat.alt)
- ),
- 'html',
- false
- )
-end
-
-return xkcd
\ No newline at end of file
diff --git a/plugins/youtube.lua b/plugins/youtube.lua
deleted file mode 100644
index 4f55ea5..0000000
--- a/plugins/youtube.lua
+++ /dev/null
@@ -1,157 +0,0 @@
---[[
- Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
- This code is licensed under the MIT. See LICENSE for details.
-]]
-
-local youtube = {}
-local mattata = require('mattata')
-local https = require('ssl.https')
-local url = require('socket.url')
-local json = require('dkjson')
-local configuration = require('configuration')
-
-function youtube:init(configuration)
- assert(configuration.keys.youtube, 'youtube.lua requires an API key, and you haven\'t got one configured!')
- youtube.commands = mattata.commands(self.info.username):command('youtube'):command('yt').table
- youtube.help = '/youtube <query> - Searches YouTube for the given search query and returns the most relevant result(s). Alias: /yt.'
-end
-
-function youtube.get_result_count(input)
- local jstr, res = https.request('https://www.googleapis.com/youtube/v3/search?key=' .. configuration.keys.youtube .. '&type=video&part=snippet&q=' .. url.escape(input))
- if res ~= 200 then
- return 0
- end
- local jdat = json.decode(jstr)
- if jdat.pageInfo.total_results == 0 then
- return 0
- end
- return #jdat.items
-end
-
-function youtube.get_result(input, n)
- n = n or 1
- local jstr, res = https.request('https://www.googleapis.com/youtube/v3/search?key=' .. configuration.keys.youtube .. '&part=snippet&type=video&safesearch=none&q=' .. url.escape(input))
- if res ~= 200 then
- return false
- end
- local jdat = json.decode(jstr)
- if jdat.pageInfo.total_results == 0 then
- return false
- end
- local jstr_info, res_info = https.request('https://www.googleapis.com/youtube/v3/videos?part=snippet,statistics,contentDetails&key=' .. configuration.keys.youtube .. '&id=' .. jdat.items[n].id.videoId .. '&fields=items(id,snippet(publishedAt,channelTitle,localized(title,description)),statistics(viewCount,likeCount,dislikeCount,commentCount),contentDetails(duration,regionRestriction(blocked)))')
- if res_info ~= 200 then
- return false
- end
- local jdat_info = json.decode(jstr_info)
- local output = '<a href="https://www.youtube.com/watch?v=' .. jdat.items[n].id.videoId .. '">' .. mattata.escape_html(jdat.items[n].snippet.title) .. '</a>\n'
- if jdat_info.items[1].snippet.channelTitle then
- output = output .. '👤 ' .. mattata.escape_html(jdat_info.items[1].snippet.channelTitle) .. '\n'
- end
- if jdat_info.items[1].statistics.viewCount then
- output = output .. '👁 ' .. mattata.comma_value(jdat_info.items[1].statistics.viewCount) .. '\n'
- end
- if jdat_info.items[1].statistics.commentCount then
- output = output .. '💬 ' .. mattata.comma_value(jdat_info.items[1].statistics.commentCount) .. '\n'
- end
- if jdat_info.items[1].statistics.likeCount then
- output = output .. '👍 ' .. mattata.comma_value(jdat_info.items[1].statistics.likeCount) .. '\n'
- end
- if jdat_info.items[1].statistics.dislikeCount then
- output = output .. '👎 ' .. mattata.comma_value(jdat_info.items[1].statistics.dislikeCount) .. '\n'
- end
- return output
-end
-
-function youtube:on_callback_query(callback_query, message, configuration, language)
- if not message.reply then
- return mattata.answer_callback_query(callback_query.id, language['errors']['generic'])
- elseif callback_query.data:match('^results:%d*$') then
- local result = callback_query.data:match('^results:(%d*)$')
- local input = mattata.input(message.reply.text)
- local total_results = youtube.get_result_count(input)
- if tonumber(result) > tonumber(total_results) then
- result = 1
- elseif tonumber(result) < 1 then
- result = tonumber(total_results)
- end
- local output = youtube.get_result(input, tonumber(result))
- if not output then
- return mattata.answer_callback_query(callback_query.id, language['errors']['generic'])
- end
- local previous_result = 'youtube:results:' .. tonumber(result) - 1
- local next_result = 'youtube:results:' .. tonumber(result) + 1
- local keyboard = json.encode(
- {
- inline_keyboard = {
- {
- {
- ['text'] = mattata.symbols.back .. ' ' .. language['youtube']['1'],
- ['callback_data'] = previous_result
- },
- {
- ['text'] = result .. '/' .. total_results,
- ['callback_data'] = 'youtube:pages:' .. result .. ':' .. total_results
- },
- {
- ['text'] = language['youtube']['2'] .. ' ' .. mattata.symbols.next,
- ['callback_data'] = next_result
- }
- }
- }
- }
- )
- return mattata.edit_message_text(message.chat.id, message.message_id, output, 'html', true, keyboard)
- elseif callback_query.data:match('^pages:.-:.-$') then
- local current_page, total_pages = callback_query.data:match('^pages:(.-):(.-)$')
- return mattata.answer_callback_query(
- callback_query.id,
- string.format(
- language['youtube']['3'],
- current_page,
- total_pages
- )
- )
- end
-end
-
-function youtube:on_message(message, configuration, language)
- local input = mattata.input(message.text)
- if not input then
- return mattata.send_reply(message, youtube.help)
- end
- local output = youtube.get_result(input)
- if not output then
- return mattata.send_reply(message, language['errors']['results'])
- end
- local keyboard = json.encode(
- {
- ['inline_keyboard'] = {
- {
- {
- ['text'] = mattata.symbols.back .. ' ' .. language['youtube']['1'],
- ['callback_data'] = 'youtube:results:0'
- },
- {
- ['text'] = '1/' .. youtube.get_result_count(input),
- ['callback_data'] = 'youtube:pages:1:' .. youtube.get_result_count(input)
- },
- {
- ['text'] = language['youtube']['2'] .. ' ' .. mattata.symbols.next,
- ['callback_data'] = 'youtube:results:2'
- }
- }
- }
- }
- )
- return mattata.send_message(
- message.chat.id,
- output,
- 'html',
- true,
- false,
- message.message_id,
- keyboard
- )
-end
-
-return youtube
\ No newline at end of file
diff --git a/soab.png b/soab.png
deleted file mode 100644
index 1e41411..0000000
Binary files a/soab.png and /dev/null differ
diff --git a/spec/core/loader_spec.lua b/spec/core/loader_spec.lua
index 9be4d7c..e21e406 100644
--- a/spec/core/loader_spec.lua
+++ b/spec/core/loader_spec.lua
@@ -1,307 +1,311 @@
--[[
Tests for src/core/loader.lua
Tests plugin registration, command lookup, category lookup, is_permanent, reload.
Uses mock plugins to avoid loading real plugin files.
]]
describe('core.loader', function()
local loader
-- Fake plugins for testing
local fake_ping = {
name = 'ping',
category = 'utility',
commands = { 'ping', 'pong' },
help = '/ping - PONG!',
description = 'Check bot responsiveness',
on_message = function() end,
}
local fake_help = {
name = 'help',
category = 'utility',
commands = { 'help', 'start' },
help = '/help [command]',
description = 'View help',
permanent = true,
on_message = function() end,
}
local fake_ban = {
name = 'ban',
category = 'admin',
commands = { 'ban', 'b' },
help = '/ban [user]',
description = 'Ban users',
admin_only = true,
group_only = true,
on_message = function() end,
}
local fake_about = {
name = 'about',
category = 'utility',
commands = { 'about' },
help = '/about',
description = 'About the bot',
on_message = function() end,
}
local fake_plugins = {
name = 'plugins',
category = 'utility',
commands = { 'plugins' },
help = '/plugins',
description = 'Enable/disable plugins',
on_message = function() end,
}
before_each(function()
-- Reset all module caches
package.loaded['src.core.loader'] = nil
package.loaded['src.core.logger'] = {
debug = function() end,
info = function() end,
warn = function() end,
error = function() end,
}
package.loaded['src.core.config'] = {
get = function(key, default) return default end,
get_number = function(key, default) return default end,
is_enabled = function() return false end,
bot_admins = function() return {} end,
load = function() end,
VERSION = '2.0',
}
-- Mock category manifests
package.loaded['src.plugins.admin.init'] = { plugins = { 'ban' } }
package.loaded['src.plugins.utility.init'] = { plugins = { 'help', 'ping', 'about', 'plugins' } }
package.loaded['src.plugins.fun.init'] = { plugins = {} }
package.loaded['src.plugins.media.init'] = { plugins = {} }
package.loaded['src.plugins.ai.init'] = { plugins = {} }
-- Mock individual plugins
package.loaded['src.plugins.admin.ban'] = fake_ban
package.loaded['src.plugins.utility.help'] = fake_help
package.loaded['src.plugins.utility.ping'] = fake_ping
package.loaded['src.plugins.utility.about'] = fake_about
package.loaded['src.plugins.utility.plugins'] = fake_plugins
loader = require('src.core.loader')
loader.init(nil, nil, nil)
end)
describe('init()', function()
it('should load plugins from manifests', function()
assert.is_true(loader.count() > 0)
end)
it('should load the expected number of plugins', function()
assert.are.equal(5, loader.count())
end)
end)
describe('get_plugins()', function()
it('should return all loaded plugins', function()
local plugins = loader.get_plugins()
assert.are.equal(5, #plugins)
end)
it('should return plugins in order', function()
local plugins = loader.get_plugins()
-- Admin category loads first, then utility
assert.are.equal('ban', plugins[1].name)
assert.are.equal('help', plugins[2].name)
end)
end)
describe('get_by_command()', function()
it('should find plugin by primary command', function()
local plugin = loader.get_by_command('ping')
assert.is_not_nil(plugin)
assert.are.equal('ping', plugin.name)
end)
it('should find plugin by alias command', function()
local plugin = loader.get_by_command('pong')
assert.is_not_nil(plugin)
assert.are.equal('ping', plugin.name)
end)
it('should find plugin by short alias', function()
local plugin = loader.get_by_command('b')
assert.is_not_nil(plugin)
assert.are.equal('ban', plugin.name)
end)
it('should be case-insensitive', function()
local plugin = loader.get_by_command('PING')
assert.is_not_nil(plugin)
assert.are.equal('ping', plugin.name)
end)
it('should return nil for unknown command', function()
local plugin = loader.get_by_command('nonexistent')
assert.is_nil(plugin)
end)
end)
describe('get_by_name()', function()
it('should find plugin by name', function()
local plugin = loader.get_by_name('ban')
assert.is_not_nil(plugin)
assert.are.equal('ban', plugin.name)
end)
it('should return nil for unknown name', function()
local plugin = loader.get_by_name('nonexistent')
assert.is_nil(plugin)
end)
end)
describe('get_category()', function()
it('should return all plugins in admin category', function()
local plugins = loader.get_category('admin')
assert.are.equal(1, #plugins)
assert.are.equal('ban', plugins[1].name)
end)
it('should return all plugins in utility category', function()
local plugins = loader.get_category('utility')
assert.are.equal(4, #plugins)
end)
it('should return empty table for empty category', function()
local plugins = loader.get_category('fun')
assert.are.same({}, plugins)
end)
it('should return empty table for unknown category', function()
local plugins = loader.get_category('nonexistent')
assert.are.same({}, plugins)
end)
end)
describe('is_permanent()', function()
it('should return true for help plugin', function()
assert.is_true(loader.is_permanent('help'))
end)
it('should return true for about plugin', function()
assert.is_true(loader.is_permanent('about'))
end)
it('should return true for plugins plugin', function()
assert.is_true(loader.is_permanent('plugins'))
end)
it('should return false for ban plugin', function()
assert.is_false(loader.is_permanent('ban'))
end)
it('should return false for ping plugin', function()
assert.is_false(loader.is_permanent('ping'))
end)
it('should return false for unknown plugin', function()
assert.is_false(loader.is_permanent('nonexistent'))
end)
end)
describe('reload()', function()
it('should return false for non-existent plugin', function()
local ok, err = loader.reload('nonexistent')
assert.is_false(ok)
assert.is_truthy(err:match('not found'))
end)
it('should successfully reload an existing plugin', function()
- -- Set up a new version of the plugin in package.loaded
+ -- Use package.preload so reload() finds it after clearing package.loaded
local new_ping = {
name = 'ping',
category = 'utility',
commands = { 'ping', 'pong', 'latency' },
help = '/ping - Updated!',
description = 'Updated ping',
on_message = function() return 'updated' end,
}
- package.loaded['src.plugins.utility.ping'] = new_ping
+ package.preload['src.plugins.utility.ping'] = function() return new_ping end
local ok = loader.reload('ping')
assert.is_true(ok)
-- New command should be registered
local p = loader.get_by_command('latency')
assert.is_not_nil(p)
assert.are.equal('ping', p.name)
+
+ package.preload['src.plugins.utility.ping'] = nil
end)
it('should re-index commands after reload', function()
- -- Simulate reload with different commands
+ -- Use package.preload so reload() finds it after clearing package.loaded
local new_ping = {
name = 'ping',
commands = { 'newping' },
on_message = function() end,
}
- package.loaded['src.plugins.utility.ping'] = new_ping
+ package.preload['src.plugins.utility.ping'] = function() return new_ping end
loader.reload('ping')
-- Old commands should no longer work
assert.is_nil(loader.get_by_command('pong'))
-- New command should work
assert.is_not_nil(loader.get_by_command('newping'))
+
+ package.preload['src.plugins.utility.ping'] = nil
end)
end)
describe('get_help()', function()
it('should return help for all plugins', function()
local help = loader.get_help()
assert.is_true(#help > 0)
end)
it('should return help for a specific category', function()
local help = loader.get_help('admin')
assert.are.equal(1, #help)
assert.are.equal('ban', help[1].name)
end)
it('should include commands in help entries', function()
local help = loader.get_help('utility')
local found_ping = false
for _, h in ipairs(help) do
if h.name == 'ping' then
found_ping = true
assert.are.same({ 'ping', 'pong' }, h.commands)
end
end
assert.is_true(found_ping)
end)
it('should include description in help entries', function()
local help = loader.get_help('utility')
for _, h in ipairs(help) do
if h.name == 'ping' then
assert.are.equal('Check bot responsiveness', h.description)
end
end
end)
end)
describe('get_categories()', function()
it('should return list of all categories', function()
local cats = loader.get_categories()
assert.is_true(#cats > 0)
-- Check it contains expected categories
local found_admin = false
local found_utility = false
for _, c in ipairs(cats) do
if c == 'admin' then found_admin = true end
if c == 'utility' then found_utility = true end
end
assert.is_true(found_admin)
assert.is_true(found_utility)
end)
end)
end)
diff --git a/spec/helpers/test_helper.lua b/spec/helpers/test_helper.lua
index 3860d1b..7489775 100644
--- a/spec/helpers/test_helper.lua
+++ b/spec/helpers/test_helper.lua
@@ -1,199 +1,200 @@
--[[
mattata v2.0 - Test Helper
Common utilities for busted test setup/teardown and assertion helpers.
]]
local test_helper = {}
+local assert = require('luassert')
local mock_api = require('spec.helpers.mock_api')
local mock_db = require('spec.helpers.mock_db')
local mock_redis = require('spec.helpers.mock_redis')
-- Create a fresh set of mocks for each test
function test_helper.setup()
local env = {
api = mock_api.new(),
db = mock_db.new(),
redis = mock_redis.new(),
}
return env
end
-- Reset all mocks between tests
function test_helper.teardown(env)
if env then
if env.api and env.api.reset then env.api.reset() end
if env.db and env.db.reset then env.db.reset() end
if env.redis and env.redis.reset then env.redis.reset() end
end
end
-- Build a mock message for testing
function test_helper.make_message(overrides)
local msg = {
message_id = 1,
date = os.time(),
from = {
id = 111111,
is_bot = false,
first_name = 'Test',
last_name = 'User',
username = 'testuser',
language_code = 'en_gb',
},
chat = {
id = -100123456789,
title = 'Test Group',
type = 'supergroup',
},
text = '',
}
if overrides then
for k, v in pairs(overrides) do
if type(v) == 'table' and type(msg[k]) == 'table' then
for k2, v2 in pairs(v) do
msg[k][k2] = v2
end
else
msg[k] = v
end
end
end
return msg
end
-- Build a mock private message
function test_helper.make_private_message(overrides)
local defaults = {
chat = {
id = 111111,
type = 'private',
first_name = 'Test',
last_name = 'User',
},
}
if overrides then
for k, v in pairs(overrides) do
defaults[k] = v
end
end
return test_helper.make_message(defaults)
end
-- Build a mock callback query
function test_helper.make_callback_query(overrides)
local cb = {
id = 'callback_123',
from = {
id = 111111,
is_bot = false,
first_name = 'Test',
username = 'testuser',
},
message = {
message_id = 1,
chat = {
id = -100123456789,
type = 'supergroup',
title = 'Test Group',
},
},
data = '',
}
if overrides then
for k, v in pairs(overrides) do
cb[k] = v
end
end
return cb
end
-- Build a context (ctx) object similar to what the router builds
function test_helper.make_ctx(env, overrides)
local ctx = {
api = env.api,
db = env.db,
redis = env.redis,
config = {
bot_name = function() return 'mattata' end,
get = function(key, default) return default end,
get_number = function(key, default) return default end,
is_enabled = function(key) return false end,
bot_admins = function() return {} end,
},
is_group = true,
is_supergroup = true,
is_private = false,
is_global_admin = false,
is_admin = false,
is_mod = false,
lang = {
errors = {
connection = 'Connection error.',
results = 'No results found.',
supergroup = 'This command can only be used in supergroups.',
admin = 'You need to be an admin to use this command.',
generic = 'An unexpected error occurred.',
},
},
lang_code = 'en_gb',
}
if overrides then
for k, v in pairs(overrides) do
ctx[k] = v
end
end
return ctx
end
-- Assert a specific API method was called
function test_helper.assert_api_called(api, method)
local call = api.get_call(method)
assert.is_not_nil(call, 'Expected API method "' .. method .. '" to be called')
return call
end
-- Assert a specific API method was NOT called
function test_helper.assert_api_not_called(api, method)
local call = api.get_call(method)
assert.is_nil(call, 'Expected API method "' .. method .. '" NOT to be called')
end
-- Assert a send_message was called with text matching a pattern
function test_helper.assert_sent_message_matches(api, pattern)
local found = false
for _, call in ipairs(api.calls) do
if call.method == 'send_message' and call.args[2] and call.args[2]:match(pattern) then
found = true
break
end
end
assert.is_true(found, 'Expected send_message with text matching "' .. pattern .. '"')
end
-- Assert a specific DB query was executed
function test_helper.assert_db_query_matches(db, pattern)
local found = false
for _, q in ipairs(db.queries) do
local sql = q.sql or ''
if sql:match(pattern) then
found = true
break
end
end
assert.is_true(found, 'Expected DB query matching "' .. pattern .. '"')
end
-- Assert a specific Redis command was issued
function test_helper.assert_redis_command(redis, cmd)
local found = false
for _, c in ipairs(redis.commands) do
if c.cmd == cmd then
found = true
break
end
end
assert.is_true(found, 'Expected Redis command "' .. cmd .. '"')
end
return test_helper
diff --git a/spec/plugins/admin/federation_spec.lua b/spec/plugins/admin/federation_spec.lua
index d293b9a..9553857 100644
--- a/spec/plugins/admin/federation_spec.lua
+++ b/spec/plugins/admin/federation_spec.lua
@@ -1,427 +1,427 @@
--[[
Tests for federation plugins: newfed, joinfed, fban, unfban, fbaninfo.
]]
describe('plugins.admin.federation', function()
local test_helper = require('spec.helpers.test_helper')
local env, ctx, message
before_each(function()
-- Mock shared dependencies
package.loaded['telegram-bot-lua.tools'] = {
escape_html = function(text)
if not text then return '' end
return tostring(text):gsub('&', '&amp;'):gsub('<', '&lt;'):gsub('>', '&gt;')
end,
}
package.loaded['src.core.logger'] = {
debug = function() end, info = function() end,
warn = function() end, error = function() end,
}
package.loaded['src.core.config'] = {
get = function(key, default) return default end,
is_enabled = function() return false end,
bot_admins = function() return {} end,
load = function() end, VERSION = '2.0',
}
package.loaded['src.core.session'] = {
get_admin_status = function() return nil end,
set_admin_status = function() end,
get_cached_setting = function(chat_id, key, fetch_fn, ttl)
return fetch_fn()
end,
}
package.loaded['src.core.permissions'] = {
is_global_admin = function() return false end,
is_group_admin = function() return false end,
can_restrict = function() return true end,
}
env = test_helper.setup()
message = test_helper.make_message()
ctx = test_helper.make_ctx(env)
end)
after_each(function()
test_helper.teardown(env)
end)
describe('newfed', function()
local newfed
before_each(function()
package.loaded['src.plugins.admin.federation.newfed'] = nil
newfed = require('src.plugins.admin.federation.newfed')
end)
it('should have correct metadata', function()
assert.are.equal('newfed', newfed.name)
assert.are.same({ 'newfed' }, newfed.commands)
end)
it('should require a name argument', function()
message.args = nil
newfed.on_message(env.api, message, ctx)
test_helper.assert_sent_message_matches(env.api, 'specify a name')
end)
it('should require a name argument when empty string', function()
message.args = ''
newfed.on_message(env.api, message, ctx)
test_helper.assert_sent_message_matches(env.api, 'specify a name')
end)
it('should reject names longer than 128 characters', function()
message.args = string.rep('a', 129)
newfed.on_message(env.api, message, ctx)
test_helper.assert_sent_message_matches(env.api, '128 characters')
end)
it('should allow names of exactly 128 characters', function()
message.args = string.rep('a', 128)
env.db.queue_result({ { count = 0 } }) -- existing count
env.db.queue_result({ { id = 'test-uuid' } }) -- insert result
newfed.on_message(env.api, message, ctx)
test_helper.assert_sent_message_matches(env.api, 'created successfully')
end)
it('should reject when user already owns 5 federations', function()
message.args = 'Test Fed'
env.db.set_next_result({ { count = 5 } })
newfed.on_message(env.api, message, ctx)
test_helper.assert_sent_message_matches(env.api, 'maximum')
end)
it('should create federation and return ID', function()
message.args = 'My Federation'
env.db.queue_result({ { count = 0 } })
env.db.queue_result({ { id = 'uuid-1234' } })
newfed.on_message(env.api, message, ctx)
test_helper.assert_sent_message_matches(env.api, 'created successfully')
test_helper.assert_sent_message_matches(env.api, 'uuid%-1234')
end)
it('should handle DB failure gracefully', function()
message.args = 'Test Fed'
env.db.queue_result({ { count = 0 } })
env.db.queue_result({}) -- empty result = failure
newfed.on_message(env.api, message, ctx)
test_helper.assert_sent_message_matches(env.api, 'Failed')
end)
end)
describe('joinfed', function()
local joinfed
before_each(function()
package.loaded['src.plugins.admin.federation.joinfed'] = nil
joinfed = require('src.plugins.admin.federation.joinfed')
end)
it('should have correct metadata', function()
assert.are.equal('joinfed', joinfed.name)
assert.is_true(joinfed.group_only)
assert.is_true(joinfed.admin_only)
end)
it('should require federation ID argument', function()
message.args = nil
joinfed.on_message(env.api, message, ctx)
test_helper.assert_sent_message_matches(env.api, 'specify the federation ID')
end)
it('should reject when chat is already in a federation', function()
message.args = 'new-fed-id'
env.db.set_next_result({ { id = 'old-fed-id', name = 'Old Fed' } })
joinfed.on_message(env.api, message, ctx)
test_helper.assert_sent_message_matches(env.api, 'already part')
end)
it('should reject when federation does not exist', function()
message.args = 'nonexistent-id'
env.db.queue_result({}) -- not in federation
env.db.queue_result({}) -- federation not found
joinfed.on_message(env.api, message, ctx)
test_helper.assert_sent_message_matches(env.api, 'not found')
end)
it('should successfully join a federation', function()
message.args = 'fed-uuid'
env.db.queue_result({}) -- not in federation
env.db.queue_result({ { id = 'fed-uuid', name = 'Test Fed' } }) -- fed exists
env.db.queue_result({ {} }) -- insert result
joinfed.on_message(env.api, message, ctx)
test_helper.assert_sent_message_matches(env.api, 'has joined')
end)
end)
describe('fban', function()
local fban
before_each(function()
package.loaded['src.plugins.admin.federation.fban'] = nil
fban = require('src.plugins.admin.federation.fban')
end)
it('should have correct metadata', function()
assert.are.equal('fban', fban.name)
assert.are.same({ 'fban' }, fban.commands)
end)
it('should require chat to be in a federation', function()
env.db.set_next_result({}) -- no federation
fban.on_message(env.api, message, ctx)
test_helper.assert_sent_message_matches(env.api, 'not part of any federation')
end)
it('should require federation admin/owner permission', function()
- env.db.set_next_result({ { id = 'fed-1', name = 'Fed', owner_id = 999 } })
- env.db.set_next_result({}) -- not a fed admin
+ env.db.queue_result({ { id = 'fed-1', name = 'Fed', owner_id = 999 } })
+ env.db.queue_result({}) -- not a fed admin
message.from.id = 111111
fban.on_message(env.api, message, ctx)
test_helper.assert_sent_message_matches(env.api, 'federation owner or a federation admin')
end)
it('should require a target user', function()
env.db.set_next_result({ { id = 'fed-1', name = 'Fed', owner_id = message.from.id } })
message.args = nil
message.reply = nil
fban.on_message(env.api, message, ctx)
test_helper.assert_sent_message_matches(env.api, 'specify a user')
end)
it('should not ban the federation owner', function()
message.from.id = 111111
env.db.set_next_result({ { id = 'fed-1', name = 'Fed', owner_id = 111111 } })
message.reply = { from = { id = 111111, first_name = 'Owner' }, message_id = 1 }
fban.on_message(env.api, message, ctx)
test_helper.assert_sent_message_matches(env.api, 'cannot federation%-ban the federation owner')
end)
it('should not ban allowlisted users', function()
message.from.id = 111111
env.db.queue_result({ { id = 'fed-1', name = 'Fed', owner_id = 111111 } })
env.db.queue_result({ { ['1'] = 1 } }) -- is allowlisted
message.reply = { from = { id = 222222, first_name = 'Target' }, message_id = 1 }
fban.on_message(env.api, message, ctx)
test_helper.assert_sent_message_matches(env.api, 'allowlist')
end)
it('should ban user across federation chats', function()
message.from.id = 111111
env.db.queue_result({ { id = 'fed-1', name = 'Fed', owner_id = 111111 } }) -- get fed
env.db.queue_result({}) -- not allowlisted
env.db.queue_result({}) -- not already banned
env.db.queue_result({}) -- insert ban
env.db.queue_result({ { chat_id = -100111 }, { chat_id = -100222 } }) -- fed chats
message.reply = { from = { id = 222222, first_name = 'Target' }, message_id = 1 }
fban.on_message(env.api, message, ctx)
assert.are.equal(2, env.api.count_calls('ban_chat_member'))
test_helper.assert_sent_message_matches(env.api, 'Federation Ban')
end)
it('should invalidate Redis cache after fban', function()
message.from.id = 111111
env.db.queue_result({ { id = 'fed-1', name = 'Fed', owner_id = 111111 } })
env.db.queue_result({}) -- not allowlisted
env.db.queue_result({}) -- not already banned
env.db.queue_result({}) -- insert
env.db.queue_result({}) -- chats
message.reply = { from = { id = 222222, first_name = 'Target' }, message_id = 1 }
fban.on_message(env.api, message, ctx)
test_helper.assert_redis_command(env.redis, 'del')
end)
it('should include reason in ban record', function()
message.from.id = 111111
env.db.queue_result({ { id = 'fed-1', name = 'Fed', owner_id = 111111 } })
env.db.queue_result({}) -- not allowlisted
env.db.queue_result({}) -- not already banned
env.db.queue_result({}) -- insert
env.db.queue_result({}) -- chats
message.reply = { from = { id = 222222, first_name = 'Target' }, message_id = 1 }
message.args = 'spamming links'
fban.on_message(env.api, message, ctx)
test_helper.assert_sent_message_matches(env.api, 'spamming links')
end)
it('should resolve user from username', function()
message.from.id = 111111
env.redis.set('username:targetuser', '333333')
env.db.queue_result({ { id = 'fed-1', name = 'Fed', owner_id = 111111 } })
env.db.queue_result({}) -- not allowlisted
env.db.queue_result({}) -- not already banned
env.db.queue_result({}) -- insert
env.db.queue_result({}) -- chats
message.args = '@targetuser reason'
message.reply = nil
fban.on_message(env.api, message, ctx)
test_helper.assert_sent_message_matches(env.api, 'Federation Ban')
end)
end)
describe('unfban', function()
local unfban
before_each(function()
package.loaded['src.plugins.admin.federation.unfban'] = nil
unfban = require('src.plugins.admin.federation.unfban')
end)
it('should have correct metadata', function()
assert.are.equal('unfban', unfban.name)
assert.is_true(unfban.group_only)
end)
it('should require federation membership', function()
env.db.set_next_result({})
unfban.on_message(env.api, message, ctx)
test_helper.assert_sent_message_matches(env.api, 'not part of any federation')
end)
it('should require federation admin permission', function()
- env.db.set_next_result({ { id = 'fed-1', name = 'Fed', owner_id = 999 } })
- env.db.set_next_result({}) -- not a fed admin
+ env.db.queue_result({ { id = 'fed-1', name = 'Fed', owner_id = 999 } })
+ env.db.queue_result({}) -- not a fed admin
message.from.id = 111111
unfban.on_message(env.api, message, ctx)
test_helper.assert_sent_message_matches(env.api, 'federation owner or a federation admin')
end)
it('should require a target user', function()
env.db.set_next_result({ { id = 'fed-1', name = 'Fed', owner_id = message.from.id } })
message.args = nil
message.reply = nil
unfban.on_message(env.api, message, ctx)
test_helper.assert_sent_message_matches(env.api, 'specify a user')
end)
it('should report when user is not banned', function()
env.db.queue_result({ { id = 'fed-1', name = 'Fed', owner_id = message.from.id } })
env.db.queue_result({}) -- not banned
message.args = '222222'
unfban.on_message(env.api, message, ctx)
test_helper.assert_sent_message_matches(env.api, 'not banned')
end)
it('should unban user across federation chats', function()
env.db.queue_result({ { id = 'fed-1', name = 'Fed', owner_id = message.from.id } })
env.db.queue_result({ { ['1'] = 1 } }) -- is banned
env.db.queue_result({}) -- delete ban
env.db.queue_result({ { chat_id = -100111 }, { chat_id = -100222 } }) -- fed chats
message.args = '222222'
unfban.on_message(env.api, message, ctx)
assert.are.equal(2, env.api.count_calls('unban_chat_member'))
test_helper.assert_sent_message_matches(env.api, 'Federation Unban')
end)
it('should invalidate Redis cache after unfban', function()
env.db.queue_result({ { id = 'fed-1', name = 'Fed', owner_id = message.from.id } })
env.db.queue_result({ { ['1'] = 1 } })
env.db.queue_result({})
env.db.queue_result({})
message.args = '222222'
unfban.on_message(env.api, message, ctx)
test_helper.assert_redis_command(env.redis, 'del')
end)
end)
describe('fbaninfo', function()
local fbaninfo
before_each(function()
package.loaded['src.plugins.admin.federation.fbaninfo'] = nil
fbaninfo = require('src.plugins.admin.federation.fbaninfo')
end)
it('should have correct metadata', function()
assert.are.equal('fbaninfo', fbaninfo.name)
assert.are.same({ 'fbaninfo' }, fbaninfo.commands)
end)
it('should default to sender when no user specified', function()
message.args = nil
message.reply = nil
ctx.is_group = true
env.db.set_next_result({}) -- no bans found
fbaninfo.on_message(env.api, message, ctx)
test_helper.assert_sent_message_matches(env.api, 'not banned')
end)
it('should show ban info for banned user (group context)', function()
ctx.is_group = true
env.db.set_next_result({
{
reason = 'Spamming',
banned_by = 111111,
banned_at = '2024-01-01',
name = 'Test Fed',
id = 'fed-uuid',
}
})
message.args = '222222'
fbaninfo.on_message(env.api, message, ctx)
test_helper.assert_sent_message_matches(env.api, 'Federation Ban Info')
test_helper.assert_sent_message_matches(env.api, 'Spamming')
end)
it('should show no-ban message for clean user', function()
ctx.is_group = true
env.db.set_next_result({})
message.args = '222222'
fbaninfo.on_message(env.api, message, ctx)
test_helper.assert_sent_message_matches(env.api, 'not banned')
end)
it('should resolve user from reply', function()
ctx.is_group = true
message.reply = { from = { id = 222222, first_name = 'Target' }, message_id = 1 }
message.args = nil
env.db.set_next_result({})
fbaninfo.on_message(env.api, message, ctx)
test_helper.assert_sent_message_matches(env.api, 'not banned')
end)
it('should query all federations in private chat', function()
ctx.is_group = false
ctx.is_private = true
message.chat.type = 'private'
env.db.set_next_result({})
message.args = '222222'
fbaninfo.on_message(env.api, message, ctx)
-- Verify it queried without chat_id constraint
local found_private_query = false
for _, q in ipairs(env.db.queries) do
if q.sql and q.sql:match('federation_bans') and not q.sql:match('fc%.chat_id') then
found_private_query = true
end
end
assert.is_true(found_private_query)
end)
it('should show multiple bans', function()
ctx.is_group = false
ctx.is_private = true
message.chat.type = 'private'
env.db.set_next_result({
{ reason = 'Reason 1', name = 'Fed A', id = 'fed-1', banned_by = 111, banned_at = '2024-01-01' },
{ reason = 'Reason 2', name = 'Fed B', id = 'fed-2', banned_by = 222, banned_at = '2024-02-01' },
})
message.args = '222222'
fbaninfo.on_message(env.api, message, ctx)
test_helper.assert_sent_message_matches(env.api, 'Fed A')
test_helper.assert_sent_message_matches(env.api, 'Fed B')
end)
end)
end)
diff --git a/src/core/i18n.lua b/src/core/i18n.lua
index 5f1dbe8..e4d3527 100644
--- a/src/core/i18n.lua
+++ b/src/core/i18n.lua
@@ -1,93 +1,92 @@
--[[
mattata v2.0 - Internationalisation Module
Manages language files and provides translation lookups.
]]
local i18n = {}
-local config = require('src.core.config')
local logger = require('src.core.logger')
local languages = {}
local default_lang = 'en_gb'
-- Load all available language files from src/languages/
function i18n.init()
local lang_registry = require('src.languages.init')
for code, path in pairs(lang_registry) do
local ok, lang = pcall(require, path)
if ok and type(lang) == 'table' then
languages[code] = lang
logger.debug('Loaded language: %s', code)
else
logger.warn('Failed to load language %s: %s', code, tostring(lang))
end
end
logger.info('Loaded %d language(s)', i18n.count())
end
-- Get a language table by code
function i18n.get(code)
code = code or default_lang
return languages[code] or languages[default_lang]
end
-- Check if a language exists
function i18n.exists(code)
return languages[code] ~= nil
end
-- Get all available language codes
function i18n.available()
local codes = {}
for code in pairs(languages) do
table.insert(codes, code)
end
table.sort(codes)
return codes
end
-- Count loaded languages
function i18n.count()
local count = 0
for _ in pairs(languages) do
count = count + 1
end
return count
end
-- Translate a key with optional interpolation
-- Usage: i18n.t(lang, 'errors', 'connection') or i18n.t(lang, 'ban', 'success', {name = 'John'})
function i18n.t(lang_table, ...)
if type(lang_table) == 'string' then
lang_table = i18n.get(lang_table)
end
if not lang_table then
lang_table = languages[default_lang]
end
local args = { ... }
local value = lang_table
local interpolation = nil
for i, key in ipairs(args) do
if type(key) == 'table' then
interpolation = key
break
end
if type(value) == 'table' then
value = value[key]
else
return nil
end
end
if type(value) ~= 'string' then
return nil
end
if interpolation then
for k, v in pairs(interpolation) do
value = value:gsub('{' .. k .. '}', tostring(v))
end
end
return value
end
return i18n
diff --git a/src/core/loader.lua b/src/core/loader.lua
index e149c9c..1a01ad3 100644
--- a/src/core/loader.lua
+++ b/src/core/loader.lua
@@ -1,174 +1,168 @@
--[[
mattata v2.0 - Plugin Loader
Discovers, validates, and manages plugins from category directories.
Supports hot-reload and per-chat enable/disable.
]]
local loader = {}
local logger = require('src.core.logger')
-local config = require('src.core.config')
local plugins = {} -- ordered list of all loaded plugins
local by_command = {} -- command -> plugin lookup
local by_name = {} -- name -> plugin lookup
local categories = {} -- category -> list of plugin names
-local api, db, redis
-
local PERMANENT_PLUGINS = { 'help', 'about', 'plugins' }
local CATEGORIES = { 'admin', 'utility', 'fun', 'media', 'ai' }
-function loader.init(api_ref, db_ref, redis_ref)
- api = api_ref
- db = db_ref
- redis = redis_ref
+function loader.init(_, _, _)
plugins = {}
by_command = {}
by_name = {}
categories = {}
for _, category in ipairs(CATEGORIES) do
categories[category] = {}
local manifest_path = 'src.plugins.' .. category .. '.init'
local ok, manifest = pcall(require, manifest_path)
if ok and type(manifest) == 'table' and manifest.plugins then
for _, plugin_name in ipairs(manifest.plugins) do
local plugin_path = 'src.plugins.' .. category .. '.' .. plugin_name
local load_ok, plugin = pcall(require, plugin_path)
if load_ok and type(plugin) == 'table' then
plugin.name = plugin.name or plugin_name
plugin.category = plugin.category or category
plugin.commands = plugin.commands or {}
plugin.help = plugin.help or ''
plugin.description = plugin.description or ''
table.insert(plugins, plugin)
by_name[plugin.name] = plugin
table.insert(categories[category], plugin.name)
-- Index commands for fast lookup
for _, cmd in ipairs(plugin.commands) do
by_command[cmd:lower()] = plugin
end
logger.debug('Loaded plugin: %s/%s (%d commands)', category, plugin.name, #plugin.commands)
else
logger.warn('Failed to load plugin %s/%s: %s', category, plugin_name, tostring(plugin))
end
end
else
logger.debug('No manifest for category: %s (%s)', category, tostring(manifest))
end
end
logger.info('Loaded %d plugins across %d categories', #plugins, #CATEGORIES)
end
-- Get all loaded plugins (ordered)
function loader.get_plugins()
return plugins
end
-- Look up a plugin by command name
function loader.get_by_command(command)
return by_command[command:lower()]
end
-- Look up a plugin by name
function loader.get_by_name(name)
return by_name[name]
end
-- Get all plugins in a category
function loader.get_category(category)
local result = {}
for _, name in ipairs(categories[category] or {}) do
table.insert(result, by_name[name])
end
return result
end
-- Count loaded plugins
function loader.count()
return #plugins
end
-- Check if a plugin is permanent (cannot be disabled)
function loader.is_permanent(name)
for _, pname in ipairs(PERMANENT_PLUGINS) do
if pname == name then
return true
end
end
return false
end
-- Hot-reload a plugin by name
function loader.reload(name)
local plugin = by_name[name]
if not plugin then
return false, 'Plugin not found: ' .. name
end
local path = 'src.plugins.' .. plugin.category .. '.' .. name
package.loaded[path] = nil
local ok, new_plugin = pcall(require, path)
if not ok then
return false, 'Reload failed: ' .. tostring(new_plugin)
end
-- Preserve metadata
new_plugin.name = name
new_plugin.category = plugin.category
new_plugin.commands = new_plugin.commands or {}
-- Replace in ordered list
for i, p in ipairs(plugins) do
if p.name == name then
plugins[i] = new_plugin
break
end
end
-- Re-index commands (remove old, add new)
for cmd, p in pairs(by_command) do
if p.name == name then
by_command[cmd] = nil
end
end
for _, cmd in ipairs(new_plugin.commands) do
by_command[cmd:lower()] = new_plugin
end
by_name[name] = new_plugin
logger.info('Hot-reloaded plugin: %s', name)
return true
end
-- Get help text for all plugins or a specific category
function loader.get_help(category, chat_id)
local help = {}
local source = category and loader.get_category(category) or plugins
for _, plugin in ipairs(source) do
if plugin.help and plugin.help ~= '' then
table.insert(help, {
name = plugin.name,
category = plugin.category,
commands = plugin.commands,
help = plugin.help,
description = plugin.description
})
end
end
return help
end
-- Get list of categories
function loader.get_categories()
return CATEGORIES
end
return loader
diff --git a/src/core/permissions.lua b/src/core/permissions.lua
index 9a3c5f9..c57ed90 100644
--- a/src/core/permissions.lua
+++ b/src/core/permissions.lua
@@ -1,129 +1,129 @@
--[[
mattata v2.0 - Permissions Module
Centralised permission checks for admin/mod/trusted roles.
Includes bot permission checks with Redis caching.
]]
local permissions = {}
local config = require('src.core.config')
local session = require('src.core.session')
-- Check if a user is a global bot admin
function permissions.is_global_admin(user_id)
user_id = tonumber(user_id)
if not user_id then
return false
end
for _, admin_id in ipairs(config.bot_admins()) do
if tonumber(admin_id) == user_id then
return true
end
end
return false
end
-- Check if a user is a group admin (Telegram admin/creator) or bot global admin
function permissions.is_group_admin(api, chat_id, user_id)
if not chat_id or not user_id then
return false
end
if permissions.is_global_admin(user_id) then
return true
end
-- Check cache first
local cached = session.get_admin_status(chat_id, user_id)
if cached ~= nil then
return cached
end
-- Query Telegram API
local member, err = api.get_chat_member(chat_id, user_id)
if not member or not member.result then
return false, err
end
local status = member.result.status
local is_admin = (status == 'creator' or status == 'administrator')
session.set_admin_status(chat_id, user_id, is_admin)
return is_admin, status
end
-- Check if a user is a moderator (custom role, stored in PostgreSQL)
function permissions.is_group_mod(db, chat_id, user_id)
if not chat_id or not user_id then
return false
end
local result = db.execute(
"SELECT 1 FROM chat_members WHERE chat_id = $1 AND user_id = $2 AND role = 'moderator'",
{ chat_id, user_id }
)
return result and #result > 0
end
-- Check if a user is trusted in a group
function permissions.is_trusted(db, chat_id, user_id)
if not chat_id or not user_id then
return false
end
local result = db.execute(
"SELECT 1 FROM chat_members WHERE chat_id = $1 AND user_id = $2 AND role = 'trusted'",
{ chat_id, user_id }
)
return result and #result > 0
end
-- Check if the bot has a specific permission in a chat (cached for 5 min)
-- permission: 'can_restrict_members', 'can_delete_messages', 'can_promote_members',
-- 'can_pin_messages', 'can_invite_users'
function permissions.check_bot_can(api, chat_id, permission)
if not chat_id or not permission then
return false
end
-- Check cache first
local cache_key = string.format('bot_perm:%s', permission)
local cached = session.get_cached_setting(chat_id, cache_key, function()
- local member, err = api.get_chat_member(chat_id, api.info.id)
+ local member, _ = api.get_chat_member(chat_id, api.info.id)
if not member or not member.result then
return nil
end
if member.result.status ~= 'administrator' then
return 'false'
end
return member.result[permission] and 'true' or 'false'
end, 300)
return cached == 'true'
end
-- Check if the bot can restrict members in a chat
function permissions.can_restrict(api, chat_id)
return permissions.check_bot_can(api, chat_id, 'can_restrict_members')
end
-- Check if the bot can delete messages
function permissions.can_delete(api, chat_id)
return permissions.check_bot_can(api, chat_id, 'can_delete_messages')
end
-- Check if the bot can promote members
function permissions.can_promote(api, chat_id)
return permissions.check_bot_can(api, chat_id, 'can_promote_members')
end
-- Check if the bot can pin messages
function permissions.can_pin(api, chat_id)
return permissions.check_bot_can(api, chat_id, 'can_pin_messages')
end
-- Check if the bot can invite users
function permissions.can_invite(api, chat_id)
return permissions.check_bot_can(api, chat_id, 'can_invite_users')
end
-- Check if a user has admin OR mod rights
function permissions.is_admin_or_mod(api, db, chat_id, user_id)
if permissions.is_group_admin(api, chat_id, user_id) then
return true
end
return permissions.is_group_mod(db, chat_id, user_id)
end
return permissions
diff --git a/src/middleware/blocklist.lua b/src/middleware/blocklist.lua
index 9a09267..6197b74 100644
--- a/src/middleware/blocklist.lua
+++ b/src/middleware/blocklist.lua
@@ -1,75 +1,74 @@
--[[
mattata v2.0 - Blocklist Middleware
Checks global bans, group bans, and SpamWatch. Stops if blocked.
]]
local blocklist = {}
blocklist.name = 'blocklist'
local config = require('src.core.config')
local session = require('src.core.session')
-local logger = require('src.core.logger')
function blocklist.run(ctx, message)
if not message.from then
return ctx, false
end
local user_id = message.from.id
-- Global admins are never blocked
if ctx.is_global_admin then
return ctx, true
end
-- Check global blocklist
if session.is_globally_blocklisted(user_id) then
ctx.is_blocklisted = true
return ctx, false
end
-- Check global ban (federation-level)
local global_ban = ctx.redis.get('global_ban:' .. user_id)
if global_ban then
ctx.is_globally_banned = true
-- Auto-ban in groups
if ctx.is_group then
pcall(function()
ctx.api.ban_chat_member(message.chat.id, user_id)
end)
end
return ctx, false
end
-- Check per-group blocklist
if ctx.is_group then
local group_blocked = ctx.redis.get('group_blocklist:' .. message.chat.id .. ':' .. user_id)
if group_blocked then
ctx.is_group_blocklisted = true
return ctx, false
end
-- Check blocklisted chats
local chat_blocked = ctx.redis.get('blocklisted_chats:' .. message.chat.id)
if chat_blocked then
pcall(function()
ctx.api.leave_chat(message.chat.id)
end)
return ctx, false
end
end
-- SpamWatch check (if configured)
local spamwatch_token = config.get('SPAMWATCH_TOKEN')
if spamwatch_token and spamwatch_token ~= '' then
local cached = ctx.redis.get('not_blocklisted:' .. user_id)
if not cached then
-- Check will be done asynchronously in future; for now just mark as not checked
ctx.spamwatch_checked = false
end
end
return ctx, true
end
return blocklist
diff --git a/src/middleware/user_tracker.lua b/src/middleware/user_tracker.lua
index cd4ad8d..4a10146 100644
--- a/src/middleware/user_tracker.lua
+++ b/src/middleware/user_tracker.lua
@@ -1,83 +1,81 @@
--[[
mattata v2.0 - User Tracker Middleware
Upserts user and chat information to PostgreSQL with Redis-based debouncing.
Uses a 60s dedup key per user+chat to reduce DB writes by ~95%.
]]
local user_tracker = {}
user_tracker.name = 'user_tracker'
-local logger = require('src.core.logger')
-
function user_tracker.run(ctx, message)
if not message.from then
return ctx, true
end
local user = message.from
local user_id = user.id
local chat_id = message.chat and message.chat.id
-- Debounce: skip DB upserts if we've seen this user+chat in the last 60s
local dedup_key = string.format('seen:%s:%s', user_id, chat_id or 'private')
local already_seen = ctx.redis.exists(dedup_key)
if already_seen == 1 or already_seen == true then
-- Still update username->id mapping (cheap Redis SET)
if user.username then
ctx.redis.set('username:' .. user.username:lower(), user_id)
end
return ctx, true
end
-- Set dedup key with 60s TTL
ctx.redis.setex(dedup_key, 60, '1')
-- Upsert user to PostgreSQL
pcall(function()
ctx.db.upsert('users', {
user_id = user_id,
username = user.username and user.username:lower() or nil,
first_name = user.first_name,
last_name = user.last_name,
language_code = user.language_code,
is_bot = user.is_bot or false,
last_seen = os.date('!%Y-%m-%d %H:%M:%S')
}, { 'user_id' }, {
'username', 'first_name', 'last_name', 'language_code', 'last_seen'
})
end)
-- Upsert chat to PostgreSQL (for groups)
if chat_id and message.chat.type ~= 'private' then
pcall(function()
ctx.db.upsert('chats', {
chat_id = chat_id,
title = message.chat.title,
chat_type = message.chat.type,
username = message.chat.username and message.chat.username:lower() or nil
}, { 'chat_id' }, {
'title', 'chat_type', 'username'
})
end)
-- Track user<->chat membership
pcall(function()
ctx.db.upsert('chat_members', {
chat_id = chat_id,
user_id = user_id,
last_seen = os.date('!%Y-%m-%d %H:%M:%S')
}, { 'chat_id', 'user_id' }, {
'last_seen'
})
end)
end
-- Keep Redis username->id mapping for quick lookups
if user.username then
ctx.redis.set('username:' .. user.username:lower(), user_id)
end
return ctx, true
end
return user_tracker
diff --git a/src/plugins/admin/addtrigger.lua b/src/plugins/admin/addtrigger.lua
index fce6689..d69de24 100644
--- a/src/plugins/admin/addtrigger.lua
+++ b/src/plugins/admin/addtrigger.lua
@@ -1,131 +1,134 @@
--[[
mattata v2.0 - Add Trigger Plugin
]]
local plugin = {}
plugin.name = 'addtrigger'
plugin.category = 'admin'
plugin.description = 'Add a trigger (auto-response pattern)'
plugin.commands = { 'addtrigger' }
plugin.help = '/addtrigger <pattern> <response> - Adds a trigger. Use /deltrigger <number> to remove.'
plugin.group_only = true
plugin.admin_only = true
function plugin.on_message(api, message, ctx)
local tools = require('telegram-bot-lua.tools')
if not message.args then
- return api.send_message(message.chat.id, 'Usage: /addtrigger <pattern> <response>\n\nThe pattern is a Lua pattern that will be matched against incoming messages. When matched, the response is sent.')
+ return api.send_message(message.chat.id,
+ 'Usage: /addtrigger <pattern> <response>\n\n'
+ .. 'The pattern is a Lua pattern that will be matched against incoming messages. '
+ .. 'When matched, the response is sent.')
end
-- If used with /deltrigger, handle deletion
if message.command == 'deltrigger' then
local index = tonumber(message.args)
if not index then
return api.send_message(message.chat.id, 'Usage: /deltrigger <number>')
end
local triggers = ctx.db.execute(
'SELECT id, pattern FROM triggers WHERE chat_id = $1 ORDER BY created_at',
{ message.chat.id }
)
if not triggers or not triggers[index] then
return api.send_message(message.chat.id, 'Invalid trigger number. Use /triggers to see the list.')
end
ctx.db.execute('DELETE FROM triggers WHERE id = $1', { triggers[index].id })
-- Invalidate trigger cache
require('src.core.session').invalidate_cached_list(message.chat.id, 'triggers')
return api.send_message(message.chat.id, string.format(
'Trigger <code>%s</code> has been removed.',
tools.escape_html(triggers[index].pattern)
), 'html')
end
-- Parse pattern and response (split on first newline or first space after the pattern)
local pattern, response
if message.args:match('\n') then
pattern, response = message.args:match('^(.-)%s*\n%s*(.+)$')
else
pattern, response = message.args:match('^(%S+)%s+(.+)$')
end
if not pattern or not response then
return api.send_message(message.chat.id, 'Usage: /addtrigger <pattern> <response>')
end
pattern = pattern:match('^%s*(.-)%s*$')
response = response:match('^%s*(.-)%s*$')
-- Validate pattern
local ok = pcall(string.match, '', pattern)
if not ok then
return api.send_message(message.chat.id, 'Invalid Lua pattern. Please check your syntax.')
end
-- Check for duplicate
local existing = ctx.db.execute(
'SELECT id FROM triggers WHERE chat_id = $1 AND pattern = $2',
{ message.chat.id, pattern }
)
if existing and #existing > 0 then
ctx.db.execute(
'UPDATE triggers SET response = $1 WHERE chat_id = $2 AND pattern = $3',
{ response, message.chat.id, pattern }
)
return api.send_message(message.chat.id, string.format(
'Trigger <code>%s</code> has been updated.',
tools.escape_html(pattern)
), 'html')
end
ctx.db.insert('triggers', {
chat_id = message.chat.id,
pattern = pattern,
response = response,
created_by = message.from.id
})
-- Invalidate trigger cache
local session = require('src.core.session')
session.invalidate_cached_list(message.chat.id, 'triggers')
api.send_message(message.chat.id, string.format(
'Trigger added: <code>%s</code> -> %s',
tools.escape_html(pattern),
tools.escape_html(response:sub(1, 100)) .. (#response > 100 and '...' or '')
), 'html')
end
-- Handle trigger matching on every new message
function plugin.on_new_message(api, message, ctx)
if not ctx.is_group or not message.text or message.text == '' then return end
-- Don't trigger on commands
if message.text:match('^[/!#]') then return end
-- Cache triggers per chat (5-min TTL)
local session = require('src.core.session')
local triggers = session.get_cached_list(message.chat.id, 'triggers', function()
return ctx.db.execute(
'SELECT pattern, response, is_media, file_id FROM triggers WHERE chat_id = $1',
{ message.chat.id }
)
end, 300)
if not triggers or #triggers == 0 then return end
local text = message.text:lower()
for _, t in ipairs(triggers) do
local ok, matched = pcall(function()
return text:match(t.pattern:lower())
end)
if ok and matched then
if t.is_media and t.file_id then
-- Send media response
api.send_document(message.chat.id, t.file_id, nil, nil, nil, message.message_id)
else
api.send_message(message.chat.id, t.response, nil, nil, nil, message.message_id)
end
return
end
end
end
return plugin
diff --git a/src/plugins/admin/allowlink.lua b/src/plugins/admin/allowlink.lua
index 6ba2bee..2ee0fdb 100644
--- a/src/plugins/admin/allowlink.lua
+++ b/src/plugins/admin/allowlink.lua
@@ -1,77 +1,77 @@
--[[
mattata v2.0 - Allow Link Plugin
]]
local plugin = {}
plugin.name = 'allowlink'
plugin.category = 'admin'
plugin.description = 'Add or remove a link from the allowed links list'
plugin.commands = { 'allowlink' }
plugin.help = '/allowlink <link|@username> - Adds a link to the allowed list. /allowlink remove <link> - Removes it.'
plugin.group_only = true
plugin.admin_only = true
function plugin.on_message(api, message, ctx)
local tools = require('telegram-bot-lua.tools')
if not message.args then
return api.send_message(message.chat.id, 'Usage:\n/allowlink <link|@username> - Allow a link\n/allowlink remove <link|@username> - Remove from allowed list')
end
local args = message.args
local is_remove = false
if args:lower():match('^remove%s+') or args:lower():match('^del%s+') then
is_remove = true
args = args:gsub('^%S+%s+', '')
end
-- Normalise the link - extract the relevant part
local link = args:match('^%s*(.-)%s*$')
-- Strip protocol and domain prefixes
link = link:gsub('^https?://', '')
link = link:gsub('^[Tt]%.?[Mm][Ee]/', '')
link = link:gsub('^[Tt][Ee][Ll][Ee][Gg][Rr][Aa][Mm]%.?[Mm][Ee]/', '')
link = link:gsub('^[Tt][Ee][Ll][Ee][Gg][Rr][Aa][Mm]%.?[Dd][Oo][Gg]/', '')
link = link:gsub('^@', '')
if link == '' then
return api.send_message(message.chat.id, 'Please provide a valid link or username.')
end
if is_remove then
- local result = ctx.db.execute(
+ ctx.db.execute(
'DELETE FROM allowed_links WHERE chat_id = $1 AND link = $2',
{ message.chat.id, link }
)
-- Also try with lowercase
ctx.db.execute(
'DELETE FROM allowed_links WHERE chat_id = $1 AND link = $2',
{ message.chat.id, link:lower() }
)
return api.send_message(message.chat.id, string.format(
'Link <code>%s</code> has been removed from the allowed list.',
tools.escape_html(link)
), 'html')
end
-- Check if already allowed
local existing = ctx.db.execute(
'SELECT 1 FROM allowed_links WHERE chat_id = $1 AND link = $2',
{ message.chat.id, link }
)
if existing and #existing > 0 then
return api.send_message(message.chat.id, 'That link is already allowed.')
end
ctx.db.insert('allowed_links', {
chat_id = message.chat.id,
link = link
})
api.send_message(message.chat.id, string.format(
'Link <code>%s</code> has been added to the allowed list.',
tools.escape_html(link)
), 'html')
end
return plugin
diff --git a/src/plugins/admin/filter.lua b/src/plugins/admin/filter.lua
index bd40083..15aba93 100644
--- a/src/plugins/admin/filter.lua
+++ b/src/plugins/admin/filter.lua
@@ -1,82 +1,74 @@
--[[
mattata v2.0 - Filter Plugin
]]
local plugin = {}
plugin.name = 'filter'
plugin.category = 'admin'
plugin.description = 'Add content filters to the group'
plugin.commands = { 'filter', 'addfilter' }
plugin.help = '/filter <pattern> [action] - Adds a filter. Actions: delete (default), warn, ban, kick.'
plugin.group_only = true
plugin.admin_only = true
-local VALID_ACTIONS = {
- delete = true,
- warn = true,
- ban = true,
- kick = true,
- mute = true
-}
-
function plugin.on_message(api, message, ctx)
local tools = require('telegram-bot-lua.tools')
if not message.args then
return api.send_message(message.chat.id, 'Usage: /filter <pattern> [action]\nActions: delete (default), warn, ban, kick, mute', 'html')
end
local pattern, action
if message.args:match('^(.+)%s+(delete|warn|ban|kick|mute)$') then
pattern, action = message.args:match('^(.+)%s+(delete|warn|ban|kick|mute)$')
else
pattern = message.args
action = 'delete'
end
pattern = pattern:match('^%s*(.-)%s*$') -- trim
if pattern == '' then
return api.send_message(message.chat.id, 'Please provide a pattern to filter.')
end
-- Validate regex pattern
local ok = pcall(string.match, '', pattern)
if not ok then
return api.send_message(message.chat.id, 'Invalid pattern. Please provide a valid Lua pattern.')
end
-- Check for duplicate
local existing = ctx.db.execute(
'SELECT id FROM filters WHERE chat_id = $1 AND pattern = $2',
{ message.chat.id, pattern }
)
if existing and #existing > 0 then
-- Update the action if filter already exists
ctx.db.execute(
'UPDATE filters SET action = $1 WHERE chat_id = $2 AND pattern = $3',
{ action, message.chat.id, pattern }
)
require('src.core.session').invalidate_cached_list(message.chat.id, 'filters')
return api.send_message(message.chat.id, string.format(
'Filter <code>%s</code> updated with action: <b>%s</b>.',
tools.escape_html(pattern), action
), 'html')
end
ctx.db.insert('filters', {
chat_id = message.chat.id,
pattern = pattern,
action = action,
created_by = message.from.id
})
-- Invalidate filter cache
require('src.core.session').invalidate_cached_list(message.chat.id, 'filters')
api.send_message(message.chat.id, string.format(
'Filter added: <code>%s</code> (action: <b>%s</b>)',
tools.escape_html(pattern), action
), 'html')
end
return plugin
diff --git a/src/plugins/admin/rules.lua b/src/plugins/admin/rules.lua
index 922d321..dd54f37 100644
--- a/src/plugins/admin/rules.lua
+++ b/src/plugins/admin/rules.lua
@@ -1,44 +1,43 @@
--[[
mattata v2.0 - Rules Plugin
]]
local plugin = {}
plugin.name = 'rules'
plugin.category = 'admin'
plugin.description = 'Display group rules'
plugin.commands = { 'rules' }
plugin.help = '/rules - Displays the group rules. Admins can set rules with /setrules <text>.'
plugin.group_only = true
plugin.admin_only = false
function plugin.on_message(api, message, ctx)
local tools = require('telegram-bot-lua.tools')
- local permissions = require('src.core.permissions')
-- If /rules is used with args and user is admin, set rules
if message.args and (ctx.is_admin or ctx.is_global_admin) then
ctx.db.upsert('rules', {
chat_id = message.chat.id,
rules_text = message.args
}, { 'chat_id' }, { 'rules_text' })
return api.send_message(message.chat.id, 'The rules have been updated.')
end
-- Retrieve rules
local result = ctx.db.execute(
'SELECT rules_text FROM rules WHERE chat_id = $1',
{ message.chat.id }
)
if not result or #result == 0 or not result[1].rules_text then
return api.send_message(message.chat.id, 'No rules have been set for this group. An admin can set them with /rules <text>.')
end
local output = string.format(
'<b>Rules for %s:</b>\n\n%s',
tools.escape_html(message.chat.title or 'this chat'),
result[1].rules_text
)
api.send_message(message.chat.id, output, 'html')
end
return plugin
diff --git a/src/plugins/admin/save.lua b/src/plugins/admin/save.lua
index a1e9bd5..f2e3ce1 100644
--- a/src/plugins/admin/save.lua
+++ b/src/plugins/admin/save.lua
@@ -1,122 +1,121 @@
--[[
mattata v2.0 - Save/Get Notes Plugin
]]
local plugin = {}
plugin.name = 'save'
plugin.category = 'admin'
plugin.description = 'Save and retrieve notes'
plugin.commands = { 'save', 'get' }
plugin.help = '/save <name> - Saves replied-to message as a note. /get <name> - Retrieves a saved note.'
plugin.group_only = true
plugin.admin_only = false
function plugin.on_message(api, message, ctx)
local tools = require('telegram-bot-lua.tools')
- local permissions = require('src.core.permissions')
if message.command == 'get' then
if not message.args then
-- List all saved notes
local notes = ctx.db.execute(
'SELECT note_name FROM saved_notes WHERE chat_id = $1 ORDER BY note_name',
{ message.chat.id }
)
if not notes or #notes == 0 then
return api.send_message(message.chat.id, 'No notes saved. An admin can save notes with /save <name> in reply to a message.')
end
local output = '<b>Saved notes:</b>\n\n'
for _, note in ipairs(notes) do
output = output .. '- <code>' .. tools.escape_html(note.note_name) .. '</code>\n'
end
return api.send_message(message.chat.id, output, 'html')
end
local name = message.args:lower():match('^(%S+)')
local note = ctx.db.execute(
'SELECT content, content_type, file_id FROM saved_notes WHERE chat_id = $1 AND note_name = $2',
{ message.chat.id, name }
)
if not note or #note == 0 then
return api.send_message(message.chat.id, string.format('Note <code>%s</code> not found.', tools.escape_html(name)), 'html')
end
local n = note[1]
if n.content_type == 'photo' and n.file_id then
api.send_photo(message.chat.id, n.file_id, n.content)
elseif n.content_type == 'document' and n.file_id then
api.send_document(message.chat.id, n.file_id, n.content)
elseif n.content_type == 'video' and n.file_id then
api.send_video(message.chat.id, n.file_id, nil, nil, nil, n.content)
elseif n.content_type == 'audio' and n.file_id then
api.send_audio(message.chat.id, n.file_id, n.content)
elseif n.content_type == 'sticker' and n.file_id then
api.send_sticker(message.chat.id, n.file_id)
else
api.send_message(message.chat.id, n.content, 'html')
end
return
end
-- /save requires admin
if not ctx.is_admin and not ctx.is_global_admin then
return api.send_message(message.chat.id, 'Only admins can save notes.')
end
if not message.args then
return api.send_message(message.chat.id, 'Usage: /save <name> in reply to a message.')
end
local name = message.args:lower():match('^(%S+)')
if not name then
return api.send_message(message.chat.id, 'Please provide a name for the note.')
end
local content = ''
local content_type = 'text'
local file_id = nil
if message.reply then
content = message.reply.text or message.reply.caption or ''
if message.reply.photo then
content_type = 'photo'
file_id = message.reply.photo[#message.reply.photo].file_id
elseif message.reply.document then
content_type = 'document'
file_id = message.reply.document.file_id
elseif message.reply.video then
content_type = 'video'
file_id = message.reply.video.file_id
elseif message.reply.audio then
content_type = 'audio'
file_id = message.reply.audio.file_id
elseif message.reply.sticker then
content_type = 'sticker'
file_id = message.reply.sticker.file_id
end
else
-- If no reply, save the text after the note name
local _, rest = message.args:match('^(%S+)%s+(.+)$')
if rest then
content = rest
else
return api.send_message(message.chat.id, 'Please reply to a message or provide text after the note name.')
end
end
ctx.db.upsert('saved_notes', {
chat_id = message.chat.id,
note_name = name,
content = content,
content_type = content_type,
file_id = file_id,
created_by = message.from.id
}, { 'chat_id', 'note_name' }, { 'content', 'content_type', 'file_id', 'created_by' })
api.send_message(message.chat.id, string.format(
'Note <code>%s</code> has been saved. Use /get %s to retrieve it.',
tools.escape_html(name), tools.escape_html(name)
), 'html')
end
return plugin
diff --git a/src/plugins/admin/setcaptcha.lua b/src/plugins/admin/setcaptcha.lua
index 8b74a6c..b458c1f 100644
--- a/src/plugins/admin/setcaptcha.lua
+++ b/src/plugins/admin/setcaptcha.lua
@@ -1,65 +1,68 @@
--[[
mattata v2.0 - Set Captcha Plugin
]]
local plugin = {}
plugin.name = 'setcaptcha'
plugin.category = 'admin'
plugin.description = 'Configure captcha settings for new members'
plugin.commands = { 'setcaptcha' }
plugin.help = '/setcaptcha <on|off|timeout <seconds>> - Configure captcha settings.'
plugin.group_only = true
plugin.admin_only = true
function plugin.on_message(api, message, ctx)
if not message.args then
-- Show current captcha status
local enabled = ctx.db.execute(
"SELECT value FROM chat_settings WHERE chat_id = $1 AND key = 'captcha_enabled'",
{ message.chat.id }
)
local timeout = ctx.db.execute(
"SELECT value FROM chat_settings WHERE chat_id = $1 AND key = 'captcha_timeout'",
{ message.chat.id }
)
local status = (enabled and #enabled > 0 and enabled[1].value == 'true') and 'enabled' or 'disabled'
local timeout_val = (timeout and #timeout > 0) and timeout[1].value or '300'
return api.send_message(message.chat.id, string.format(
- '<b>Captcha settings:</b>\nStatus: %s\nTimeout: %s seconds\n\nUsage:\n<code>/setcaptcha on</code> - Enable captcha\n<code>/setcaptcha off</code> - Disable captcha\n<code>/setcaptcha timeout &lt;seconds&gt;</code> - Set timeout',
+ '<b>Captcha settings:</b>\nStatus: %s\nTimeout: %s seconds\n\n'
+ .. 'Usage:\n<code>/setcaptcha on</code> - Enable captcha\n'
+ .. '<code>/setcaptcha off</code> - Disable captcha\n'
+ .. '<code>/setcaptcha timeout &lt;seconds&gt;</code> - Set timeout',
status, timeout_val
), 'html')
end
local args = message.args:lower()
if args == 'on' or args == 'enable' then
ctx.db.upsert('chat_settings', {
chat_id = message.chat.id,
key = 'captcha_enabled',
value = 'true'
}, { 'chat_id', 'key' }, { 'value' })
return api.send_message(message.chat.id, 'Captcha has been enabled for this group.')
elseif args == 'off' or args == 'disable' then
ctx.db.upsert('chat_settings', {
chat_id = message.chat.id,
key = 'captcha_enabled',
value = 'false'
}, { 'chat_id', 'key' }, { 'value' })
return api.send_message(message.chat.id, 'Captcha has been disabled for this group.')
elseif args:match('^timeout%s+(%d+)$') then
local seconds = args:match('^timeout%s+(%d+)$')
seconds = tonumber(seconds)
if seconds < 30 or seconds > 3600 then
return api.send_message(message.chat.id, 'Timeout must be between 30 and 3600 seconds.')
end
ctx.db.upsert('chat_settings', {
chat_id = message.chat.id,
key = 'captcha_timeout',
value = tostring(seconds)
}, { 'chat_id', 'key' }, { 'value' })
return api.send_message(message.chat.id, string.format('Captcha timeout set to %d seconds.', seconds))
else
return api.send_message(message.chat.id, 'Usage: /setcaptcha <on|off|timeout <seconds>>')
end
end
return plugin
diff --git a/src/plugins/admin/setwelcome.lua b/src/plugins/admin/setwelcome.lua
index de98c93..a2df046 100644
--- a/src/plugins/admin/setwelcome.lua
+++ b/src/plugins/admin/setwelcome.lua
@@ -1,39 +1,43 @@
--[[
mattata v2.0 - Set Welcome Plugin
]]
local plugin = {}
plugin.name = 'setwelcome'
plugin.category = 'admin'
plugin.description = 'Set the welcome message for new members'
plugin.commands = { 'setwelcome', 'welcome' }
plugin.help = '/setwelcome <message> - Sets the welcome message. Placeholders: $name, $title, $id, $username, $mention'
plugin.group_only = true
plugin.admin_only = true
function plugin.on_message(api, message, ctx)
if message.command == 'welcome' and not message.args then
-- Show current welcome message
local result = ctx.db.execute(
'SELECT message FROM welcome_messages WHERE chat_id = $1',
{ message.chat.id }
)
if not result or #result == 0 then
return api.send_message(message.chat.id, 'No welcome message has been set. Use /setwelcome <message> to set one.')
end
return api.send_message(message.chat.id, '<b>Current welcome message:</b>\n\n' .. result[1].message, 'html')
end
if not message.args then
- return api.send_message(message.chat.id, 'Please provide the welcome message text.\n\nPlaceholders: <code>$name</code>, <code>$title</code>, <code>$id</code>, <code>$username</code>, <code>$mention</code>', 'html')
+ return api.send_message(message.chat.id,
+ 'Please provide the welcome message text.\n\n'
+ .. 'Placeholders: <code>$name</code>, <code>$title</code>, '
+ .. '<code>$id</code>, <code>$username</code>, <code>$mention</code>',
+ 'html')
end
ctx.db.upsert('welcome_messages', {
chat_id = message.chat.id,
message = message.args
}, { 'chat_id' }, { 'message' })
api.send_message(message.chat.id, 'The welcome message has been updated.')
end
return plugin
diff --git a/src/plugins/ai/ai.lua b/src/plugins/ai/ai.lua
index 854350c..1659897 100644
--- a/src/plugins/ai/ai.lua
+++ b/src/plugins/ai/ai.lua
@@ -1,260 +1,262 @@
--[[
mattata v2.0 - AI Plugin
AI-powered chat using OpenAI or Anthropic API.
Must be enabled via AI_ENABLED=true in configuration.
]]
local plugin = {}
plugin.name = 'ai'
plugin.category = 'ai'
plugin.description = 'Chat with an AI assistant'
plugin.commands = { 'ai', 'ask' }
plugin.help = '/ai <prompt> - Send a prompt to the AI assistant and receive a response.'
local MAX_HISTORY = 10
-local SYSTEM_PROMPT = 'You are a helpful assistant embedded in a Telegram bot called mattata. Be concise and direct in your responses. Use Telegram-compatible formatting (bold, italic, code) when helpful.'
+local SYSTEM_PROMPT = 'You are a helpful assistant embedded in a Telegram bot called mattata. '
+ .. 'Be concise and direct in your responses. '
+ .. 'Use Telegram-compatible formatting (bold, italic, code) when helpful.'
-- Build a Redis key for conversation history
local function history_key(chat_id, user_id)
return string.format('ai:history:%s:%s', tostring(chat_id), tostring(user_id))
end
-- Retrieve recent conversation history from Redis
local function get_history(redis, chat_id, user_id)
local json = require('dkjson')
local key = history_key(chat_id, user_id)
local raw = redis.lrange(key, 0, MAX_HISTORY * 2 - 1)
local messages = {}
if raw and #raw > 0 then
for _, entry in ipairs(raw) do
local msg = json.decode(entry)
if msg then
table.insert(messages, msg)
end
end
end
return messages
end
-- Append a message to conversation history
local function push_history(redis, chat_id, user_id, role, content)
local json = require('dkjson')
local key = history_key(chat_id, user_id)
redis.rpush(key, json.encode({ role = role, content = content }))
-- Trim to keep only recent messages
redis.ltrim(key, -(MAX_HISTORY * 2), -1)
-- Auto-expire after 1 hour of inactivity
redis.expire(key, 3600)
end
-- Call OpenAI Chat Completions API
local function call_openai(api_key, model, messages)
local https = require('ssl.https')
local json = require('dkjson')
local ltn12 = require('ltn12')
local request_body = json.encode({
model = model,
messages = messages,
max_tokens = 1024
})
local response_body = {}
local res, code = https.request({
url = 'https://api.openai.com/v1/chat/completions',
method = 'POST',
sink = ltn12.sink.table(response_body),
source = ltn12.source.string(request_body),
headers = {
['Authorization'] = 'Bearer ' .. api_key,
['Content-Type'] = 'application/json',
['Content-Length'] = tostring(#request_body)
}
})
if not res or code ~= 200 then
return nil, 'OpenAI API request failed (HTTP ' .. tostring(code) .. ').'
end
local data = json.decode(table.concat(response_body))
if not data or not data.choices or #data.choices == 0 then
return nil, 'No response from OpenAI.'
end
return data.choices[1].message and data.choices[1].message.content or nil
end
-- Call Anthropic Messages API
local function call_anthropic(api_key, model, messages)
local https = require('ssl.https')
local json = require('dkjson')
local ltn12 = require('ltn12')
-- Convert from OpenAI message format; extract system prompt
local system_text = nil
local api_messages = {}
for _, msg in ipairs(messages) do
if msg.role == 'system' then
system_text = msg.content
else
table.insert(api_messages, { role = msg.role, content = msg.content })
end
end
local request_body = json.encode({
model = model,
max_tokens = 1024,
system = system_text or SYSTEM_PROMPT,
messages = api_messages
})
local response_body = {}
local res, code = https.request({
url = 'https://api.anthropic.com/v1/messages',
method = 'POST',
sink = ltn12.sink.table(response_body),
source = ltn12.source.string(request_body),
headers = {
['x-api-key'] = api_key,
['anthropic-version'] = '2023-06-01',
['Content-Type'] = 'application/json',
['Content-Length'] = tostring(#request_body)
}
})
if not res or code ~= 200 then
return nil, 'Anthropic API request failed (HTTP ' .. tostring(code) .. ').'
end
local data = json.decode(table.concat(response_body))
if not data or not data.content or #data.content == 0 then
return nil, 'No response from Anthropic.'
end
return data.content[1].text
end
-- Main dispatch: pick provider and call
local function get_ai_response(ai_config, messages)
if ai_config.anthropic_key then
return call_anthropic(ai_config.anthropic_key, ai_config.anthropic_model, messages)
elseif ai_config.openai_key then
return call_openai(ai_config.openai_key, ai_config.openai_model, messages)
end
return nil, 'No AI API key has been configured.'
end
function plugin.on_message(api, message, ctx)
local ai_config = ctx.config.ai()
if not ai_config.enabled then
return api.send_message(message.chat.id, 'The AI feature is currently disabled.')
end
local input = message.args
-- If replying to a message, prepend the quoted text for context
if (not input or input == '') and message.reply and message.reply.text and message.reply.text ~= '' then
input = message.reply.text
end
if not input or input == '' then
return api.send_message(message.chat.id, 'Please provide a prompt, e.g. <code>/ai What is the capital of France?</code>', 'html')
end
-- Send typing action while processing
api.send_chat_action(message.chat.id, 'typing')
-- Build message history
local history = get_history(ctx.redis, message.chat.id, message.from.id)
local messages = {
{ role = 'system', content = SYSTEM_PROMPT }
}
for _, msg in ipairs(history) do
table.insert(messages, msg)
end
table.insert(messages, { role = 'user', content = input })
local response, err = get_ai_response(ai_config, messages)
if not response then
return api.send_message(message.chat.id, err or 'Failed to get a response from the AI.')
end
-- Store conversation turn
push_history(ctx.redis, message.chat.id, message.from.id, 'user', input)
push_history(ctx.redis, message.chat.id, message.from.id, 'assistant', response)
-- Truncate if response exceeds Telegram's 4096 character limit
if #response > 4096 then
response = response:sub(1, 4090) .. '\n...'
end
return api.send_message(message.chat.id, response, nil, true, false, message.message_id)
end
-- Respond to @mentions and DMs passively if AI is enabled
function plugin.on_new_message(api, message, ctx)
local ai_config = ctx.config.ai()
if not ai_config.enabled then
return
end
-- Skip if this was already handled as a command
if message.text and message.text:match('^[/!#]') then
return
end
local text = message.text or ''
local is_mention = false
local is_dm = message.chat and message.chat.type == 'private'
-- Check for @bot_username mentions in entities
if message.entities then
for _, entity in ipairs(message.entities) do
if entity.type == 'mention' then
local mention = text:sub(entity.offset + 1, entity.offset + entity.length)
if mention:lower() == '@' .. api.info.username:lower() then
is_mention = true
-- Strip the mention from the input
text = text:sub(1, entity.offset) .. text:sub(entity.offset + entity.length + 1)
text = text:match('^%s*(.-)%s*$') -- trim
break
end
end
end
end
if not is_mention and not is_dm then
return
end
if text == '' then
return
end
-- Send typing action
api.send_chat_action(message.chat.id, 'typing')
local history = get_history(ctx.redis, message.chat.id, message.from.id)
local messages = {
{ role = 'system', content = SYSTEM_PROMPT }
}
for _, msg in ipairs(history) do
table.insert(messages, msg)
end
table.insert(messages, { role = 'user', content = text })
- local response, err = get_ai_response(ai_config, messages)
+ local response, _ = get_ai_response(ai_config, messages)
if not response then
return
end
push_history(ctx.redis, message.chat.id, message.from.id, 'user', text)
push_history(ctx.redis, message.chat.id, message.from.id, 'assistant', response)
if #response > 4096 then
response = response:sub(1, 4090) .. '\n...'
end
return api.send_message(message.chat.id, response, nil, true, false, message.message_id)
end
return plugin
diff --git a/src/plugins/fun/catfact.lua b/src/plugins/fun/catfact.lua
index ba265c5..1321f93 100644
--- a/src/plugins/fun/catfact.lua
+++ b/src/plugins/fun/catfact.lua
@@ -1,42 +1,42 @@
--[[
mattata v2.0 - Cat Fact Plugin
Fetches a real cat fact from the catfact.ninja API.
]]
local plugin = {}
plugin.name = 'catfact'
plugin.category = 'fun'
plugin.description = 'Get a random real cat fact'
plugin.commands = { 'catfact', 'cfact' }
plugin.help = '/catfact - Get a random cat fact from catfact.ninja.'
function plugin.on_message(api, message, ctx)
local https = require('ssl.https')
local json = require('dkjson')
local ltn12 = require('ltn12')
local response_body = {}
local res, code = https.request({
url = 'https://catfact.ninja/fact',
method = 'GET',
headers = {
['Accept'] = 'application/json'
},
sink = ltn12.sink.table(response_body)
})
if not res or code ~= 200 then
return api.send_message(message.chat.id, 'Failed to fetch a cat fact. Try again later.')
end
local body = table.concat(response_body)
- local data, _, err = json.decode(body)
+ local data, _ = json.decode(body)
if not data or not data.fact then
return api.send_message(message.chat.id, 'Failed to parse cat fact response. Try again later.')
end
local output = string.format('\xF0\x9F\x90\xB1 <b>Cat Fact:</b> %s', data.fact)
return api.send_message(message.chat.id, output, 'html')
end
return plugin
diff --git a/src/plugins/fun/game.lua b/src/plugins/fun/game.lua
index e7048f5..74f1003 100644
--- a/src/plugins/fun/game.lua
+++ b/src/plugins/fun/game.lua
@@ -1,208 +1,208 @@
--[[
mattata v2.0 - Game Plugin
Tic-tac-toe with inline keyboard buttons. Two players take turns.
Game state stored in Redis as JSON.
]]
local plugin = {}
plugin.name = 'game'
plugin.category = 'fun'
plugin.description = 'Play tic-tac-toe with another user'
plugin.commands = { 'game', 'tictactoe' }
plugin.help = '/game - Start a tic-tac-toe game. Another user clicks a cell to join as O.'
local json = require('dkjson')
local EMPTY = ' '
local X = 'X'
local O = 'O'
-- Symbols for display on buttons
local DISPLAY = {
[EMPTY] = '\xE2\xAC\x9C', -- white square
[X] = '\xE2\x9D\x8C', -- cross mark
[O] = '\xE2\xAD\x95', -- hollow circle
}
local function game_key(chat_id, message_id)
return 'ttt:' .. chat_id .. ':' .. message_id
end
local function new_board()
return {
EMPTY, EMPTY, EMPTY,
EMPTY, EMPTY, EMPTY,
EMPTY, EMPTY, EMPTY
}
end
local WIN_LINES = {
{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, -- rows
{1, 4, 7}, {2, 5, 8}, {3, 6, 9}, -- columns
{1, 5, 9}, {3, 5, 7} -- diagonals
}
local function check_winner(board)
for _, line in ipairs(WIN_LINES) do
local a, b, c = board[line[1]], board[line[2]], board[line[3]]
if a ~= EMPTY and a == b and b == c then
return a
end
end
-- Check for draw
for _, cell in ipairs(board) do
if cell == EMPTY then
return nil -- game still in progress
end
end
return 'draw'
end
local function build_keyboard(api, board, game_over)
local keyboard = api.inline_keyboard()
for row = 0, 2 do
local r = api.row()
for col = 1, 3 do
local idx = row * 3 + col
local label = DISPLAY[board[idx]]
if game_over then
r:callback_data_button(label, 'game:noop')
else
r:callback_data_button(label, 'game:move:' .. idx)
end
end
keyboard:row(r)
end
return keyboard
end
local function format_status(game_state, winner)
local tools = require('telegram-bot-lua.tools')
local x_name = tools.escape_html(game_state.x_name or 'Player X')
local o_name = tools.escape_html(game_state.o_name or '???')
if winner == 'draw' then
return string.format(
'<b>Tic-Tac-Toe</b>\n%s %s vs %s %s\n\nIt\'s a draw!',
DISPLAY[X], x_name, DISPLAY[O], o_name
)
elseif winner == X then
return string.format(
'<b>Tic-Tac-Toe</b>\n%s %s vs %s %s\n\n%s %s wins!',
DISPLAY[X], x_name, DISPLAY[O], o_name, DISPLAY[X], x_name
)
elseif winner == O then
return string.format(
'<b>Tic-Tac-Toe</b>\n%s %s vs %s %s\n\n%s %s wins!',
DISPLAY[X], x_name, DISPLAY[O], o_name, DISPLAY[O], o_name
)
else
local turn_name = game_state.turn == X and x_name or o_name
local turn_symbol = DISPLAY[game_state.turn]
if not game_state.o_id then
return string.format(
'<b>Tic-Tac-Toe</b>\n%s %s vs %s ???\n\n%s is waiting for an opponent. Click a cell to join!',
DISPLAY[X], x_name, DISPLAY[O], x_name
)
end
return string.format(
'<b>Tic-Tac-Toe</b>\n%s %s vs %s %s\n\n%s %s\'s turn',
DISPLAY[X], x_name, DISPLAY[O], o_name, turn_symbol, turn_name
)
end
end
function plugin.on_message(api, message, ctx)
local board = new_board()
local game_state = {
board = board,
turn = X,
x_id = message.from.id,
x_name = message.from.first_name or 'Player X',
o_id = nil,
o_name = nil
}
local status = format_status(game_state, nil)
local keyboard = build_keyboard(api, board, false)
local result = api.send_message(message.chat.id, status, 'html', true, false, nil, keyboard)
if result and result.result and result.result.message_id then
local key = game_key(message.chat.id, result.result.message_id)
ctx.redis.setex(key, 3600, json.encode(game_state))
end
end
function plugin.on_callback_query(api, callback_query, message, ctx)
local data = callback_query.data
if data == 'noop' then
return api.answer_callback_query(callback_query.id)
end
local idx = tonumber(data:match('^move:(%d+)$'))
if not idx or idx < 1 or idx > 9 then
return api.answer_callback_query(callback_query.id, 'Invalid move.')
end
local key = game_key(message.chat.id, message.message_id)
local raw = ctx.redis.get(key)
if not raw then
return api.answer_callback_query(callback_query.id, 'This game has expired.')
end
- local game_state, _, err = json.decode(raw)
+ local game_state, _ = json.decode(raw)
if not game_state then
return api.answer_callback_query(callback_query.id, 'Failed to load game state.')
end
local user_id = callback_query.from.id
local user_name = callback_query.from.first_name or 'Unknown'
-- If no opponent yet, the first person who clicks (that isn't X) becomes O
if not game_state.o_id then
if user_id == game_state.x_id then
return api.answer_callback_query(callback_query.id, 'Waiting for an opponent to join. Another user must click a cell.')
end
game_state.o_id = user_id
game_state.o_name = user_name
end
-- Check it's this user's turn
local expected_id = game_state.turn == X and game_state.x_id or game_state.o_id
if user_id ~= expected_id then
if user_id ~= game_state.x_id and user_id ~= game_state.o_id then
return api.answer_callback_query(callback_query.id, 'You are not a player in this game.')
end
return api.answer_callback_query(callback_query.id, 'It\'s not your turn.')
end
-- Check cell is empty
if game_state.board[idx] ~= EMPTY then
return api.answer_callback_query(callback_query.id, 'That cell is already taken.')
end
-- Make the move
game_state.board[idx] = game_state.turn
local winner = check_winner(game_state.board)
if winner then
-- Game over
local status = format_status(game_state, winner)
local keyboard = build_keyboard(api, game_state.board, true)
ctx.redis.del(key)
api.answer_callback_query(callback_query.id)
return api.edit_message_text(message.chat.id, message.message_id, status, 'html', true, keyboard)
end
-- Switch turns
game_state.turn = game_state.turn == X and O or X
local status = format_status(game_state, nil)
local keyboard = build_keyboard(api, game_state.board, false)
ctx.redis.setex(key, 3600, json.encode(game_state))
api.answer_callback_query(callback_query.id)
return api.edit_message_text(message.chat.id, message.message_id, status, 'html', true, keyboard)
end
return plugin
diff --git a/src/plugins/fun/quote.lua b/src/plugins/fun/quote.lua
index 2fd5eec..a6d9a25 100644
--- a/src/plugins/fun/quote.lua
+++ b/src/plugins/fun/quote.lua
@@ -1,62 +1,62 @@
--[[
mattata v2.0 - Quote Plugin
Save and retrieve random quotes per chat. Stores in Redis set quotes:{chat_id}.
]]
local plugin = {}
plugin.name = 'quote'
plugin.category = 'fun'
plugin.description = 'Save and retrieve random quotes'
plugin.commands = { 'quote', 'q', 'save' }
plugin.help = '/save - Save the replied message as a quote.\n/quote - Retrieve a random saved quote from this chat.'
function plugin.on_message(api, message, ctx)
local tools = require('telegram-bot-lua.tools')
local json = require('dkjson')
local redis = ctx.redis
local chat_id = message.chat.id
local key = 'quotes:' .. chat_id
if message.command == 'save' then
-- Save a quote from a reply
if not message.reply then
return api.send_message(chat_id, 'Please use /save in reply to a message you want to save as a quote.')
end
local quote_text = message.reply.text
if not quote_text or quote_text == '' then
return api.send_message(chat_id, 'The replied message has no text to save.')
end
local author = message.reply.from and message.reply.from.first_name or 'Unknown'
local quote_data = json.encode({
text = quote_text,
author = author,
author_id = message.reply.from and message.reply.from.id,
saved_by = message.from.first_name,
saved_at = os.time()
})
redis.sadd(key, quote_data)
return api.send_message(chat_id, 'Quote saved successfully.')
end
-- Retrieve a random quote
local quotes = redis.smembers(key)
if not quotes or #quotes == 0 then
return api.send_message(chat_id, 'No quotes saved in this chat yet. Use /save in reply to a message to save one.')
end
math.randomseed(os.time() + os.clock() * 1000)
local raw = quotes[math.random(#quotes)]
- local quote, _, err = json.decode(raw)
+ local quote, _ = json.decode(raw)
if not quote then
return api.send_message(chat_id, 'Failed to read quote data.')
end
local output = string.format(
'\xE2\x80\x9C%s\xE2\x80\x9D\n\n\xE2\x80\x94 %s',
tools.escape_html(quote.text),
tools.escape_html(quote.author)
)
return api.send_message(chat_id, output, 'html')
end
return plugin
diff --git a/src/plugins/media/cats.lua b/src/plugins/media/cats.lua
index a7c8d59..2fed34a 100644
--- a/src/plugins/media/cats.lua
+++ b/src/plugins/media/cats.lua
@@ -1,50 +1,50 @@
--[[
mattata v2.0 - Cats Plugin
Sends a random cat image from TheCatAPI.
]]
local plugin = {}
plugin.name = 'cats'
plugin.category = 'media'
plugin.description = 'Get a random cat image'
plugin.commands = { 'cat', 'cats' }
plugin.help = '/cat - Sends a random cat image.'
function plugin.on_message(api, message, ctx)
local https = require('ssl.https')
local json = require('dkjson')
local ltn12 = require('ltn12')
local response_body = {}
local res, code = https.request({
url = 'https://api.thecatapi.com/v1/images/search',
method = 'GET',
sink = ltn12.sink.table(response_body),
headers = {
['Accept'] = 'application/json'
}
})
if not res or code ~= 200 then
return api.send_message(message.chat.id, 'Failed to fetch a cat image. Please try again later.')
end
local body = table.concat(response_body)
- local data, _, err = json.decode(body)
+ local data, _ = json.decode(body)
if not data or #data == 0 then
return api.send_message(message.chat.id, 'No cat images found. Please try again later.')
end
local image_url = data[1].url
if not image_url then
return api.send_message(message.chat.id, 'Failed to parse the cat image response.')
end
-- Send as animation if it's a gif, otherwise as photo
if image_url:lower():match('%.gif$') then
return api.send_animation(message.chat.id, image_url)
end
return api.send_photo(message.chat.id, image_url)
end
return plugin
diff --git a/src/plugins/media/gif.lua b/src/plugins/media/gif.lua
index f587ba8..e2eccee 100644
--- a/src/plugins/media/gif.lua
+++ b/src/plugins/media/gif.lua
@@ -1,63 +1,63 @@
--[[
mattata v2.0 - GIF Plugin
Searches for GIFs using the Tenor API and sends them as animations.
]]
local plugin = {}
plugin.name = 'gif'
plugin.category = 'media'
plugin.description = 'Search for GIFs using Tenor'
plugin.commands = { 'gif', 'tenor' }
plugin.help = '/gif <query> - Search for a GIF and send it.'
local TENOR_KEY = 'AIzaSyAyimkuYQYF_FXVALexPuGQctUWRURdCYQ'
function plugin.on_message(api, message, ctx)
local https = require('ssl.https')
local json = require('dkjson')
local url = require('socket.url')
local ltn12 = require('ltn12')
if not message.args or message.args == '' then
return api.send_message(message.chat.id, 'Please specify a search query, e.g. <code>/gif funny cats</code>.', 'html')
end
local query = url.escape(message.args)
local api_url = string.format(
'https://tenor.googleapis.com/v2/search?q=%s&key=%s&limit=1&media_filter=gif',
query, TENOR_KEY
)
local response_body = {}
local res, code = https.request({
url = api_url,
method = 'GET',
sink = ltn12.sink.table(response_body),
headers = {
['Accept'] = 'application/json'
}
})
if not res or code ~= 200 then
return api.send_message(message.chat.id, 'Failed to search Tenor. Please try again later.')
end
local body = table.concat(response_body)
- local data, _, err = json.decode(body)
+ local data, _ = json.decode(body)
if not data or not data.results or #data.results == 0 then
return api.send_message(message.chat.id, 'No GIFs found for that query.')
end
local result = data.results[1]
local gif_url = result.media_formats
and result.media_formats.gif
and result.media_formats.gif.url
if not gif_url then
return api.send_message(message.chat.id, 'Failed to retrieve the GIF URL.')
end
return api.send_animation(message.chat.id, gif_url)
end
return plugin
diff --git a/src/plugins/media/itunes.lua b/src/plugins/media/itunes.lua
index 65310d9..9045c17 100644
--- a/src/plugins/media/itunes.lua
+++ b/src/plugins/media/itunes.lua
@@ -1,93 +1,93 @@
--[[
mattata v2.0 - iTunes Plugin
Searches the iTunes Store for tracks.
]]
local plugin = {}
plugin.name = 'itunes'
plugin.category = 'media'
plugin.description = 'Search the iTunes Store for tracks'
plugin.commands = { 'itunes' }
plugin.help = '/itunes <query> - Search iTunes for a track and return song info with pricing.'
function plugin.on_message(api, message, ctx)
local https = require('ssl.https')
local json = require('dkjson')
local url = require('socket.url')
local tools = require('telegram-bot-lua.tools')
local ltn12 = require('ltn12')
if not message.args or message.args == '' then
return api.send_message(message.chat.id, 'Please specify a search query, e.g. <code>/itunes imagine dragons believer</code>.', 'html')
end
local query = url.escape(message.args)
local api_url = string.format(
'https://itunes.apple.com/search?term=%s&media=music&entity=song&limit=1',
query
)
local response_body = {}
local res, code = https.request({
url = api_url,
method = 'GET',
sink = ltn12.sink.table(response_body),
headers = {
['Accept'] = 'application/json'
}
})
if not res or code ~= 200 then
return api.send_message(message.chat.id, 'Failed to search iTunes. Please try again later.')
end
local body = table.concat(response_body)
- local data, _, err = json.decode(body)
+ local data, _ = json.decode(body)
if not data or not data.results or #data.results == 0 then
return api.send_message(message.chat.id, 'No results found for that query.')
end
local track = data.results[1]
local track_name = track.trackName or 'Unknown'
local artist_name = track.artistName or 'Unknown'
local album_name = track.collectionName or 'Unknown'
local track_url = track.trackViewUrl or ''
local artwork_url = track.artworkUrl100 or ''
-- Format price
local price = 'N/A'
if track.trackPrice and track.currency then
if track.trackPrice < 0 then
price = 'Not available for individual sale'
else
price = string.format('%s %.2f', track.currency, track.trackPrice)
end
end
local output = string.format(
'<b>%s</b>\nArtist: %s\nAlbum: %s\nPrice: %s',
tools.escape_html(track_name),
tools.escape_html(artist_name),
tools.escape_html(album_name),
tools.escape_html(price)
)
if track_url ~= '' then
output = output .. string.format('\n<a href="%s">View on iTunes</a>', tools.escape_html(track_url))
end
-- Send artwork as photo with caption if available
if artwork_url ~= '' then
-- Use higher resolution artwork
local hires_url = artwork_url:gsub('100x100', '600x600')
local success = api.send_photo(message.chat.id, hires_url, output, 'html')
if success then
return success
end
end
-- Fallback to text-only
return api.send_message(message.chat.id, output, 'html', true)
end
return plugin
diff --git a/src/plugins/media/youtube.lua b/src/plugins/media/youtube.lua
index a8b4b7f..4f31c0e 100644
--- a/src/plugins/media/youtube.lua
+++ b/src/plugins/media/youtube.lua
@@ -1,105 +1,105 @@
--[[
mattata v2.0 - YouTube Plugin
Searches YouTube using the Data API v3 and returns the top result.
]]
local plugin = {}
plugin.name = 'youtube'
plugin.category = 'media'
plugin.description = 'Search YouTube for videos'
plugin.commands = { 'youtube', 'yt' }
plugin.help = '/youtube <query> - Search YouTube and return the top result with title, channel, and views.'
function plugin.on_message(api, message, ctx)
local https = require('ssl.https')
local json = require('dkjson')
local url = require('socket.url')
local tools = require('telegram-bot-lua.tools')
local ltn12 = require('ltn12')
local api_key = ctx.config.get('YOUTUBE_API_KEY')
if not api_key then
return api.send_message(message.chat.id, 'The YouTube API key has not been configured.')
end
if not message.args or message.args == '' then
return api.send_message(message.chat.id, 'Please specify a search query, e.g. <code>/yt never gonna give you up</code>.', 'html')
end
-- Step 1: Search for videos
local query = url.escape(message.args)
local search_url = string.format(
'https://www.googleapis.com/youtube/v3/search?part=snippet&type=video&maxResults=1&q=%s&key=%s',
query, api_key
)
local response_body = {}
local res, code = https.request({
url = search_url,
method = 'GET',
sink = ltn12.sink.table(response_body),
headers = {
['Accept'] = 'application/json'
}
})
if not res or code ~= 200 then
return api.send_message(message.chat.id, 'Failed to search YouTube. Please try again later.')
end
local body = table.concat(response_body)
- local data, _, err = json.decode(body)
+ local data, _ = json.decode(body)
if not data or not data.items or #data.items == 0 then
return api.send_message(message.chat.id, 'No results found for that query.')
end
local item = data.items[1]
local video_id = item.id and item.id.videoId
local title = item.snippet and item.snippet.title or 'Unknown'
local channel = item.snippet and item.snippet.channelTitle or 'Unknown'
if not video_id then
return api.send_message(message.chat.id, 'Failed to parse the YouTube search results.')
end
-- Step 2: Fetch video statistics
local stats_url = string.format(
'https://www.googleapis.com/youtube/v3/videos?part=statistics&id=%s&key=%s',
video_id, api_key
)
local stats_body = {}
local stats_res, stats_code = https.request({
url = stats_url,
method = 'GET',
sink = ltn12.sink.table(stats_body),
headers = {
['Accept'] = 'application/json'
}
})
local views = 'N/A'
if stats_res and stats_code == 200 then
local stats_data = json.decode(table.concat(stats_body))
if stats_data and stats_data.items and #stats_data.items > 0 then
local stats = stats_data.items[1].statistics
if stats and stats.viewCount then
-- Format view count with commas
views = tostring(stats.viewCount):reverse():gsub('(%d%d%d)', '%1,'):reverse():gsub('^,', '')
end
end
end
local video_url = 'https://youtu.be/' .. video_id
local output = string.format(
'<a href="%s">%s</a>\nChannel: %s\nViews: %s',
tools.escape_html(video_url),
tools.escape_html(title),
tools.escape_html(channel),
views
)
return api.send_message(message.chat.id, output, 'html', true)
end
return plugin
diff --git a/src/plugins/utility/about.lua b/src/plugins/utility/about.lua
index 27a5893..2fec74e 100644
--- a/src/plugins/utility/about.lua
+++ b/src/plugins/utility/about.lua
@@ -1,23 +1,22 @@
--[[
mattata v2.0 - About Plugin
]]
local plugin = {}
plugin.name = 'about'
plugin.category = 'utility'
plugin.description = 'View information about the bot'
plugin.commands = { 'about' }
plugin.help = '/about - View information about the bot.'
plugin.permanent = true
function plugin.on_message(api, message, ctx)
- local tools = require('telegram-bot-lua.tools')
local config = require('src.core.config')
local output = string.format(
'Created by <a href="tg://user?id=221714512">Matt</a>. Powered by <code>mattata v%s</code>. Source code available <a href="https://github.com/wrxck/mattata">on GitHub</a>.',
config.VERSION
)
return api.send_message(message.chat.id, output, 'html')
end
return plugin
diff --git a/src/plugins/utility/afk.lua b/src/plugins/utility/afk.lua
index 00ea42c..100f0fe 100644
--- a/src/plugins/utility/afk.lua
+++ b/src/plugins/utility/afk.lua
@@ -1,149 +1,149 @@
--[[
mattata v2.0 - AFK Plugin
Tracks AFK status for users. Notifies when an AFK user is mentioned.
Automatically marks users as returned when they send a message.
Uses ctx.session for AFK state management (backed by Redis).
]]
local plugin = {}
plugin.name = 'afk'
plugin.category = 'utility'
plugin.description = 'Set and track AFK status'
plugin.commands = { 'afk' }
plugin.help = '/afk [reason] - Mark yourself as AFK. Send any message to return.'
local tools = require('telegram-bot-lua.tools')
-- Format a time difference into a human-readable string
local function format_time_ago(seconds)
if seconds < 60 then
return 'just now'
elseif seconds < 3600 then
local mins = math.floor(seconds / 60)
return mins .. ' minute' .. (mins == 1 and '' or 's') .. ' ago'
elseif seconds < 86400 then
local hours = math.floor(seconds / 3600)
local mins = math.floor((seconds % 3600) / 60)
local result = hours .. ' hour' .. (hours == 1 and '' or 's')
if mins > 0 then
result = result .. ', ' .. mins .. ' min'
end
return result .. ' ago'
else
local days = math.floor(seconds / 86400)
local hours = math.floor((seconds % 86400) / 3600)
local result = days .. ' day' .. (days == 1 and '' or 's')
if hours > 0 then
result = result .. ', ' .. hours .. 'h'
end
return result .. ' ago'
end
end
-- Check if a user is mentioned in the message (by @username or text_mention entity)
local function get_mentioned_user_ids(message, redis)
local mentioned = {}
if not message.entities then
return mentioned
end
for _, entity in ipairs(message.entities) do
if entity.type == 'mention' and message.text then
-- Extract @username
local username = message.text:sub(entity.offset + 1, entity.offset + entity.length)
username = username:gsub('^@', ''):lower()
-- Look up user ID from username cache
local user_id = redis.get('username:' .. username)
if user_id then
table.insert(mentioned, tonumber(user_id))
end
elseif entity.type == 'text_mention' and entity.user then
table.insert(mentioned, entity.user.id)
end
end
return mentioned
end
-- /afk command handler
function plugin.on_message(api, message, ctx)
local note = message.args
if note and note == '' then
note = nil
end
ctx.session.set_afk(message.from.id, note)
local output
if note then
output = string.format(
'<b>%s</b> is now AFK: <i>%s</i>',
tools.escape_html(message.from.first_name),
tools.escape_html(note)
)
else
output = string.format(
'<b>%s</b> is now AFK.',
tools.escape_html(message.from.first_name)
)
end
return api.send_message(message.chat.id, output, 'html')
end
-- Passive handler: runs on every message (not just commands)
function plugin.on_new_message(api, message, ctx)
if not message.from then return end
local session = ctx.session
local redis = ctx.redis
-- Check if the sender was AFK and auto-return them
-- Skip if they just sent the /afk command itself
- if not (message.command == 'afk') then
+ if message.command ~= 'afk' then
local afk_data = session.get_afk(message.from.id)
if afk_data then
session.clear_afk(message.from.id)
local elapsed = os.time() - (afk_data.since or os.time())
local output = string.format(
'<b>%s</b> is no longer AFK (was away for %s).',
tools.escape_html(message.from.first_name),
format_time_ago(elapsed)
)
api.send_message(message.chat.id, output, 'html')
end
end
-- Check if any mentioned user is AFK
local mentioned_ids = get_mentioned_user_ids(message, redis)
for _, user_id in ipairs(mentioned_ids) do
-- Don't notify about yourself
if user_id ~= message.from.id then
local afk_data = session.get_afk(user_id)
if afk_data then
-- Rate-limit: only notify once per AFK user per chat per conversation
local replied_key = string.format('afk:%d:replied:%d:%d', user_id, message.chat.id, message.from.id)
local already_replied = redis.get(replied_key)
if not already_replied then
redis.setex(replied_key, 300, '1') -- 5 minute cooldown
local elapsed = os.time() - (afk_data.since or os.time())
local output
if afk_data.note then
output = string.format(
'That user is currently AFK (%s): <i>%s</i>',
format_time_ago(elapsed),
tools.escape_html(afk_data.note)
)
else
output = string.format(
'That user is currently AFK (%s).',
format_time_ago(elapsed)
)
end
api.send_message(message.chat.id, output, 'html')
end
end
end
end
end
return plugin
diff --git a/src/plugins/utility/currency.lua b/src/plugins/utility/currency.lua
index a49bbb4..b91359a 100644
--- a/src/plugins/utility/currency.lua
+++ b/src/plugins/utility/currency.lua
@@ -1,157 +1,147 @@
--[[
mattata v2.0 - Currency Plugin
Currency conversion using the frankfurter.app API (free, no key needed).
Frankfurter uses ECB (European Central Bank) rates.
]]
local plugin = {}
plugin.name = 'currency'
plugin.category = 'utility'
plugin.description = 'Convert between currencies'
plugin.commands = { 'currency', 'convert', 'cash' }
plugin.help = '/currency <amount> <from> to <to> - Convert between currencies.\nExample: /currency 10 USD to EUR'
local https = require('ssl.https')
local json = require('dkjson')
local ltn12 = require('ltn12')
local tools = require('telegram-bot-lua.tools')
local function convert(amount, from, to)
local request_url = string.format(
'https://api.frankfurter.app/latest?amount=%.2f&from=%s&to=%s',
amount, from:upper(), to:upper()
)
local body = {}
local _, code = https.request({
url = request_url,
sink = ltn12.sink.table(body)
})
if code ~= 200 then
return nil, 'Currency conversion request failed. Check that the currency codes are valid.'
end
local data = json.decode(table.concat(body))
if not data then
return nil, 'Failed to parse conversion response.'
end
if data.message then
return nil, 'API error: ' .. tostring(data.message)
end
if not data.rates then
return nil, 'No conversion rates returned. Check your currency codes.'
end
local target_key = to:upper()
if not data.rates[target_key] then
return nil, 'Currency "' .. target_key .. '" is not supported.'
end
return {
amount = data.amount,
from = data.base,
to = target_key,
result = data.rates[target_key],
date = data.date
}
end
-local function get_supported_currencies()
- local body = {}
- local _, code = https.request({
- url = 'https://api.frankfurter.app/currencies',
- sink = ltn12.sink.table(body)
- })
- if code ~= 200 then return nil end
- return json.decode(table.concat(body))
-end
-
local function format_number(n)
if n >= 1 then
return string.format('%.2f', n)
elseif n >= 0.01 then
return string.format('%.4f', n)
else
return string.format('%.6f', n)
end
end
function plugin.on_message(api, message, ctx)
local input = message.args
if not input or input == '' then
return api.send_message(
message.chat.id,
'Please provide a conversion query.\nUsage: <code>/currency 10 USD to EUR</code>',
'html'
)
end
-- Parse: <amount> <from> to <to>
-- Also support: <amount> <from> <to>, <from> to <to> (assume amount=1)
local amount, from, to
-- Try: 10 USD to EUR / 10 USD in EUR
amount, from, to = input:match('^([%d%.]+)%s*(%a+)%s+[tT][oO]%s+(%a+)$')
if not amount then
amount, from, to = input:match('^([%d%.]+)%s*(%a+)%s+[iI][nN]%s+(%a+)$')
end
-- Try: 10 USD EUR
if not amount then
amount, from, to = input:match('^([%d%.]+)%s*(%a+)%s+(%a+)$')
end
-- Try: USD to EUR (amount=1)
if not amount then
from, to = input:match('^(%a+)%s+[tT][oO]%s+(%a+)$')
if from then
amount = '1'
end
end
-- Try: USD EUR (amount=1)
if not amount then
from, to = input:match('^(%a+)%s+(%a+)$')
if from then
amount = '1'
end
end
if not amount or not from or not to then
return api.send_message(
message.chat.id,
'Invalid format. Please use:\n<code>/currency 10 USD to EUR</code>\n<code>/currency USD EUR</code>',
'html'
)
end
amount = tonumber(amount)
if not amount or amount <= 0 then
return api.send_message(message.chat.id, 'Please enter a valid positive number for the amount.')
end
if amount > 999999999 then
return api.send_message(message.chat.id, 'Amount is too large.')
end
from = from:upper()
to = to:upper()
if from == to then
return api.send_message(
message.chat.id,
string.format('<b>%s %s</b> = <b>%s %s</b>', format_number(amount), tools.escape_html(from), format_number(amount), tools.escape_html(to)),
'html'
)
end
local result, err = convert(amount, from, to)
if not result then
return api.send_message(message.chat.id, err)
end
local output = string.format(
'<b>%s %s</b> = <b>%s %s</b>\n<i>Rate as of %s (ECB)</i>',
format_number(result.amount),
tools.escape_html(result.from),
format_number(result.result),
tools.escape_html(result.to),
tools.escape_html(result.date)
)
return api.send_message(message.chat.id, output, 'html')
end
return plugin
diff --git a/src/plugins/utility/help.lua b/src/plugins/utility/help.lua
index 15706c6..31c64c4 100644
--- a/src/plugins/utility/help.lua
+++ b/src/plugins/utility/help.lua
@@ -1,162 +1,161 @@
--[[
mattata v2.0 - Help Plugin
Displays help menus with inline keyboard navigation.
]]
local plugin = {}
plugin.name = 'help'
plugin.category = 'utility'
plugin.description = 'View bot help and command list'
plugin.commands = { 'help', 'start' }
plugin.help = '/help [command] - View help menu or get usage info for a specific command.'
plugin.permanent = true
local PER_PAGE = 10
local function get_page(items, page)
local start_idx = (page - 1) * PER_PAGE + 1
local end_idx = math.min(start_idx + PER_PAGE - 1, #items)
local result = {}
for i = start_idx, end_idx do
table.insert(result, items[i])
end
return result, math.ceil(#items / PER_PAGE)
end
local function format_help_list(help_items)
local lines = {}
for _, item in ipairs(help_items) do
local cmd = item.commands[1] and ('/' .. item.commands[1]) or ''
local desc = item.description or ''
table.insert(lines, string.format('%s %s - <em>%s</em>', '\xe2\x80\xa2', cmd, desc))
end
return table.concat(lines, '\n')
end
function plugin.on_message(api, message, ctx)
local tools = require('telegram-bot-lua.tools')
local loader = require('src.core.loader')
-- If argument given, show help for specific command
if message.args and message.args ~= '' then
local input = message.args:match('^/?(%w+)$')
if input then
local target = loader.get_by_command(input:lower())
if target and target.help then
return api.send_message(message.chat.id, 'Usage:\n' .. target.help .. '\n\nTo see all commands, send /help.')
end
return api.send_message(message.chat.id, 'No plugin found matching that command. Send /help to see all available commands.')
end
end
-- Show main help menu
- local bot_name = ctx.config.bot_name()
local name = tools.escape_html(message.from.first_name)
local output = string.format(
'Hey %s! I\'m <b>%s</b>, a feature-rich Telegram bot.\n\nUse the buttons below to navigate my commands, or type <code>/help &lt;command&gt;</code> for details on a specific command.',
name, tools.escape_html(api.info.first_name)
)
local keyboard = api.inline_keyboard():row(
api.row():callback_data_button('Commands', 'help:cmds:1')
:callback_data_button('Admin Help', 'help:acmds:1')
):row(
api.row():callback_data_button('Links', 'help:links')
:callback_data_button('Settings', 'help:settings')
)
return api.send_message(message.chat.id, output, 'html', true, false, nil, keyboard)
end
function plugin.on_callback_query(api, callback_query, message, ctx)
local tools = require('telegram-bot-lua.tools')
local loader = require('src.core.loader')
local data = callback_query.data
if data:match('^cmds:%d+$') then
local page = tonumber(data:match('^cmds:(%d+)$'))
local all_help = loader.get_help(nil)
-- Filter non-admin
local items = {}
for _, h in ipairs(all_help) do
if h.category ~= 'admin' then
table.insert(items, h)
end
end
local page_items, total_pages = get_page(items, page)
if page < 1 then page = total_pages end
if page > total_pages then page = 1 end
page_items, total_pages = get_page(items, page)
local output = format_help_list(page_items)
local keyboard = api.inline_keyboard():row(
api.row():callback_data_button('<', 'help:cmds:' .. (page - 1))
:callback_data_button(page .. '/' .. total_pages, 'help:noop')
:callback_data_button('>', 'help:cmds:' .. (page + 1))
):row(
api.row():callback_data_button('Back', 'help:back')
)
return api.edit_message_text(message.chat.id, message.message_id, output, 'html', true, keyboard)
elseif data:match('^acmds:%d+$') then
local page = tonumber(data:match('^acmds:(%d+)$'))
local items = loader.get_help('admin')
local page_items, total_pages = get_page(items, page)
if page < 1 then page = total_pages end
if page > total_pages then page = 1 end
page_items, total_pages = get_page(items, page)
local output = format_help_list(page_items)
local keyboard = api.inline_keyboard():row(
api.row():callback_data_button('<', 'help:acmds:' .. (page - 1))
:callback_data_button(page .. '/' .. total_pages, 'help:noop')
:callback_data_button('>', 'help:acmds:' .. (page + 1))
):row(
api.row():callback_data_button('Back', 'help:back')
)
return api.edit_message_text(message.chat.id, message.message_id, output, 'html', true, keyboard)
elseif data == 'links' then
local keyboard = api.inline_keyboard():row(
api.row():url_button('Development', 'https://t.me/mattataDev')
:url_button('Channel', 'https://t.me/mattata')
):row(
api.row():url_button('GitHub', 'https://github.com/wrxck/mattata')
:url_button('Support', 'https://t.me/mattataSupport')
):row(
api.row():callback_data_button('Back', 'help:back')
)
return api.edit_message_text(message.chat.id, message.message_id, 'Useful links:', nil, true, keyboard)
elseif data == 'settings' then
local permissions = require('src.core.permissions')
if message.chat.type == 'supergroup' and not permissions.is_group_admin(api, message.chat.id, callback_query.from.id) then
return api.answer_callback_query(callback_query.id, 'You need to be an admin to change settings.')
end
local keyboard = api.inline_keyboard():row(
api.row():callback_data_button('Administration', 'administration:' .. message.chat.id .. ':page:1')
:callback_data_button('Plugins', 'plugins:' .. message.chat.id .. ':page:1')
):row(
api.row():callback_data_button('Back', 'help:back')
)
return api.edit_message_reply_markup(message.chat.id, message.message_id, nil, keyboard)
elseif data == 'back' then
local name = tools.escape_html(callback_query.from.first_name)
local output = string.format(
'Hey %s! I\'m <b>%s</b>, a feature-rich Telegram bot.\n\nUse the buttons below to navigate my commands, or type <code>/help &lt;command&gt;</code> for details on a specific command.',
name, tools.escape_html(api.info.first_name)
)
local keyboard = api.inline_keyboard():row(
api.row():callback_data_button('Commands', 'help:cmds:1')
:callback_data_button('Admin Help', 'help:acmds:1')
):row(
api.row():callback_data_button('Links', 'help:links')
:callback_data_button('Settings', 'help:settings')
)
return api.edit_message_text(message.chat.id, message.message_id, output, 'html', true, keyboard)
elseif data == 'noop' then
return api.answer_callback_query(callback_query.id)
end
end
return plugin
diff --git a/src/plugins/utility/remind.lua b/src/plugins/utility/remind.lua
index 0f696c4..0cc8fe6 100644
--- a/src/plugins/utility/remind.lua
+++ b/src/plugins/utility/remind.lua
@@ -1,272 +1,279 @@
--[[
mattata v2.0 - Remind Plugin
Sets timed reminders stored in Redis with a cron job to check expirations.
Supports duration parsing (e.g., 2h30m, 1d, 45m, 90s).
Max 4 active reminders per chat per user.
]]
local plugin = {}
plugin.name = 'remind'
plugin.category = 'utility'
plugin.description = 'Set and manage reminders'
plugin.commands = { 'remind', 'reminders' }
plugin.help = '/remind <duration> <message> - Set a reminder (e.g., /remind 2h30m take out the bins).\n/reminders - List your active reminders.'
local tools = require('telegram-bot-lua.tools')
local MAX_REMINDERS = 4
local MAX_DURATION = 7 * 24 * 3600 -- 7 days
local REDIS_PREFIX = 'reminder:'
-- Parse a duration string like "2h30m", "1d", "45m", "90s", "1h", "2d12h"
local function parse_duration(str)
if not str or str == '' then
return nil
end
-- Try pure number (assume minutes)
local pure_num = tonumber(str)
if pure_num then
return math.floor(pure_num * 60)
end
local total = 0
local found = false
-- Days
local d = str:match('(%d+)%s*d')
if d then
total = total + tonumber(d) * 86400
found = true
end
-- Hours
local h = str:match('(%d+)%s*h')
if h then
total = total + tonumber(h) * 3600
found = true
end
-- Minutes
local m = str:match('(%d+)%s*m')
if m then
total = total + tonumber(m) * 60
found = true
end
-- Seconds
local s = str:match('(%d+)%s*s')
if s then
total = total + tonumber(s)
found = true
end
if not found or total <= 0 then
return nil
end
return total
end
-- Format seconds into a human-readable string
local function format_duration(seconds)
if seconds < 60 then
return seconds .. ' second' .. (seconds == 1 and '' or 's')
end
local parts = {}
local days = math.floor(seconds / 86400)
seconds = seconds % 86400
local hours = math.floor(seconds / 3600)
seconds = seconds % 3600
local mins = math.floor(seconds / 60)
local secs = seconds % 60
if days > 0 then
table.insert(parts, days .. 'd')
end
if hours > 0 then
table.insert(parts, hours .. 'h')
end
if mins > 0 then
table.insert(parts, mins .. 'm')
end
if secs > 0 and days == 0 then
table.insert(parts, secs .. 's')
end
return table.concat(parts, ' ')
end
-- Get all reminder keys for a user in a chat
local function get_user_reminders(redis, chat_id, user_id)
local pattern = string.format('%s%s:%s:*', REDIS_PREFIX, tostring(chat_id), tostring(user_id))
return redis.keys(pattern) or {}
end
-- Get all reminder keys globally (for cron)
local function get_all_reminders(redis)
return redis.keys(REDIS_PREFIX .. '*') or {}
end
function plugin.on_message(api, message, ctx)
local redis = ctx.redis
-- /reminders - list active reminders
if message.command == 'reminders' then
local keys = get_user_reminders(redis, message.chat.id, message.from.id)
if #keys == 0 then
return api.send_message(message.chat.id, 'You have no active reminders in this chat.')
end
local lines = { '<b>Your active reminders:</b>', '' }
for i, key in ipairs(keys) do
local data = redis.hgetall(key)
if data and data.text then
local expires = tonumber(data.expires) or 0
local remaining = expires - os.time()
if remaining > 0 then
table.insert(lines, string.format(
'%d. %s <i>(in %s)</i>',
i,
tools.escape_html(data.text),
format_duration(remaining)
))
end
end
end
if #lines <= 2 then
return api.send_message(message.chat.id, 'You have no active reminders in this chat.')
end
return api.send_message(message.chat.id, table.concat(lines, '\n'), 'html')
end
-- /remind <duration> <message>
local input = message.args
if not input or input == '' then
return api.send_message(
message.chat.id,
- 'Usage: <code>/remind &lt;duration&gt; &lt;message&gt;</code>\n\nDurations: <code>30m</code>, <code>2h</code>, <code>1d</code>, <code>2h30m</code>\nMax: 7 days. Max 4 reminders per chat.\n\nExamples:\n<code>/remind 30m check the oven</code>\n<code>/remind 2h30m meeting with John</code>\n<code>/remind 1d renew subscription</code>',
+ 'Usage: <code>/remind &lt;duration&gt; &lt;message&gt;</code>\n\n'
+ .. 'Durations: <code>30m</code>, <code>2h</code>, <code>1d</code>, '
+ .. '<code>2h30m</code>\n'
+ .. 'Max: 7 days. Max 4 reminders per chat.\n\n'
+ .. 'Examples:\n'
+ .. '<code>/remind 30m check the oven</code>\n'
+ .. '<code>/remind 2h30m meeting with John</code>\n'
+ .. '<code>/remind 1d renew subscription</code>',
'html'
)
end
-- Parse duration from the first token
local duration_str, reminder_text = input:match('^(%S+)%s+(.+)$')
if not duration_str then
-- Maybe just a duration with no text
duration_str = input
reminder_text = nil
end
local duration = parse_duration(duration_str)
if not duration then
return api.send_message(
message.chat.id,
'Invalid duration format. Use combinations like: <code>30m</code>, <code>2h</code>, <code>1d</code>, <code>2h30m</code>',
'html'
)
end
if not reminder_text or reminder_text == '' then
return api.send_message(message.chat.id, 'Please include a reminder message after the duration.')
end
if duration < 30 then
return api.send_message(message.chat.id, 'Minimum reminder duration is 30 seconds.')
end
if duration > MAX_DURATION then
return api.send_message(message.chat.id, 'Maximum reminder duration is 7 days.')
end
-- Check reminder limit
local existing = get_user_reminders(redis, message.chat.id, message.from.id)
-- Filter to only count non-expired ones
local active_count = 0
for _, key in ipairs(existing) do
local expires = redis.hget(key, 'expires')
if expires and tonumber(expires) > os.time() then
active_count = active_count + 1
else
-- Clean up expired entry
redis.del(key)
end
end
if active_count >= MAX_REMINDERS then
return api.send_message(
message.chat.id,
string.format('You already have %d active reminders in this chat (max %d). Wait for one to expire or use /reminders to check them.', active_count, MAX_REMINDERS)
)
end
-- Truncate long reminder text
if #reminder_text > 500 then
reminder_text = reminder_text:sub(1, 497) .. '...'
end
-- Store reminder
local expires_at = os.time() + duration
local reminder_id = string.format('%s%s:%s:%d',
REDIS_PREFIX,
tostring(message.chat.id),
tostring(message.from.id),
expires_at
)
redis.hset(reminder_id, 'chat_id', tostring(message.chat.id))
redis.hset(reminder_id, 'user_id', tostring(message.from.id))
redis.hset(reminder_id, 'text', reminder_text)
redis.hset(reminder_id, 'expires', tostring(expires_at))
redis.hset(reminder_id, 'first_name', message.from.first_name or 'User')
-- Set Redis TTL slightly beyond expiry for auto-cleanup
local key_ttl = duration + 300
redis.expire(reminder_id, key_ttl)
return api.send_message(
message.chat.id,
string.format(
'Reminder set for <b>%s</b> from now.\n\n<i>%s</i>',
format_duration(duration),
tools.escape_html(reminder_text)
),
'html'
)
end
-- Cron job: runs every minute, checks for expired reminders
function plugin.cron(api, ctx)
local redis = ctx.redis
local keys = get_all_reminders(redis)
local now = os.time()
for _, key in ipairs(keys) do
local data = redis.hgetall(key)
if data and data.expires then
local expires = tonumber(data.expires)
if expires and expires <= now then
-- Send the reminder
local chat_id = data.chat_id
local user_id = data.user_id
local text = data.text or 'Reminder!'
local first_name = data.first_name or 'User'
if chat_id then
local output = string.format(
'<a href="tg://user?id=%s">%s</a>, here is your reminder:\n\n<i>%s</i>',
tostring(user_id),
tools.escape_html(first_name),
tools.escape_html(text)
)
- local ok, err = pcall(function()
+ pcall(function()
api.send_message(tonumber(chat_id), output, 'html')
end)
end
-- Delete the reminder
redis.del(key)
end
end
end
end
return plugin
diff --git a/src/plugins/utility/translate.lua b/src/plugins/utility/translate.lua
index bb70a18..2a5acf3 100644
--- a/src/plugins/utility/translate.lua
+++ b/src/plugins/utility/translate.lua
@@ -1,171 +1,147 @@
--[[
mattata v2.0 - Translate Plugin
Translates text using LibreTranslate public API.
Supports auto-detection of source language.
]]
local plugin = {}
plugin.name = 'translate'
plugin.category = 'utility'
plugin.description = 'Translate text between languages'
plugin.commands = { 'translate', 'tl' }
plugin.help = '/translate [lang] <text> - Translate text to the specified language (default: en). Reply to a message to translate it, or provide text directly.'
local https = require('ssl.https')
local json = require('dkjson')
-local url = require('socket.url')
local ltn12 = require('ltn12')
local tools = require('telegram-bot-lua.tools')
local BASE_URL = 'https://libretranslate.com'
-- Common language code aliases
local LANG_ALIASES = {
english = 'en', en = 'en',
spanish = 'es', es = 'es',
french = 'fr', fr = 'fr',
german = 'de', de = 'de',
italian = 'it', it = 'it',
portuguese = 'pt', pt = 'pt',
russian = 'ru', ru = 'ru',
chinese = 'zh', zh = 'zh',
japanese = 'ja', ja = 'ja',
korean = 'ko', ko = 'ko',
arabic = 'ar', ar = 'ar',
hindi = 'hi', hi = 'hi',
dutch = 'nl', nl = 'nl',
polish = 'pl', pl = 'pl',
turkish = 'tr', tr = 'tr',
swedish = 'sv', sv = 'sv',
czech = 'cs', cs = 'cs',
romanian = 'ro', ro = 'ro',
hungarian = 'hu', hu = 'hu',
ukrainian = 'uk', uk = 'uk',
indonesian = 'id', id = 'id',
finnish = 'fi', fi = 'fi',
hebrew = 'he', he = 'he',
thai = 'th', th = 'th',
vietnamese = 'vi', vi = 'vi',
greek = 'el', el = 'el'
}
local function translate_text(text, target, source)
source = source or 'auto'
local request_body = json.encode({
q = text,
source = source,
target = target,
format = 'text'
})
local body = {}
local _, code = https.request({
url = BASE_URL .. '/translate',
method = 'POST',
headers = {
['Content-Type'] = 'application/json',
['Content-Length'] = tostring(#request_body)
},
source = ltn12.source.string(request_body),
sink = ltn12.sink.table(body)
})
if code ~= 200 then
return nil, 'Translation service returned an error (HTTP ' .. tostring(code) .. '). The public instance may be rate-limited; try again shortly.'
end
local data = json.decode(table.concat(body))
if not data then
return nil, 'Failed to parse translation response.'
end
if data.error then
return nil, 'Translation error: ' .. tostring(data.error)
end
return {
translated = data.translatedText,
source_lang = data.detectedLanguage and data.detectedLanguage.language or source
}
end
-local function detect_language(text)
- local request_body = json.encode({ q = text })
- local body = {}
- local _, code = https.request({
- url = BASE_URL .. '/detect',
- method = 'POST',
- headers = {
- ['Content-Type'] = 'application/json',
- ['Content-Length'] = tostring(#request_body)
- },
- source = ltn12.source.string(request_body),
- sink = ltn12.sink.table(body)
- })
- if code ~= 200 then
- return 'auto'
- end
- local data = json.decode(table.concat(body))
- if data and data[1] and data[1].language then
- return data[1].language
- end
- return 'auto'
-end
-
function plugin.on_message(api, message, ctx)
local input = message.args
local text_to_translate
local target_lang = 'en'
-- If replying to a message, use that text
if message.reply and message.reply.text and message.reply.text ~= '' then
text_to_translate = message.reply.text
-- If args given, treat as target language
if input and input ~= '' then
local lang = input:match('^(%S+)')
if lang then
lang = lang:lower()
target_lang = LANG_ALIASES[lang] or lang
end
end
elseif input and input ~= '' then
-- Parse: /translate [lang] <text>
local first_word, rest = input:match('^(%S+)%s+(.+)$')
if first_word then
local resolved = LANG_ALIASES[first_word:lower()]
if resolved then
target_lang = resolved
text_to_translate = rest
elseif first_word:match('^%a%a$') or first_word:match('^%a%a%a$') then
-- Assume it's a language code even if not in our alias table
target_lang = first_word:lower()
text_to_translate = rest
else
-- No language specified, translate the whole input to English
text_to_translate = input
end
else
text_to_translate = input
end
end
if not text_to_translate or text_to_translate == '' then
return api.send_message(
message.chat.id,
'Please provide text to translate.\nUsage: <code>/translate [lang] text</code>\nOr reply to a message with <code>/translate [lang]</code>',
'html'
)
end
local result, err = translate_text(text_to_translate, target_lang)
if not result then
return api.send_message(message.chat.id, err)
end
local source_label = result.source_lang ~= 'auto' and result.source_lang:upper() or '??'
local output = string.format(
'<b>Translation</b> [%s -> %s]\n\n%s',
tools.escape_html(source_label),
tools.escape_html(target_lang:upper()),
tools.escape_html(result.translated)
)
return api.send_message(message.chat.id, output, 'html')
end
return plugin
diff --git a/src/plugins/utility/weather.lua b/src/plugins/utility/weather.lua
index 78c34cb..9cbdd1a 100644
--- a/src/plugins/utility/weather.lua
+++ b/src/plugins/utility/weather.lua
@@ -1,168 +1,171 @@
--[[
mattata v2.0 - Weather Plugin
Shows current weather for a location using Open-Meteo (no API key needed).
Geocodes via Nominatim (OpenStreetMap). Supports stored locations from setloc.
]]
local plugin = {}
plugin.name = 'weather'
plugin.category = 'utility'
plugin.description = 'Get current weather for a location'
plugin.commands = { 'weather', 'w' }
plugin.help = '/weather [location] - Get current weather for a location. If no location is given, your saved location is used (set with /setloc).'
local https = require('ssl.https')
local json = require('dkjson')
local url = require('socket.url')
local ltn12 = require('ltn12')
local tools = require('telegram-bot-lua.tools')
-- WMO weather codes to human-readable descriptions
local WMO_CODES = {
[0] = 'Clear sky',
[1] = 'Mainly clear',
[2] = 'Partly cloudy',
[3] = 'Overcast',
[45] = 'Foggy',
[48] = 'Depositing rime fog',
[51] = 'Light drizzle',
[53] = 'Moderate drizzle',
[55] = 'Dense drizzle',
[56] = 'Light freezing drizzle',
[57] = 'Dense freezing drizzle',
[61] = 'Slight rain',
[63] = 'Moderate rain',
[65] = 'Heavy rain',
[66] = 'Light freezing rain',
[67] = 'Heavy freezing rain',
[71] = 'Slight snowfall',
[73] = 'Moderate snowfall',
[75] = 'Heavy snowfall',
[77] = 'Snow grains',
[80] = 'Slight rain showers',
[81] = 'Moderate rain showers',
[82] = 'Violent rain showers',
[85] = 'Slight snow showers',
[86] = 'Heavy snow showers',
[95] = 'Thunderstorm',
[96] = 'Thunderstorm with slight hail',
[99] = 'Thunderstorm with heavy hail'
}
local function geocode(query)
local encoded = url.escape(query)
local request_url = 'https://nominatim.openstreetmap.org/search?q=' .. encoded .. '&format=json&limit=1&addressdetails=1'
local body = {}
local _, code = https.request({
url = request_url,
sink = ltn12.sink.table(body),
headers = {
['User-Agent'] = 'mattata-telegram-bot/2.0'
}
})
if code ~= 200 then
return nil, 'Geocoding request failed.'
end
local data = json.decode(table.concat(body))
if not data or #data == 0 then
return nil, 'Location not found. Please check the spelling and try again.'
end
return {
lat = tonumber(data[1].lat),
lon = tonumber(data[1].lon),
name = data[1].display_name
}
end
local function get_weather(lat, lon)
local request_url = string.format(
- 'https://api.open-meteo.com/v1/forecast?latitude=%.6f&longitude=%.6f&current=temperature_2m,relative_humidity_2m,apparent_temperature,weather_code,wind_speed_10m,wind_direction_10m&temperature_unit=celsius&wind_speed_unit=kmh',
+ 'https://api.open-meteo.com/v1/forecast?latitude=%.6f&longitude=%.6f'
+ .. '&current=temperature_2m,relative_humidity_2m,apparent_temperature'
+ .. ',weather_code,wind_speed_10m,wind_direction_10m'
+ .. '&temperature_unit=celsius&wind_speed_unit=kmh',
lat, lon
)
local body = {}
local _, code = https.request({
url = request_url,
sink = ltn12.sink.table(body)
})
if code ~= 200 then
return nil, 'Weather API request failed.'
end
local data = json.decode(table.concat(body))
if not data or not data.current then
return nil, 'Failed to parse weather data.'
end
return data.current
end
local function c_to_f(c)
return c * 9 / 5 + 32
end
local function wind_direction(degrees)
local dirs = { 'N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW' }
local idx = math.floor((degrees / 22.5) + 0.5) % 16 + 1
return dirs[idx]
end
function plugin.on_message(api, message, ctx)
local input = message.args
local lat, lon, location_name
if not input or input == '' then
-- Try stored location
local result = ctx.db.execute(
'SELECT latitude, longitude, address FROM user_locations WHERE user_id = $1',
{ message.from.id }
)
if result and result[1] then
lat = tonumber(result[1].latitude)
lon = tonumber(result[1].longitude)
location_name = result[1].address or string.format('%.4f, %.4f', lat, lon)
else
return api.send_message(
message.chat.id,
'Please specify a location or set your default with /setloc.\nUsage: <code>/weather London</code>',
'html'
)
end
else
local geo, err = geocode(input)
if not geo then
return api.send_message(message.chat.id, err)
end
lat = geo.lat
lon = geo.lon
location_name = geo.name
end
local weather, err = get_weather(lat, lon)
if not weather then
return api.send_message(message.chat.id, err)
end
local temp_c = weather.temperature_2m or 0
local feels_c = weather.apparent_temperature or 0
local humidity = weather.relative_humidity_2m or 0
local wind_speed = weather.wind_speed_10m or 0
local wind_dir = wind_direction(weather.wind_direction_10m or 0)
local conditions = WMO_CODES[weather.weather_code] or 'Unknown'
local output = string.format(
'<b>Weather for %s</b>\n\n'
.. 'Conditions: %s\n'
.. 'Temperature: <b>%.1f°C</b> / <b>%.1f°F</b>\n'
.. 'Feels like: %.1f°C / %.1f°F\n'
.. 'Humidity: %d%%\n'
.. 'Wind: %.1f km/h %s',
tools.escape_html(location_name),
conditions,
temp_c, c_to_f(temp_c),
feels_c, c_to_f(feels_c),
humidity,
wind_speed, wind_dir
)
return api.send_message(message.chat.id, output, 'html')
end
return plugin
diff --git a/src/plugins/utility/wikipedia.lua b/src/plugins/utility/wikipedia.lua
index 18fddd6..f28a1b3 100644
--- a/src/plugins/utility/wikipedia.lua
+++ b/src/plugins/utility/wikipedia.lua
@@ -1,149 +1,151 @@
--[[
mattata v2.0 - Wikipedia Plugin
Looks up Wikipedia articles using the MediaWiki API.
]]
local plugin = {}
plugin.name = 'wikipedia'
plugin.category = 'utility'
plugin.description = 'Look up Wikipedia articles'
plugin.commands = { 'wikipedia', 'wiki', 'w' }
plugin.help = '/wiki <query> - Search Wikipedia for an article.'
local https = require('ssl.https')
local json = require('dkjson')
local url = require('socket.url')
local ltn12 = require('ltn12')
local tools = require('telegram-bot-lua.tools')
+local search_wikipedia_fallback
+
local function search_wikipedia(query, lang)
lang = lang or 'en'
local encoded = url.escape(query)
-- Use the REST API summary endpoint via search
local search_url = string.format(
'https://%s.wikipedia.org/api/rest_v1/page/summary/%s?redirect=true',
lang, encoded
)
local body = {}
local _, code = https.request({
url = search_url,
sink = ltn12.sink.table(body),
headers = {
['User-Agent'] = 'mattata-telegram-bot/2.0',
['Accept'] = 'application/json'
}
})
-- If direct lookup fails, try the search API
if code ~= 200 then
return search_wikipedia_fallback(query, lang)
end
local data = json.decode(table.concat(body))
if not data or data.type == 'not_found' or data.type == 'https://mediawiki.org/wiki/HyperSwitch/errors/not_found' then
return search_wikipedia_fallback(query, lang)
end
return data
end
-function search_wikipedia_fallback(query, lang)
+search_wikipedia_fallback = function(query, lang)
lang = lang or 'en'
local encoded = url.escape(query)
local search_url = string.format(
'https://%s.wikipedia.org/w/api.php?action=opensearch&search=%s&limit=1&format=json',
lang, encoded
)
local body = {}
local _, code = https.request({
url = search_url,
sink = ltn12.sink.table(body),
headers = {
['User-Agent'] = 'mattata-telegram-bot/2.0'
}
})
if code ~= 200 then
return nil, 'Wikipedia search failed (HTTP ' .. tostring(code) .. ').'
end
local data = json.decode(table.concat(body))
if not data or not data[2] or #data[2] == 0 then
return nil, 'No Wikipedia articles found for that query.'
end
-- Fetch the summary for the first result
local title = data[2][1]
local title_encoded = url.escape(title)
local summary_url = string.format(
'https://%s.wikipedia.org/api/rest_v1/page/summary/%s?redirect=true',
lang, title_encoded
)
body = {}
_, code = https.request({
url = summary_url,
sink = ltn12.sink.table(body),
headers = {
['User-Agent'] = 'mattata-telegram-bot/2.0',
['Accept'] = 'application/json'
}
})
if code ~= 200 then
return nil, 'Failed to retrieve article summary.'
end
local summary = json.decode(table.concat(body))
if not summary then
return nil, 'Failed to parse article summary.'
end
return summary
end
function plugin.on_message(api, message, ctx)
local input = message.args
if not input or input == '' then
return api.send_message(
message.chat.id,
'Please provide a search term.\nUsage: <code>/wiki search term</code>',
'html'
)
end
local data, err = search_wikipedia(input)
if not data then
return api.send_message(message.chat.id, err or 'No Wikipedia articles found for that query.')
end
-- Handle disambiguation pages
if data.type == 'disambiguation' then
local output = string.format(
'<b>%s</b> (disambiguation)\n\n%s\n\n<a href="%s">View on Wikipedia</a>',
tools.escape_html(data.title or input),
tools.escape_html(data.extract or 'This is a disambiguation page.'),
tools.escape_html(data.content_urls and data.content_urls.desktop and data.content_urls.desktop.page or '')
)
return api.send_message(message.chat.id, output, 'html', true)
end
local title = data.title or input
local extract = data.extract or data.description or 'No summary available.'
local page_url = data.content_urls and data.content_urls.desktop and data.content_urls.desktop.page or ''
-- Truncate long extracts
if #extract > 800 then
extract = extract:sub(1, 797) .. '...'
end
local lines = {
'<b>' .. tools.escape_html(title) .. '</b>'
}
if data.description and data.description ~= '' and data.description ~= extract then
table.insert(lines, '<i>' .. tools.escape_html(data.description) .. '</i>')
end
table.insert(lines, '')
table.insert(lines, tools.escape_html(extract))
if page_url ~= '' then
table.insert(lines, '')
table.insert(lines, '<a href="' .. tools.escape_html(page_url) .. '">Read more on Wikipedia</a>')
end
return api.send_message(message.chat.id, table.concat(lines, '\n'), 'html', true)
end
return plugin
diff --git a/tesseract/eng.traineddata b/tesseract/eng.traineddata
deleted file mode 100644
index 561883f..0000000
Binary files a/tesseract/eng.traineddata and /dev/null differ
diff --git a/transcribe.sh b/transcribe.sh
deleted file mode 100644
index 8bed4b3..0000000
--- a/transcribe.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/sh
-if [ ! -f ./configuration.lua ]
-then
- echo "Please insert the required variables into configuration.example.lua. Then, you need to rename configuration.example.lua to configuration.lua!"
-else
- cd helpers/
- while true; do
- lua transcribe.lua
- echo "Transcribe helper has stopped!"
- sleep 3s
- done
-fi

File Metadata

Mime Type
text/x-diff
Expires
Sun, May 17, 11:26 AM (1 d, 18 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
45/92/33edcef0f1b9148eaa53dea602c8
Default Alt Text
(1 MB)

Event Timeline