Commited backup

This commit is contained in:
2025-07-10 21:02:34 +03:00
parent 952c1001e3
commit da0b80823e
1310 changed files with 254133 additions and 41 deletions

View File

@@ -0,0 +1,454 @@
# -*- coding: future_fstrings -*-
# Friendly Telegram (telegram userbot)
# By Magical Unicorn (based on official Anti PM & AFK Friendly Telegram modules)
# Copyright (C) 2020 Magical Unicorn
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from .. import loader, utils
import logging
import datetime
import time
from telethon import functions, types
logger = logging.getLogger(__name__)
def register(cb):
cb(DoNotDisturbMod())
@loader.tds
class DoNotDisturbMod(loader.Module):
"""
DND (Do Not Disturb) :
-> Prevents people sending you unsolicited private messages.
-> Prevents disturbing when you are unavailable.\n
Commands :
 
"""
strings = {"name": "DND",
"afk": "<b>I'm AFK right now (since</b> <i>{}</i> <b>ago).</b>",
"afk_back": "<b>I'm goin' BACK !</b>",
"afk_gone": "<b>I'm goin' AFK !</b>",
"afk_no_group_off": "<b>AFK status message enabled for group chats.</b>",
"afk_no_group_on": "<b>AFK status message disabled for group chats.</b>",
"afk_no_pm_off": "<b>AFK status message enabled for PMs.</b>",
"afk_no_pm_on": "<b>AFK status message disabled for PMs.</b>",
"afk_notif_off": "<b>Notifications are now disabled during AFK time.</b>",
"afk_notif_on": "<b>Notifications are now enabled during AFK time.</b>",
"afk_rate_limit_off": "<b>AFK status message rate limit disabled.</b>",
"afk_rate_limit_on": ("<b>AFK status message rate limit enabled.</b>"
"\n\n<b>One AFK status message max will be sent per chat.</b>"),
"afk_reason": ("<b>I'm AFK right now (since {} ago).</b>"
"\n\n<b>Reason :</b> <i>{}</i>"),
"arg_on_off": "<b>Argument must be 'off' or 'on' !</b>",
"pm_off": ("<b>Automatic answer for denied PMs disabled."
"\n\nUsers are now free to PM !</b>"),
"pm_on": "<b>An automatic answer is now sent for denied PMs.</b>",
"pm_allowed": "<b>I have allowed</b> <a href='tg://user?id={}'>you</a> <b>to PM now.</b>",
"pm_blocked": ("<b>I don't want any PM from</b> <a href='tg://user?id={}'>you</a>, "
"<b>so you have been blocked !</b>"),
"pm_denied": "<b>I have denied</b> <a href='tg://user?id={}'>you</a> <b>to PM now.</b>",
"pm_go_away": ("Hey there! Unfortunately, I don't accept private messages from strangers."
"\n\nPlease contact me in a group, or <b>wait</b> for me to approve you."),
"pm_reported": "<b>You just got reported to spam !</b>",
"pm_limit_arg": "<b>Argument must be 'off', 'on' or a number between 10 and 1000 !</b>",
"pm_limit_off": "<b>Not allowed users are now free to PM without be automatically blocked.</b>",
"pm_limit_on": "<b>Not allowed users are now blocked after {} PMs.</b>",
"pm_limit_current": "<b>Current limit is {}.</b>",
"pm_limit_current_no": "<b>Automatic user blocking is currently disabled.</b>",
"pm_limit_reset": "<b>Limit reseted to {}.</b>",
"pm_limit_set": "<b>Limit set to {}.</b>",
"pm_notif_off": "<b>Notifications from denied PMs are now disabled.</b>",
"pm_notif_on": "<b>Notifications from denied PMs are now enabled.</b>",
"pm_triggered": ("Hey! I don't appreciate you barging into my PM like this !"
"\nDid you even ask me for approving you to PM ? No ?"
"\nGoodbye then."
"\n\nPS: You've been reported as spam."),
"pm_unblocked": ("<b>Alright fine! I'll forgive them this time. PM has been unblocked for</b> "
"<a href='tg://user?id={}'>this user</a>."),
"unknow": ("An unknow problem as occured."
"\n\nPlease report problem with logs on "
"<a href='https://github.com/LegendaryUnicorn/FTG-Unofficial-Modules'>Github</a>."),
"who_to_allow": "<b>Who shall I allow to PM ?</b>",
"who_to_block": "<b>Specify who to block.</b>",
"who_to_deny": "<b>Who shall I deny to PM ?</b>",
"who_to_report": "<b>Who shall I report ?</b>",
"who_to_unblock": "<b>Specify who to unblock.</b>"}
def __init__(self):
self._me = None
self.default_pm_limit = 50
def config_complete(self):
self.name = self.strings["name"]
async def client_ready(self, client, db):
self._db = db
self._client = client
self._me = await client.get_me(True)
async def afkbackcmd(self, message):
"""Remove the AFK status.\n """
self._db.set(__name__, "afk", False)
self._db.set(__name__, "afk_gone", None)
self._db.set(__name__, "afk_rate", [])
await utils.answer(message, self.strings["afk_back"])
async def afkgocmd(self, message):
"""
.afkgo : Enable AFK status.
.afkgo [message] : Enable AFK status and add a reason.
 
"""
if utils.get_args_raw(message):
self._db.set(__name__, "afk", utils.get_args_raw(message))
else:
self._db.set(__name__, "afk", True)
self._db.set(__name__, "afk_gone", time.time())
self._db.set(__name__, "afk_rate", [])
await utils.answer(message, self.strings["afk_gone"])
async def afknogroupcmd(self, message):
"""
.afknogroup : Disable/Enable AFK status message for group chats.
.afknogroup off : Enable AFK status message for group chats.
.afknogroup on : Disable AFK status message for group chats.
 
"""
if utils.get_args_raw(message):
afknogroup_arg = utils.get_args_raw(message)
if afknogroup_arg == "off":
self._db.set(__name__, "afk_no_group", False)
await utils.answer(message, self.strings["afk_no_group_off"])
elif afknogroup_arg == "on":
self._db.set(__name__, "afk_no_group", True)
await utils.answer(message, self.strings["afk_no_group_on"])
else:
await utils.answer(message, self.strings["arg_on_off"])
else:
afknogroup_current = self._db.get(__name__, "afk_no_group")
if afknogroup_current is None or afknogroup_current is False:
self._db.set(__name__, "afk_no_group", True)
await utils.answer(message, self.strings["afk_no_group_on"])
elif afknogroup_current is True:
self._db.set(__name__, "afk_no_group", False)
await utils.answer(message, self.strings["afk_no_group_off"])
else:
await utils.answer(message, self.strings["unknow"])
async def afknopmcmd(self, message):
"""
.afknopm : Disable/Enable AFK status message for PMs.
.afknopm off : Enable AFK status message for PMs.
.afknopm on : Disable AFK status message for PMs.
 
"""
if utils.get_args_raw(message):
afknopm_arg = utils.get_args_raw(message)
if afknopm_arg == "off":
self._db.set(__name__, "afk_no_pm", False)
await utils.answer(message, self.strings["afk_no_pm_off"])
elif afknopm_arg == "on":
self._db.set(__name__, "afk_no_pm", True)
await utils.answer(message, self.strings["afk_no_pm_on"])
else:
await utils.answer(message, self.strings["arg_on_off"])
else:
afknopm_current = self._db.get(__name__, "afk_no_pm")
if afknopm_current is None or afknopm_current is False:
self._db.set(__name__, "afk_no_pm", True)
await utils.answer(message, self.strings["afk_no_pm_on"])
elif afknopm_current is True:
self._db.set(__name__, "afk_no_pm", False)
await utils.answer(message, self.strings["afk_no_pm_off"])
else:
await utils.answer(message, self.strings["unknow"])
async def afknotifcmd(self, message):
"""
.afknotif : Disable/Enable the notifications during AFK time.
.afknotif off : Disable the notifications during AFK time.
.afknotif on : Enable the notifications during AFK time.
 
"""
if utils.get_args_raw(message):
afknotif_arg = utils.get_args_raw(message)
if afknotif_arg == "off":
self._db.set(__name__, "afk_notif", False)
await utils.answer(message, self.strings["afk_notif_off"])
elif afknotif_arg == "on":
self._db.set(__name__, "afk_notif", True)
await utils.answer(message, self.strings["afk_notif_on"])
else:
await utils.answer(message, self.strings["arg_on_off"])
else:
afknotif_current = self._db.get(__name__, "afk_notif")
if afknotif_current is None or afknotif_current is False:
self._db.set(__name__, "afk_notif", True)
await utils.answer(message, self.strings["afk_notif_on"])
elif afknotif_current is True:
self._db.set(__name__, "afk_notif", False)
await utils.answer(message, self.strings["afk_notif_off"])
else:
await utils.answer(message, self.strings["unknow"])
async def afkratecmd(self, message):
"""
.afkrate : Disable/Enable AFK rate limit.
.afkrate off : Disable AFK rate limit.
.afkrate on : Enable AFK rate limit. One AFK status message max will be sent per chat.
 
"""
if utils.get_args_raw(message):
afkrate_arg = utils.get_args_raw(message)
if afkrate_arg == "off":
self._db.set(__name__, "afk_rate_limit", False)
await utils.answer(message, self.strings["afk_rate_limit_off"])
elif afkrate_arg == "on":
self._db.set(__name__, "afk_rate_limit", True)
await utils.answer(message, self.strings["afk_rate_limit_on"])
else:
await utils.answer(message, self.strings["arg_on_off"])
else:
afkrate_current = self._db.get(__name__, "afk_rate_limit")
if afkrate_current is None or afkrate_current is False:
self._db.set(__name__, "afk_rate_limit", True)
await utils.answer(message, self.strings["afk_rate_limit_on"])
elif afkrate_current is True:
self._db.set(__name__, "afk_rate_limit", False)
await utils.answer(message, self.strings["afk_rate_limit_off"])
else:
await utils.answer(message, self.strings["unknow"])
async def allowcmd(self, message):
"""Allow this user to PM.\n """
user = await utils.get_target(message)
if not user:
await utils.answer(message, self.strings["who_to_allow"])
return
self._db.set(__name__, "allow", list(set(self._db.get(__name__, "allow", [])).union({user})))
await utils.answer(message, self.strings["pm_allowed"].format(user))
async def blockcmd(self, message):
"""Block this user to PM without being warned.\n """
user = await utils.get_target(message)
if not user:
await utils.answer(message, self.strings["who_to_block"])
return
await message.client(functions.contacts.BlockRequest(user))
await utils.answer(message, self.strings["pm_blocked"].format(user))
async def denycmd(self, message):
"""Deny this user to PM without being warned.\n """
user = await utils.get_target(message)
if not user:
await utils.answer(message, self.strings["who_to_deny"])
return
self._db.set(__name__, "allow", list(set(self._db.get(__name__, "allow", [])).difference({user})))
await utils.answer(message, self.strings["pm_denied"].format(user))
async def pmcmd(self, message):
"""
.pm : Disable/Enable automatic answer for denied PMs.
.pm off : Disable automatic answer for denied PMs.
.pm on : Enable automatic answer for denied PMs.
 
"""
if utils.get_args_raw(message):
pm_arg = utils.get_args_raw(message)
if pm_arg == "off":
self._db.set(__name__, "pm", True)
await utils.answer(message, self.strings["pm_off"])
elif pm_arg == "on":
self._db.set(__name__, "pm", False)
await utils.answer(message, self.strings["pm_on"])
else:
await utils.answer(message, self.strings["arg_on_off"])
else:
pm_current = self._db.get(__name__, "pm")
if pm_current is None or pm_current is False:
self._db.set(__name__, "pm", True)
await utils.answer(message, self.strings["pm_off"])
elif pm_current is True:
self._db.set(__name__, "pm", False)
await utils.answer(message, self.strings["pm_on"])
else:
await utils.answer(message, self.strings["unknow"])
async def pmlimitcmd(self, message):
"""
.pmlimit : Get current max number of PMs before automatically block not allowed user.
.pmlimit off : Disable automatic user blocking.
.pmlimit on : Enable automatic user blocking.
.pmlimit reset : Reset max number of PMs before automatically block not allowed user.
.pmlimit [number] : Modify max number of PMs before automatically block not allowed user.
 
"""
if utils.get_args_raw(message):
pmlimit_arg = utils.get_args_raw(message)
if pmlimit_arg == "off":
self._db.set(__name__, "pm_limit", False)
await utils.answer(message, self.strings["pm_limit_off"])
return
elif pmlimit_arg == "on":
self._db.set(__name__, "pm_limit", True)
pmlimit_on = self.strings["pm_limit_on"].format(self.get_current_limit())
await utils.answer(message, pmlimit_on)
return
elif pmlimit_arg == "reset":
self._db.set(__name__, "pm_limit_max", self.default_pm_limit)
pmlimit_reset = self.strings["pm_limit_reset"].format(self.get_current_pm_limit())
await utils.answer(message, pmlimit_reset)
return
else:
try:
pmlimit_number = int(pmlimit_arg)
if pmlimit_number >= 10 and pmlimit_number <= 1000:
self._db.set(__name__, "pm_limit_max", pmlimit_number)
pmlimit_new = self.strings["pm_limit_set"].format(self.get_current_pm_limit())
await utils.answer(message, pmlimit_new)
return
else:
await utils.answer(message, self.strings["pm_limit_arg"])
return
except ValueError:
await utils.answer(message, self.strings["pm_limit_arg"])
return
await utils.answer(message, self.strings["limit_arg"])
else:
pmlimit = self._db.get(__name__, "pm_limit")
if pmlimit is None or pmlimit is False:
pmlimit_current = self.strings["pm_limit_current_no"]
elif pmlimit is True:
pmlimit_current = self.strings["pm_limit_current"].format(self.get_current_pm_limit())
else:
await utils.answer(message, self.strings["unknow"])
return
await utils.answer(message, pmlimit_current)
async def pmnotifcmd(self, message):
"""
.pmnotif : Disable/Enable the notifications from denied PMs.
.pmnotif off : Disable the notifications from denied PMs.
.pmnotif on : Enable the notifications from denied PMs.
 
"""
if utils.get_args_raw(message):
pmnotif_arg = utils.get_args_raw(message)
if pmnotif_arg == "off":
self._db.set(__name__, "pm_notif", False)
await utils.answer(message, self.strings["pm_notif_off"])
elif pmnotif_arg == "on":
self._db.set(__name__, "pm_notif", True)
await utils.answer(message, self.strings["pm_notif_on"])
else:
await utils.answer(message, self.strings["arg_on_off"])
else:
pmnotif_current = self._db.get(__name__, "pm_notif")
if pmnotif_current is None or pmnotif_current is False:
self._db.set(__name__, "pm_notif", True)
await utils.answer(message, self.strings["pm_notif_on"])
elif pmnotif_current is True:
self._db.set(__name__, "pm_notif", False)
await utils.answer(message, self.strings["pm_notif_off"])
else:
await utils.answer(message, self.strings["unknow"])
async def reportcmd(self, message):
"""Report the user to spam. Use only in PM.\n """
user = await utils.get_target(message)
if not user:
await utils.answer(message, self.strings["who_to_report"])
return
self._db.set(__name__, "allow", list(set(self._db.get(__name__, "allow", [])).difference({user})))
if message.is_reply and isinstance(message.to_id, types.PeerChannel):
await message.client(functions.messages.ReportRequest(peer=message.chat_id,
id=[message.reply_to_msg_id],
reason=types.InputReportReasonSpam()))
else:
await message.client(functions.messages.ReportSpamRequest(peer=message.to_id))
await utils.answer(message, self.strings["pm_reported"])
async def unblockcmd(self, message):
"""Unblock this user to PM."""
user = await utils.get_target(message)
if not user:
await utils.answer(message, self.strings["who_to_unblock"])
return
await message.client(functions.contacts.UnblockRequest(user))
await utils.answer(message, self.strings["pm_unblocked"].format(user))
async def watcher(self, message):
user = await utils.get_user(message)
pm = self._db.get(__name__, "pm")
if getattr(message.to_id, "user_id", None) == self._me.user_id and (pm is None or pm is False):
if not user.is_self and not user.bot and not user.verified and not self.get_allowed(message.from_id):
await utils.answer(message, self.strings["pm_go_away"])
if self._db.get(__name__, "pm_limit") is True:
pms = self._db.get(__name__, "pms", {})
pm_limit = self._db.get(__name__, "pm_limit_max")
pm_user = pms.get(message.from_id, 0)
if isinstance(pm_limit, int) and pm_limit >= 10 and pm_limit <= 1000 and pm_user >= pm_limit:
await utils.answer(message, self.strings["pm_triggered"])
await message.client(functions.contacts.BlockRequest(message.from_id))
await message.client(functions.messages.ReportSpamRequest(peer=message.from_id))
del pms[message.from_id]
self._db.set(__name__, "pms", pms)
else:
self._db.set(__name__, "pms", {**pms, message.from_id: pms.get(message.from_id, 0) + 1})
pm_notif = self._db.get(__name__, "pm_notif")
if pm_notif is None or pm_notif is False:
await message.client.send_read_acknowledge(message.chat_id)
return
if message.mentioned or getattr(message.to_id, "user_id", None) == self._me.user_id:
afk_status = self._db.get(__name__, "afk")
if user.is_self or user.bot or user.verified or afk_status is False:
return
if message.mentioned and self._db.get(__name__, "afk_no_group") is True:
return
afk_no_pm = self._db.get(__name__, "afk_no_pm")
if getattr(message.to_id, "user_id", None) == self._me.user_id and afk_no_pm is True:
return
if self._db.get(__name__, "afk_rate_limit") is True:
afk_rate = self._db.get(__name__, "afk_rate", [])
if utils.get_chat_id(message) in afk_rate:
return
else:
self._db.setdefault(__name__, {}).setdefault("afk_rate", []).append(utils.get_chat_id(message))
self._db.save()
now = datetime.datetime.now().replace(microsecond=0)
gone = datetime.datetime.fromtimestamp(self._db.get(__name__, "afk_gone")).replace(microsecond=0)
diff = now - gone
if afk_status is True:
afk_message = self.strings["afk"].format(diff)
elif afk_status is not False:
afk_message = self.strings["afk_reason"].format(diff, afk_status)
await utils.answer(message, afk_message)
_notif = self._db.get(__name__, "_notif")
if _notif is None or _notif is False:
await message.client.send_read_acknowledge(message.chat_id)
def get_allowed(self, id):
return id in self._db.get(__name__, "allow", [])
def get_current_pm_limit(self):
pm_limit = self._db.get(__name__, "pm_limit_max")
if not isinstance(pm_limit, int) or pm_limit < 10 or pm_limit > 1000:
pm_limit = self.default_pm_limit
self._db.set(__name__, "pm_limit_max", pm_limit)
return pm_limit

View File

@@ -0,0 +1,125 @@
# -*- coding: future_fstrings -*-
# Friendly Telegram (telegram userbot)
# By Magical Unicorn (based on official Anti PM & AFK Friendly Telegram modules)
# Copyright (C) 2020 Magical Unicorn
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from .. import loader, utils
import logging
from telethon import functions, types
from telethon.tl.types import PeerUser, PeerChat, PeerChannel, ChannelParticipantsAdmins
logger = logging.getLogger(__name__)
def register(cb):
cb(TagMod())
@loader.tds
class TagMod(loader.Module):
"""
Tag :
-> Tag all admins (fast way to report).
-> Tag all bots (why not ?).
-> Tag all members (why not ?).\n
Commands :
 
"""
strings = {"name": "Tag",
"error_chat": "<b>This command can be used in channels and group chats only.</b>",
"unknow": ("An unknow problem as occured."
"\n\nPlease report problem with logs on "
"<a href='https://github.com/LegendaryUnicorn/FTG-Unofficial-Modules'>Github</a>."),
"user_link": "\n• <a href='tg://user?id={}'>{}</a>"}
def config_complete(self):
self.name = self.strings["name"]
async def admincmd(self, message):
"""
.admin : Tag all admins (excepted bots).
.admin [message] : Tag all admins (excepted bots) with message before tags.
 
"""
if isinstance(message.to_id, PeerUser):
await utils.answer(message, self.strings["error_chat"])
return
if utils.get_args_raw(message):
rep = utils.get_args_raw(message)
else:
rep = ""
user = await utils.get_target(message)
if isinstance(message.to_id, PeerChat) or isinstance(message.to_id, PeerChannel):
async for user in message.client.iter_participants(message.to_id, filter=ChannelParticipantsAdmins):
if not user.bot:
user_name = user.first_name
if user.last_name is not None:
user_name += " " + user.last_name
rep += self.strings["user_link"].format(user.id, user_name)
await utils.answer(message, rep)
else:
await utils.answer(message, self.strings["unknow"])
async def allcmd(self, message):
"""
.all : Tag all members.
.all [message] : Tag all members with message before tags.
 
"""
if isinstance(message.to_id, PeerUser):
await utils.answer(message, self.strings["error_chat"])
return
if utils.get_args_raw(message):
rep = utils.get_args_raw(message)
else:
rep = ""
user = await utils.get_target(message)
if isinstance(message.to_id, PeerChat) or isinstance(message.to_id, PeerChannel):
async for user in message.client.iter_participants(message.to_id):
user_name = user.first_name
if user.last_name is not None:
user_name += " " + user.last_name
rep += self.strings["user_link"].format(user.id, user_name)
await utils.answer(message, rep)
else:
await utils.answer(message, self.strings["unknow"])
async def botcmd(self, message):
"""
.bot : Tag all bots.
.bot [message] : Tag all bots with message before tags.
 
"""
if isinstance(message.to_id, PeerUser):
await utils.answer(message, self.strings["error_chat"])
return
if utils.get_args_raw(message):
rep = utils.get_args_raw(message)
else:
rep = ""
user = await utils.get_target(message)
if isinstance(message.to_id, PeerChat) or isinstance(message.to_id, PeerChannel):
async for user in message.client.iter_participants(message.to_id):
if user.bot:
user_name = user.first_name
if user.last_name is not None:
user_name += " " + user.last_name
rep += self.strings["user_link"].format(user.id, user_name)
await utils.answer(message, rep)
else:
await utils.answer(message, self.strings["unknow"])

View File

@@ -0,0 +1,42 @@
from .. import loader, utils
import logging
import datetime
import time
import asyncio
logger = logging.getLogger(__name__)
def register(cb):
cb(CONTACTMod())
@loader.tds
class CONTACTMod(loader.Module):
"""Это модуль для игры в \"контакт\""""
strings = {"name": "contact"}
def __init__(self):
self.name = self.strings["name"]
def config_complete(self):
pass
async def contactcmd(self, message):
"""Эта команда пишет 10 сообщений для контакта"""
try:
await message.delete()
x = 10
lst = str(x)
await message.respond(lst)
dd = time.time()
while time.time() - dd < x:
now = str(x - round(time.time() - dd))
if now != lst:
await message.respond(now)
lst = now
except:
await message.respond("Упс, ошибочка вышла! Напшите @gerasikoff, он вам поможет")

View File

@@ -0,0 +1,95 @@
import requests as rq
from urllib.parse import quote_plus as escape
import re
from .. import loader, utils
import asyncio
import logging
logger = logging.getLogger(__name__)
# simplified cuttly api
class CuttlyApi:
def __init__(self, token, api_url='https://cutt.ly/api/api.php'):
self.token = token
self.api_url = api_url
self.error_codes = {
1: 'Link is already shortened',
2: 'Link to short is not a link',
3: 'Short link https://cutt.ly/{name} is taken',
4: 'Invalid API key',
5: 'Link preferred alias contains invalid characters',
6: 'Link is from blocked domain'
}
self.ok_code = 7
def shorten(self, short: str, name: str=None) -> dict:
if not re.fullmatch(r'\w+://.+', short): # add scheme if needed
short = 'http://' + short # assume that it supports http
res = rq.get(self.api_url, params={
"key": self.token,
"short": escape(short, ':/%._-'),
"name": name
})
res = res.json()['url']
return res
@loader.tds
class CuttlyMod(loader.Module):
"""URL shortener module"""
# make errors translatable
strings = {
"name": "Cutt.ly",
"error_1": "<b>Link is already shortened</b>",
"error_2": "<b>It is not a link</b>",
"error_3": "<b>Short link https://cutt.ly/{name} is taken</b>",
"error_4": "<b>Invalid API key. Change it in config.</b>",
"error_5": "<b>Link preferred alias contains invalid characters</b>",
"error_6": "<b>Link is from blocked domain</b>",
"unknown_error": "<b>Unknown error {}. Check https://cutt.ly/cuttly-api for information.</b>",
"ok": "<b>Shorted!</b>\nShort link: {short}\nFull link: {full}",
"ok_nofull": "<b>Shorted!</b>\nShort link: {short}",
"no_args": "<b>At least 1 argument needed - the link you gonna to short</b>",
"many_args": "<b>At most 2 arguments - the link you gonna to short and preferred alias for it."
}
def __init__(self):
self.config = loader.ModuleConfig(
# name - default - description
"cuttly_api_url", "https://cutt.ly/api/api.php", "Cuttly API URL, took from https://cutt.ly/cuttly-api",
"api_key", None, "API key for cutt.ly. Register there and take one.",
"include_full_link", True, "Shall bot include full link into answer."
)
def config_complete(self):
self.name = self.strings['name']
self.cl = CuttlyApi(self.config['api_key'], self.config['cuttly_api_url'])
async def shortcmd(self, message):
'''usage: .short <link_to_short> [preferred_alias]'''
args = utils.get_args(message)
if len(args) < 1:
await utils.answer(message, self.strings['no_args'])
return
elif len(args) > 2:
await utils.answer(message, self.strings['many_args'])
return
if len(args) == 1:
args.append(None)
res = self.cl.shorten(*args)
logger.debug(f'Got response from cutt.ly: {res}')
if res['status'] != self.cl.ok_code:
try:
msg = self.strings[f'error_{res["status"]}']
except KeyError: # Unknown error, not in strings yet
msg = self.strings['unknown_error'].format(res['status'])
else:
if self.config['include_full_link']:
msg = self.strings['ok']
else:
msg = self.strings['ok_nofull']
await utils.answer(message, msg.format(
short = res.get('shortLink', None), # If we got an error
full = res.get('fullLink', None),
name = args[1]
))

View File

@@ -0,0 +1,131 @@
# Copyright (C) 2019 The Raphielscape Company LLC.
#
# Licensed under the Raphielscape Public License, Version 1.c (the "License");
# you may not use this file except in compliance with the License.
#
""" Userbot module containing commands for interacting with dogbin(https://del.dog)"""
from requests import get, post, exceptions
import asyncio
import os
from userbot import BOTLOG, BOTLOG_CHATID, CMD_HELP, LOGS, TEMP_DOWNLOAD_DIRECTORY
from userbot.events import register
DOGBIN_URL = "https://dogbin.f0x1d.com/"
@register(outgoing=True, pattern=r"^.paste(?: |$)([\s\S]*)")
async def paste(pstl):
""" For .paste command, pastes the text directly to dogbin. """
dogbin_final_url = ""
match = pstl.pattern_match.group(1).strip()
reply_id = pstl.reply_to_msg_id
if not match and not reply_id:
await pstl.edit("`Elon Musk said I cannot paste void.`")
return
if match:
message = match
elif reply_id:
message = (await pstl.get_reply_message())
if message.media:
downloaded_file_name = await pstl.client.download_media(
message,
TEMP_DOWNLOAD_DIRECTORY,
)
m_list = None
with open(downloaded_file_name, "rb") as fd:
m_list = fd.readlines()
message = ""
for m in m_list:
message += m.decode("UTF-8") + "\r"
os.remove(downloaded_file_name)
else:
message = message.message
# Dogbin
await pstl.edit("`Pasting text . . .`")
resp = post(DOGBIN_URL + "documents", data=message.encode('utf-8'))
if resp.status_code == 200:
response = resp.json()
key = response['key']
dogbin_final_url = DOGBIN_URL + key
if response['isUrl']:
reply_text = ("`Pasted successfully!`\n\n"
f"`Shortened URL:` {dogbin_final_url}\n\n"
"`Original(non-shortened) URLs`\n"
f"`Dogbin URL`: {DOGBIN_URL}v/{key}\n")
else:
reply_text = ("`Pasted successfully!`\n\n"
f"`Dogbin URL`: {dogbin_final_url}")
else:
reply_text = ("`Failed to reach Dogbin`")
await pstl.edit(reply_text)
if BOTLOG:
await pstl.client.send_message(
BOTLOG_CHATID,
f"Paste query was executed successfully",
)
@register(outgoing=True, pattern="^.getpaste(?: |$)(.*)")
async def get_dogbin_content(dog_url):
""" For .getpaste command, fetches the content of a dogbin URL. """
textx = await dog_url.get_reply_message()
message = dog_url.pattern_match.group(1)
await dog_url.edit("`Getting dogbin content...`")
if textx:
message = str(textx.message)
format_normal = f'{DOGBIN_URL}'
format_view = f'{DOGBIN_URL}v/'
if message.startswith(format_view):
message = message[len(format_view):]
elif message.startswith(format_normal):
message = message[len(format_normal):]
elif message.startswith("del.dog/"):
message = message[len("del.dog/"):]
else:
await dog_url.edit("`Is that even a dogbin url?`")
return
resp = get(f'{DOGBIN_URL}raw/{message}')
try:
resp.raise_for_status()
except exceptions.HTTPError as HTTPErr:
await dog_url.edit(
"Request returned an unsuccessful status code.\n\n" + str(HTTPErr))
return
except exceptions.Timeout as TimeoutErr:
await dog_url.edit("Request timed out." + str(TimeoutErr))
return
except exceptions.TooManyRedirects as RedirectsErr:
await dog_url.edit(
"Request exceeded the configured number of maximum redirections." +
str(RedirectsErr))
return
reply_text = "`Fetched dogbin URL content successfully!`\n\n`Content:` " + resp.text
await dog_url.edit(reply_text)
if BOTLOG:
await dog_url.client.send_message(
BOTLOG_CHATID,
"Get dogbin content query was executed successfully",
)
CMD_HELP.update({
"dogbin":
".paste <text/reply>\
\nUsage: Create a paste or a shortened url using dogbin (https://dogbin.f0x1d.com/)\
\n\n.getpaste\
\nUsage: Gets the content of a paste or shortened url from dogbin (https://dogbin.f0x1d.com/)"
})

View File

@@ -0,0 +1,143 @@
import logging
import json
# import telethon
from .. import loader, utils, security
logger = logging.getLogger(__name__)
@loader.tds
class InactiveDetectorMod(loader.Module):
"""Detects inactive users"""
strings = {
"name": "Inactivity detector",
"top_header": "These {un} users wrote {mn} messages or less since joining the group:\n\n",
"top_place": "[{name}](tg://user?id={uid}) ({nmsg})", # FIXME: mentions
"top_delimiter": ", ", # TODO: move to config
"not_int": "<b>Most messages must be integer</b>",
"recount_priv": "<b>I can't recount stats in private messages!</b>",
"recount_started": "<b>Processing recount for chat {}. It may take a lot.</b>",
"recount_db_dumped": "<b>Dumped database to owners and/or saved messages</b>",
"recount_dump": "<b>Database dump for chat {cid}:<b>\n\n<pre>{dmp}</pre>",
"recount_iter_done": "<b>Iterated over {} messages in this chat</b>",
"recount_finish": "<b>Recount successful!</b>"
}
def __init__(self):
self.config = loader.ModuleConfig(
"default_chat_id", -1001457369532, "Chat ID to get top if command used in PM",
"top_delimiter", ', ', "Separates inactivity top members",
"dump_db_before_recount", False, "Dump database of chat before recounting. "
"Dump will be sent to saved or bot owners"
)
self.name = self.strings['name']
async def client_ready(self, client, db):
self.client = client
self.db = db
self.me = await self.client.get_me()
async def inactivecmd(self, message):
""".inactive <N>"""
if message.is_private:
chat_id = self.config['default_chat_id']
else:
chat_id = message.chat_id
args = utils.get_args(message)
if args:
if args[0].isdigit():
most = int(args[0])
else:
await utils.answer(message, self.strings("not_int", message))
return
else:
most = 0
users_db = self.db.get(__name__, str(chat_id), {})
users = {}
async for user in self.client.iter_participants(chat_id):
if not user.bot:
if str(user.id) not in users_db:
users_db[str(user.id)] = self.get_empty_user(user)
users[str(user.id)] = users_db[str(user.id)]
# We won't include users not CURRENTLY in chat,
# but their stats will remain in the database
self.db.set(__name__, str(chat_id), users_db)
def key(x):
return x[1]['cnt']
users = sorted(users.items(), key=key)
text = []
for uid, u in users:
if u['cnt'] <= most:
text.append(self.strings('top_place', message).format(
name=u['name'], uid=uid, nmsg=u['cnt']
))
else:
break
msg = self.strings('top_header', message).format(un=len(text), mn=most)\
+ self.config['top_delimiter'].join(text)
kw = {}
if self.me.id != message.from_id:
kw['silent'] = True
await utils.answer(message, msg, parse_mode="md", **kw)
async def recountcmd(self, message):
if message.is_private:
await utils.answer(message, self.strings('recount_priv', message))
return
chat_id = message.chat_id
await utils.answer(message, self.strings('recount_started', message).format(chat_id))
db = self.db.get(__name__, str(chat_id), {})
json_db = json.dumps(db)
msg = self.strings("recount_dump", message).format(cid=chat_id, dmp=json_db)
logging.debug('Database dump (chat %d): %s', chat_id, json_db)
owners = self.db.get(security.__name__, "owner", ["me"])
if owners:
for owner in owners:
try:
await self.client.send_message(owner, msg)
except Exception:
logger.warning("Dump of chat %d sending to %d failed",
chat_id, owner, exc_info=True)
new_db = {}
n = 0
async for msg in self.client.iter_messages(chat_id, limit=None):
if not msg.sender.bot:
n += 1
from_id = msg.from_id
# Ensure such user exists, or create him
new_db[str(from_id)] = new_db.get(str(from_id),
self.get_empty_user(msg.sender))
new_db[str(from_id)]['cnt'] += 1
await utils.answer(message, self.strings("recount_iter_done", message).format(n))
self.db.set(__name__, str(chat_id), new_db)
await utils.answer(message, self.strings("recount_finish", message))
async def watcher(self, message):
if message.is_private:
return
else:
chat_id = str(message.chat_id)
users = self.db.get(__name__, chat_id, {})
from_id = str(message.from_id)
# this creates user if not exists
if message.sender:
users[from_id] = users.get(from_id, self.get_empty_user(message.sender))
users[from_id]["cnt"] += 1
self.db.set(__name__, chat_id, users)
def get_full_name(self, user):
fn, ln = '', ''
if user.first_name:
fn = user.first_name
if user.last_name: # Can be None, then we get an exception
ln = user.last_name
return (fn + ' ' + ln).strip()
def get_empty_user(self, user):
return {"cnt": 0, "name": self.get_full_name(user)}

View File

@@ -0,0 +1,154 @@
# Copyright (C) 2019 The Raphielscape Company LLC.
#
# Licensed under the Raphielscape Public License, Version 1.c (the "License");
# you may not use this file except in compliance with the License.
#
""" Userbot module for purging unneeded messages(usually spam or ot). """
from asyncio import sleep
from telethon.errors import rpcbaseerrors
from userbot import BOTLOG, BOTLOG_CHATID, CMD_HELP
from userbot.events import register
@register(outgoing=True, pattern="^.purge$")
async def fastpurger(purg):
""" For .purge command, purge all messages starting from the reply. """
chat = await purg.get_input_chat()
msgs = []
itermsg = purg.client.iter_messages(chat, min_id=purg.reply_to_msg_id)
count = 0
if purg.reply_to_msg_id is not None:
async for msg in itermsg:
msgs.append(msg)
count = count + 1
msgs.append(purg.reply_to_msg_id)
if len(msgs) == 100:
await purg.client.delete_messages(chat, msgs)
msgs = []
else:
await purg.edit("`I need a mesasge to start purging from.`")
return
if msgs:
await purg.client.delete_messages(chat, msgs)
done = await purg.client.send_message(
purg.chat_id, f"`Fast purge complete!`\
\nPurged {str(count)} messages")
if BOTLOG:
await purg.client.send_message(
BOTLOG_CHATID,
"Purge of " + str(count) + " messages done successfully.")
await sleep(2)
await done.delete()
@register(outgoing=True, pattern="^.purgeme")
async def purgeme(delme):
""" For .purgeme, delete x count of your latest message."""
message = delme.text
count = int(message[9:])
i = 1
async for message in delme.client.iter_messages(delme.chat_id,
from_user='me'):
if i > count + 1:
break
i = i + 1
await message.delete()
smsg = await delme.client.send_message(
delme.chat_id,
"`Purge complete!` Purged " + str(count) + " messages.",
)
if BOTLOG:
await delme.client.send_message(
BOTLOG_CHATID,
"Purge of " + str(count) + " messages done successfully.")
await sleep(2)
i = 1
await smsg.delete()
@register(outgoing=True, pattern="^.del$")
async def delete_it(delme):
""" For .del command, delete the replied message. """
msg_src = await delme.get_reply_message()
if delme.reply_to_msg_id:
try:
await msg_src.delete()
await delme.delete()
if BOTLOG:
await delme.client.send_message(
BOTLOG_CHATID, "Deletion of message was successful")
except rpcbaseerrors.BadRequestError:
if BOTLOG:
await delme.client.send_message(
BOTLOG_CHATID, "Well, I can't delete a message")
@register(outgoing=True, pattern="^.edit")
async def editer(edit):
""" For .editme command, edit your last message. """
message = edit.text
chat = await edit.get_input_chat()
self_id = await edit.client.get_peer_id('me')
string = str(message[6:])
i = 1
async for message in edit.client.iter_messages(chat, self_id):
if i == 2:
await message.edit(string)
await edit.delete()
break
i = i + 1
if BOTLOG:
await edit.client.send_message(BOTLOG_CHATID,
"Edit query was executed successfully")
@register(outgoing=True, pattern="^.sd")
async def selfdestruct(destroy):
""" For .sd command, make seflf-destructable messages. """
message = destroy.text
counter = int(message[4:6])
text = str(destroy.text[6:])
await destroy.delete()
smsg = await destroy.client.send_message(destroy.chat_id, text)
await sleep(counter)
await smsg.delete()
if BOTLOG:
await destroy.client.send_message(BOTLOG_CHATID,
"sd query done successfully")
CMD_HELP.update({
'purge':
'.purge\
\nUsage: Purges all messages starting from the reply.'
})
CMD_HELP.update({
'purgeme':
'.purgeme <x>\
\nUsage: Deletes x amount of your latest messages.'
})
CMD_HELP.update({"del": ".del\
\nUsage: Deletes the message you replied to."})
CMD_HELP.update({
'edit':
".edit <newmessage>\
\nUsage: Replace your last message with <newmessage>."
})
CMD_HELP.update({
'sd':
'.sd <x> <message>\
\nUsage: Creates a message that selfdestructs in x seconds.\
\nKeep the seconds under 100 since it puts your bot to sleep.'
})

View File

@@ -0,0 +1,298 @@
# -*- coding: future_fstrings -*-
# Friendly Telegram (telegram userbot)
# Copyright (C) 2018-2019 The Authors
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
import logging
import requests
import base64
import json
import telethon
from .. import loader, utils
from PIL import Image
from io import BytesIO
logger = logging.getLogger(__name__)
def register(cb):
cb(QuotesMod())
@loader.tds
class QuotesMod(loader.Module):
"""Quote a message."""
strings = {
"name": "Quotes",
"api_token_cfg_doc": "API Key/Token for Quotes.",
"api_url_cfg_doc": "API URL for Quotes.",
"colors_cfg_doc": "Username colors",
"default_username_color_cfg_doc": "Default color for the username.",
"no_reply": "<b>You didn't reply to a message.</b>",
"no_template": "<b>You didn't specify the template.</b>",
"delimiter": "</code>, <code>",
"server_error": "<b>Server error. Please report to developer.</b>",
"invalid_token": "<b>You've set an invalid token.</b>",
"unauthorized": "<b>You're unauthorized to do this.</b>",
"not_enough_permissions": "<b>Wrong template. You can use only the default one.</b>",
"templates": "<b>Available Templates:</b> <code>{}</code>",
"cannot_send_stickers": "<b>You cannot send stickers in this chat.</b>",
"admin": "admin",
"creator": "creator",
"hidden": "hidden",
"channel": "Channel",
"filename": "file.png"
}
def __init__(self):
self.config = loader.ModuleConfig("api_token", None, lambda: self.strings["api_token_cfg_doc"],
"api_url", "http://api.antiddos.systems",
lambda: self.strings["api_url_cfg_doc"],
"username_colors", ["#fb6169", "#faa357", "#b48bf2", "#85de85",
"#62d4e3", "#65bdf3", "#ff5694"],
lambda: self.strings["colors_cfg_doc"],
"default_username_color", "#b48bf2",
lambda: self.strings["default_username_color_cfg_doc"])
def config_complete(self):
self.name = self.strings["name"]
async def client_ready(self, client, db):
self.client = client
async def quotecmd(self, message): # noqa: C901
"""Quote a message.
Usage: .quote [template] [file/force_file]
Or: .quote np [template] [file/force_file]
If template is missing, possible templates are fetched.
If no args provided, default template will be used, quote sent as sticker"""
args = utils.get_args(message)
if len(args) > 0 and args[0] == 'np':
no_picture = True
del args[0]
else:
no_picture = False
reply = await message.get_reply_message()
if not reply:
return await utils.answer(message, self.strings["no_reply"])
username_color = username = admintitle = user_id = None
profile_photo_url = reply.from_id
admintitle = ""
pfp = None
if isinstance(reply.to_id, telethon.tl.types.PeerChannel) and reply.fwd_from:
user = reply.forward.chat
elif isinstance(reply.to_id, telethon.tl.types.PeerChat):
chat = await self.client(telethon.tl.functions.messages.GetFullChatRequest(reply.to_id))
participants = chat.full_chat.participants.participants
participant = next(filter(lambda x: x.user_id == reply.from_id, participants), None)
if isinstance(participant, telethon.tl.types.ChatParticipantCreator):
admintitle = self.strings["creator"]
elif isinstance(participant, telethon.tl.types.ChatParticipantAdmin):
admintitle = self.strings["admin"]
user = await reply.get_sender()
else:
user = await reply.get_sender()
username = telethon.utils.get_display_name(user)
if reply.fwd_from is not None and reply.fwd_from.post_author is not None:
username += f" ({reply.fwd_from.post_author})"
user_id = reply.from_id
if reply.fwd_from:
if reply.fwd_from.saved_from_peer:
profile_photo_url = reply.forward.chat
admintitle = self.strings["channel"]
elif reply.fwd_from.from_name:
username = reply.fwd_from.from_name
profile_photo_url = None
admintitle = ""
elif reply.forward.sender:
username = telethon.utils.get_display_name(reply.forward.sender)
profile_photo_url = reply.forward.sender.id
admintitle = ""
elif reply.forward.chat:
admintitle = self.strings["channel"]
profile_photo_url = user
else:
if isinstance(reply.to_id, telethon.tl.types.PeerUser) is False:
try:
user = await self.client(telethon.tl.functions.channels.GetParticipantRequest(message.chat_id,
user))
if isinstance(user.participant, telethon.tl.types.ChannelParticipantCreator):
admintitle = user.participant.rank or self.strings["creator"]
elif isinstance(user.participant, telethon.tl.types.ChannelParticipantAdmin):
admintitle = user.participant.rank or self.strings["admin"]
user = user.users[0]
except telethon.errors.rpcerrorlist.UserNotParticipantError:
pass
if no_picture:
profile_photo_url = ''
else:
if profile_photo_url is not None:
pfp = await self.client.download_profile_photo(profile_photo_url, bytes)
if pfp is not None:
profile_photo_url = "data:image/png;base64, " + base64.b64encode(pfp).decode()
else:
profile_photo_url = ""
if user_id is not None:
username_color = self.config["username_colors"][user_id % 7]
else:
username_color = self.config["default_username_color"]
reply_username = ""
reply_text = ""
if reply.is_reply is True:
reply_to = await reply.get_reply_message()
reply_peer = None
if reply_to.fwd_from is not None:
if reply_to.forward.chat is not None:
reply_peer = reply_to.forward.chat
elif reply_to.fwd_from.from_id is not None:
try:
user_id = reply_to.fwd_from.from_id
user = await self.client(telethon.tl.functions.users.GetFullUserRequest(user_id))
reply_peer = user.user
except ValueError:
pass
else:
reply_username = reply_to.fwd_from.from_name
elif reply_to.from_id is not None:
reply_user = await self.client(telethon.tl.functions.users.GetFullUserRequest(reply_to.from_id))
reply_peer = reply_user.user
if reply_username is None or reply_username == "":
reply_username = telethon.utils.get_display_name(reply_peer)
reply_text = reply_to.message
date = ""
if reply.fwd_from is not None:
date = reply.fwd_from.date.strftime("%H:%M")
else:
date = reply.date.strftime("%H:%M")
request = json.dumps({
"ProfilePhotoURL": profile_photo_url,
"usernameColor": username_color,
"username": username,
"adminTitle": admintitle,
"Text": reply.message,
"Markdown": get_markdown(reply),
"ReplyUsername": reply_username,
"ReplyText": reply_text,
"Date": date,
"Template": args[0] if len(args) > 0 else 'default',
"APIKey": self.config["api_token"]
})
resp = await utils.run_sync(requests.post, self.config["api_url"] + "/api/v2/quote", data=request)
resp.raise_for_status()
resp = await utils.run_sync(resp.json)
if resp["status"] == 500:
return await utils.answer(message, self.strings["server_error"])
elif resp["status"] == 401:
if resp["message"] == "ERROR_TOKEN_INVALID":
return await utils.answer(message, self.strings["invalid_token"])
else:
raise ValueError("Invalid response from server", resp)
elif resp["status"] == 403:
if resp["message"] == "ERROR_UNAUTHORIZED":
return await utils.answer(message, self.strings["unauthorized"])
else:
raise ValueError("Invalid response from server", resp)
elif resp["status"] == 404:
if resp["message"] == "ERROR_TEMPLATE_NOT_FOUND":
newreq = await utils.run_sync(requests.post, self.config["api_url"] + "/api/v1/getalltemplates", data={
"token": self.config["api_token"]
})
newreq = await utils.run_sync(newreq.json)
if newreq["status"] == "NOT_ENOUGH_PERMISSIONS":
return await utils.answer(message, self.strings["not_enough_permissions"])
elif newreq["status"] == "SUCCESS":
templates = self.strings["delimiter"].join(newreq["message"])
return await utils.answer(message, self.strings["templates"].format(templates))
elif newreq["status"] == "INVALID_TOKEN":
return await utils.answer(message, self.strings["invalid_token"])
else:
raise ValueError("Invalid response from server", newreq)
else:
raise ValueError("Invalid response from server", resp)
elif resp["status"] != 200:
raise ValueError("Invalid response from server", resp)
req = await utils.run_sync(requests.get, self.config["api_url"] + "/cdn/" + resp["message"])
req.raise_for_status()
file = BytesIO(req.content)
file.seek(0)
if len(args) == 2:
if args[1] == "file":
await utils.answer(message, file)
elif args[1] == "force_file":
file.name = self.strings["filename"]
await utils.answer(message, file, force_document=True)
else:
img = await utils.run_sync(Image.open, file)
with BytesIO() as sticker:
await utils.run_sync(img.save, sticker, "webp")
sticker.name = "sticker.webp"
sticker.seek(0)
try:
await utils.answer(message, sticker)
except telethon.errors.rpcerrorlist.ChatSendStickersForbiddenError:
await utils.answer(message, self.strings["cannot_send_stickers"])
file.close()
def get_markdown(reply):
if not reply.entities:
return []
markdown = []
for entity in reply.entities:
md_item = {
"Type": None,
"Start": entity.offset,
"End": entity.offset + entity.length - 1
}
if isinstance(entity, telethon.tl.types.MessageEntityBold):
md_item["Type"] = "bold"
elif isinstance(entity, telethon.tl.types.MessageEntityItalic):
md_item["Type"] = "italic"
elif isinstance(entity, (telethon.tl.types.MessageEntityMention, telethon.tl.types.MessageEntityTextUrl,
telethon.tl.types.MessageEntityMentionName, telethon.tl.types.MessageEntityHashtag,
telethon.tl.types.MessageEntityCashtag, telethon.tl.types.MessageEntityBotCommand,
telethon.tl.types.MessageEntityUrl)):
md_item["Type"] = "link"
elif isinstance(entity, telethon.tl.types.MessageEntityCode):
md_item["Type"] = "code"
elif isinstance(entity, telethon.tl.types.MessageEntityStrike):
md_item["Type"] = "stroke"
elif isinstance(entity, telethon.tl.types.MessageEntityUnderline):
md_item["Type"] = "underline"
else:
logger.warning("Unknown entity: " + str(entity))
markdown.append(md_item)
return markdown

View File

@@ -0,0 +1,147 @@
# encoding: utf-8
import asyncio
import time
import logging
from .. import loader, utils
logger = logging.getLogger(__name__)
def register(cb):
cb(RangeMod())
@loader.tds
class RangeMod(loader.Module):
"""Provides numbers as in Python range with delay"""
strings = {
"name": "Range",
"no_args": "<b>Not enough args (minimum {})</b>",
"delay_num": "<b>Delay must be a number</b>",
"args_int": "<b>All range args must be integers</b>",
"many_args": "<b>There must be no more than {} arguments</b>"
}
def __init__(self):
self.config = loader.ModuleConfig(
"msg_format", "{0}", "Format of each message. {0} replaces current number.",
"default_delay", 1.0, "Delay in all commands by default"
)
self.name = self.strings['name']
def config_complete(self):
self.name = self.strings['name']
async def _do_range(self, range_args, delay, message):
"""for internal usage; do range itself"""
await message.delete()
for now in range(*range_args):
before = time.time()
await message.respond(self.config['msg_format'].format(now))
delta = time.time() - before
await asyncio.sleep(max(delay - delta, 0))
async def _get_args(self, message, minn, maxn):
args = utils.get_args(message)
if len(args) < minn:
logger.warning(f'Minimum {minn} {"args" if minn != 1 else "arg"}, {len(args)} provided')
await utils.answer(message, self.strings['no_args'].format(minn))
return None
elif len(args) > maxn:
logger.warning(f'Maximum {maxn} {"args" if maxn != 1 else "arg"}, {len(args)} provided')
await utils.answer(message, self.strings['many_args'].format(maxn))
return None
return args
async def _check_range_args(self, range_args, message):
"""for internal usage; check if range args are int"""
try:
range_args = [int(x) for x in range_args]
return range_args
except ValueError:
logger.warning(f'Impossible to convert all range args to int ({range_args})')
await utils.answer(message, self.strings['args_int'])
return None
async def rangecmd(self, message):
"""Iterates over the given range and returns each number in separate message.
Usage: .range <python_range_args>"""
args = await self._get_args(message, 1, 3)
if args is None:
return # user done sth wrong
delay = self.config['default_delay']
range_args = await self._check_range_args(args, message)
if range_args is None:
return # user done sth wrong
await self._do_range(range_args, delay, message)
async def drangecmd(self, message):
"""Iterates over the given range and returns each number in separate message.
Usage: .drange <delay> <python_range_args>"""
args = await self._get_args(message, 2, 4)
if args is None:
return # user done sth wrong
try:
delay = float(args[0])
except ValueError:
logger.warning(f'Impossible to convert delay to float ({args[0]})')
await utils.answer(message, self.strings['delay_num'])
return
range_args = await self._check_range_args(args[1:], message)
if range_args is None:
return
await self._do_range(range_args, delay, message)
async def countcmd(self, message):
"""Count from 1 to N.\nUsage: .count <delay> <N> or .count <N>"""
args = await self._get_args(message, 1, 2)
if args is None:
return
if len(args) == 1:
delay = self.config['default_delay']
range_args = (1, args[0], 1)
elif len(args) == 2:
try:
delay = float(args[0])
except ValueError:
logger.warning(f'Impossible to convert delay to float ({args[0]})')
await utils.answer(message, self.strings['delay_num'])
return
range_args = (1, args[1], 1)
range_args = await self._check_range_args(range_args, message)
if range_args is None:
return
range_args[1] += 1 # so last number we print will be N itself
await self._do_range(range_args, delay, message)
async def rcountcmd(self, message):
"""Count from N to 1.\nUsage: .rcount <delay> <N> or .rcount <N>"""
args = await self._get_args(message, 1, 2)
if args is None:
return
if len(args) == 1:
delay = self.config['default_delay']
range_args = (args[0], 0, -1)
elif len(args) == 2:
try:
delay = float(args[0])
except ValueError:
logger.warning(f'Impossible to convert delay to float ({args[0]})')
await utils.answer(message, self.strings['delay_num'])
return
range_args = (args[1], 0, -1)
range_args = await self._check_range_args(range_args, message)
if range_args is None:
return
await self._do_range(range_args, delay, message)

View File

@@ -0,0 +1,66 @@
from .. import loader, utils
# from telethon import*
from telethon import functions, types
import logging
import datetime
import time
import asyncio
logger = logging.getLogger(__name__)
def register(cb):
cb(REPLMod())
@loader.tds
class REPLMod(loader.Module):
"""REPLIED for selected users"""
strings = {"name": "REPL"}
d = dict()
def __init__(self):
self.name = self.strings["name"]
def config_complete(self):
pass
async def client_ready(self, client, db):
self._db = db
self._me = await client.get_me()
async def addtxcmd(self, message):
"""Select users\nFor example: .addtx used_id \"text when reply (Default: \'.\'\""""
args = utils.get_args(message)
if not len(args):
await utils.answer(message, "Напиши .help REPL, там есть пример, как нужно делать.\nТы сделал неправильно!")
elif len(args) == 1:
self.d[int(args[0])] = '.'
else:
f = ""
for i in range(1, len(args)):
f += args[i]
if i != len(args) - 1:
f += " "
self.d[int(args[0])] = f
await utils.answer(message, "Done.\nP.S: 3 seconds later it's automatic delete")
await asyncio.sleep(3)
await message.delete()
async def clrtxcmd(self, message):
"""Unselect user\nFor example: `.clrtx used_id` for one user or `.clrtx` for all users"""
args = utils.get_args(message)
if not len(args):
self.d.clear()
else:
self.d.pop(int(args[0]))
await utils.answer(message, "Done.\nP.S: 3 seconds later it's automatic delete")
await asyncio.sleep(3)
await message.delete()
async def watcher(self, message):
if (message.from_id in self.d) and (
message.mentioned or getattr(message.to_id, "user_id", None) == self._me.id):
await message.respond(self.d[message.from_id], reply_to=message)

View File

@@ -0,0 +1,81 @@
# requires: pymongo dnspython
# Забейте
import asyncio
import pymongo
import logging
logger = logging.getLogger(__name__)
from .. import loader, utils
class Student:
def __init__(self, id: int, last_name: str, first_name: str,
patronymic: str, grade: int, region: str, academ: bool, approved: int=None):
self.last_name = last_name
self.first_name = first_name
self.patronymic = patronymic
self.grade = int(grade)
self.region = region
self.academ = bool(academ)
self.approved = approved
self.id = int(id)
def __str__(self):
p = 'Академ' if self.academ else 'Отбор'
# a = f'Уже вроде бы добавлен в чат (tg://user?id={self.approved})' if self.approved else 'Еще нет в чате'
return f'[{p}.{self.id}] {self.last_name} {self.first_name} {self.patronymic}, '\
f'{self.grade} класс, из {self.region}'
class SiriusMod(loader.Module):
"""Ищем поступивших на ИЮ2020"""
strings = {"name": "Sirius"}
def __init__(self):
self.config = loader.ModuleConfig(
# name - default - description
"db_uri", None, "Database URI, if you dont know where to take it - nevermind",
"db_db", None, "database",
"db_coll", None, "collection",
"replace_ё", True, "replace ё with е in requests, incorrect usage may return incorrect result"
)
self.name = self.strings['name']
self.db = None
def config_complete(self):
self.db = pymongo.MongoClient(self.config['db_uri'])\
.get_database(self.config['db_db']).get_collection(self.config['db_coll'])
async def findcmd(self, message):
arg = utils.get_args_raw(message).strip()
if self.config['replace_ё']:
arg = arg.replace('ё', 'е')
arg = arg.replace('Ё', 'Е')
logger.debug('Got: %s', arg)
if not arg:
await utils.answer(message, 'Только 1 аргумент - номер в списке или фамилия/имя')
if arg.isdigit():
add = f'людей с номером {arg}'
arg = int(arg)
users = list(self.db.find({"id": arg}))
elif ' ' in arg or arg.lower() == 'янао': # Костыли костыли
add = f'людей из региона {arg}'
_users = list(self.db.find())
users = []
for user in _users:
if user['region'].lower() == arg.lower():
users.append(user)
else:
add = f'людей, которых зовут {arg}'
arg = arg.capitalize()
users = list(self.db.find({'$or': [{"last_name": arg}, {"first_name": arg}, {"patronymic": arg}]}))
msg = [f'{len(users)} всего {add}', '==']
for user in users:
del user['_id']
s = Student(**user)
msg += [str(s), '==']
msg = msg[:-1]
msg = '\n'.join(msg)
await utils.answer(message, msg)

View File

@@ -0,0 +1,92 @@
# Copyright (C) 2019 The Raphielscape Company LLC.
#
# Licensed under the Raphielscape Public License, Version 1.c (the "License");
# you may not use this file except in compliance with the License.
import asyncio
from asyncio import wait, sleep
from userbot import BOTLOG, BOTLOG_CHATID, CMD_HELP
from userbot.events import register
@register(outgoing=True, pattern="^.cspam (.*)")
async def tmeme(e):
cspam = str(e.pattern_match.group(1))
message = cspam.replace(" ", "")
await e.delete()
for letter in message:
await e.respond(letter)
if BOTLOG:
await e.client.send_message(
BOTLOG_CHATID, "#CSPAM\n"
"TSpam was executed successfully")
@register(outgoing=True, pattern="^.wspam (.*)")
async def tmeme(e):
wspam = str(e.pattern_match.group(1))
message = wspam.split()
await e.delete()
for word in message:
await e.respond(word)
if BOTLOG:
await e.client.send_message(
BOTLOG_CHATID, "#WSPAM\n"
"WSpam was executed successfully")
@register(outgoing=True, pattern="^.spam (.*)")
async def spammer(e):
counter = int(e.pattern_match.group(1).split(' ', 1)[0])
spam_message = str(e.pattern_match.group(1).split(' ', 1)[1])
await e.delete()
await asyncio.wait([e.respond(spam_message) for i in range(counter)])
if BOTLOG:
await e.client.send_message(BOTLOG_CHATID, "#SPAM\n"
"Spam was executed successfully")
@register(outgoing=True, pattern="^.picspam")
async def tiny_pic_spam(e):
message = e.text
text = message.split()
counter = int(text[1])
link = str(text[2])
await e.delete()
await asyncio.wait([e.client.send_file(e.chat_id, link) for i in range(counter)])
if BOTLOG:
await e.client.send_message(
BOTLOG_CHATID, "#PICSPAM\n"
"PicSpam was executed successfully")
@register(outgoing=True, pattern="^.delayspam (.*)")
async def spammer(e):
spamDelay = float(e.pattern_match.group(1).split(' ', 2)[0])
counter = int(e.pattern_match.group(1).split(' ', 2)[1])
spam_message = str(e.pattern_match.group(1).split(' ', 2)[2])
await e.delete()
for i in range(1, counter):
await e.respond(spam_message)
await sleep(spamDelay)
if BOTLOG:
await e.client.send_message(
BOTLOG_CHATID, "#DelaySPAM\n"
"DelaySpam was executed successfully")
CMD_HELP.update({
"spam":
".cspam <text>\
\nUsage: Spam the text letter by letter.\
\n\n.spam <count> <text>\
\nUsage: Floods text in the chat !!\
\n\n.wspam <text>\
\nUsage: Spam the text word by word.\
\n\n.picspam <count> <link to image/gif>\
\nUsage: As if text spam was not enough !!\
\n\n.delayspam <delay> <count> <text>\
\nUsage: .bigspam but with custom delay.\
\n\n\nNOTE : Spam at your own risk !!"
})

View File

@@ -0,0 +1,37 @@
# fuck python the encoding: utf-8
from .. import loader, utils
import logging
import datetime
import time
import asyncio
logger = logging.getLogger(__name__)
def register(cb):
cb(SPFMod())
@loader.tds
class SPFMod(loader.Module):
"""Этот модуль геи личку ваших друзей"""
strings = {"name": "ЖУЖАКА НАХУЙ"}
def __init__(self):
self.name = self.strings["name"]
def config_complete(self):
pass
async def spfcmd(self, message):
"""Чтобы использовать пишем так: .spf @ник_вашегоруга"""
args = utils.get_args(message)
if not args:
await utils.answer(message, "Вы не указали кому хотите писать\nЧтобы использовать напишите так: .spf @ник_вашегоруга")
return
who = args[0][1:]
conv = message.client.conversation("t.me/" + who,
timeout=5, exclusive=True)
for i in range(100):
await conv.send_message("Ты гей")

View File

@@ -0,0 +1,245 @@
from .. import loader, utils
import logging
import random
logger = logging.getLogger(__name__)
version = 4.8
sentence_min = 3
sentence_max = 10
# paragraph_min = 10
# paragraph_max = 20
print_length = False
m = ['некультурный', 'необразованный',
'гороховый', 'мудовый', 'глупенький',
'малолетний', 'ебучий', 'гнилой',
'собачий', 'ссаный', 'моржовый',
'вредный', 'прибабахнутый', 'ебаный',
'волшебный', 'сказочный', 'маленький',
'приёмный', 'сральный', 'пердёжный',
'обоссанный', 'обосранный', 'чёртов',
'грязный', 'тупой', 'нищий', 'родной', 'мусорный',
'дегенеративный',
'распроклятый', 'турецкий', 'блядский',
'ёбаный', 'хуев', 'хуёвый', 'ебанутый',
'ёбнутый', 'грязный', 'зелёный', 'сукин',
'лысый', 'пожилой', 'вонючий', 'чокнутый']
f = ['некультурная', 'необразованная',
'гороховая', 'мудовая', 'глупенькая',
'малолетняя', 'ебучая', 'гнилая',
'собачья', 'ссаная', 'моржовая',
'вредная', 'прибабахнутая', 'ебаная',
'волшебная', 'сказочная', 'маленькая',
'приёмная', 'сральная', 'пердёжная',
'обоссанная', 'обосранная', 'чёртова',
'грязная', 'тупая', 'нищая',
'родная', 'мусорная', 'дегенеративная',
'распроклятая', 'турецкая', 'блядская',
'ёбаная', 'хуева', 'хуёвая', 'ебанутая',
'ёбнутая', 'грязная', 'зелёная', 'сукина',
'лысая', 'пожилая', 'вонючая', 'чокнутая']
s = ['некультурное', 'необразованное',
'гороховое', 'мудовое', 'глупенькое',
'малолетнее', 'ебучее', 'гнилое',
'собачье', 'ссаное', 'моржовое',
'вредное', 'прибабахнутое', 'ебаное',
'волшебное', 'сказочное', 'маленькое',
'приёмное', 'сральное', 'пердёжное',
'обоссанное', 'обосранное', 'чёртово', 'грязное',
'тупое', 'нищее', 'родное', 'мусорное', 'дегенеративное',
'распроклятое', 'турецкое', 'блядское',
'ёбаное', 'хуево', 'хуёвое', 'ебанутое',
'ёбнутое', 'грязное', 'зелёное', 'сукино',
'лысое', 'пожилое', 'вонючее', 'чокнутое']
k = ['из жопы', 'в ловушке', 'в бане',
'на хуе', 'в дурке', 'из стула', 'в дурке ебаной',
'в хуипе', 'в запечатанной колоде']
n = ['негра', 'джокера', 'тупого говна', 'хуйни ебаной',
'хуя', 'феминизма', 'говна',
'от народа', 'хуйни', 'Навального',
'ловушкера', 'Путина', 'русского народа', 'вонючки', 'с функцией жопа']
o = ['пиздец', 'блять', 'попался в ловушку',
'тебя забайтили', 'ловушка джокера', 'тебе бан',
'фак ю', 'убейся', 'соси',
'ёбаный твой рот', 'срал я на тебя',
'убейся об стену', 'соси пизду', 'у тебя хуй вместо носа',
'купи мою подписку на ютубе',
'хуй соси', 'губой тряси', 'я съел деда',
'насрал в пизду',
'22 июня 1642 года Карл Первый поднял королевский штандарт (королевский флаг), что по английским традициям означало объявление войны',
'мне этот мир абсолютно понятен',
'я был на этой планете бесконечным множеством',
'но тебе этого не понять',
'иди преисполняться в гранях каких-то',
'пиздуй - бороздуй',
'бредишь', 'вот я какну и смываю, и ты так делай',
'не надо шутить с войной',
'твою дочку ебут', 'залупаешься',
'хули ты пиздишь', 'поцелуй лошадиную сраку',
'распронаёб тебя', 'ъеь', 'ьуь', 'аье',
'какого хуя они в другом порядке разложены',
'ай фак ю булщит щит',
'он за углом сидит и тебе на голову дрочит',
'армяне в нарды играют', 'жирняк гай',
'иди сюда, попробуй меня трахнуть, я тебя сам трахну',
'что ты там делаешь', 'беги за горизонт',
'попал в дурку ебаную', 'был бы ты человек', 'нахуй',
'запомни', 'хули ты сюда лезешь',
'высрана твоя морда', 'возьми салфетку',
'я бы никому не проиграл',
'иди нахуй', 'иди',
'я тебя ебал, гад, срать на нас говна',
'я тебя ебал гадить нас срать так',
'держи в курсе', 'несёшь хуйню какую-то',
'русские вперёд']
d = ['бекон', 'сыр', 'пенис', 'член',
'мудозвон', 'лицемер', 'лжец',
'хуй', 'гомогей', 'чай', 'рукоблуд',
'долбан', 'пидорас', 'сын', 'козёл',
'газ', 'фашист', 'пососатель',
'дегенерат', 'спермобак', 'долбоёб',
'клоун', 'паразит', 'письколёт',
'мудак', 'спидозник', 'пудж', 'кремлебот',
'объебос', 'дурачок', 'хуебес', 'пиздолёт',
'педик', 'педик - медведик', 'дебил', 'дифичент',
'кок сакер', 'пиздабол', 'аутист', 'гадёныш', 'выблядок',
'глиномес', 'даун', 'хер', 'булщит', 'засранец',
'инвалид', 'дурак', 'болван',
'минетчик', 'онанист', 'напёрдыш',
'чилипиздрик', 'пиздюк', 'гей', 'ловушкер',
'пендос', 'наркоман', 'алкаш', 'жиробас',
'рак', 'укурок', 'крокодил', 'ебальник',
'секс-раб', 'потомок', 'дрыщ',
'урод', 'карлик', 'дед инсайд', 'волк',
'калыван', 'либераст', 'шакал',
'педофил', 'бомж', 'пингвин', 'жираф',
'огурец', 'салат', 'лук', 'картофель',
'деградант', 'спам', 'человек', 'гуманитарий',
'язык', 'стол', 'PEP-8', 'ебалай', 'враг', 'недруг', 'супостат',
'кретин', 'козолуп', 'свинарь',
'униженец', 'опущенец', 'муравей',
'дятел', 'козёл', 'жирняк', 'говноед',
'чёрт', 'суслик', 'идиот', 'жлоб', 'мерзавец',
'негодяй', 'подлец', 'ублюдок', 'гад',
'гавкошмыг', 'чикибамбонатор', 'чикибамбог',
'джокер', 'жмых', 'жмышок', 'жмышонок',
'куколд', 'ебалай', 'ушлёпок',
'хуесос', 'членосос', 'чикибамбонёнок',
'чикибан', 'чикибомбастер', 'чайник',
'чикибамбонизатор', 'чикибамбог']
dd = ['куколда', 'хуйолда', 'мудила', 'блядина', 'гнида',
'пидрила', 'тварь', 'сука', 'сперма', 'пидорасина',
'либераха', 'срака', 'жопа', 'петушара', 'залупа',
'хуета', 'пупа', 'петька', 'блядь', 'елда', 'тряпка',
'яма', 'хуемразь', 'срань', 'мошонка', 'ссанина',
'вагина', 'пизда', 'пососательница',
'ловушка', 'паста', 'макаронина',
'жиробасина', 'радфемка', 'шлюха', 'прошмандовка',
'жируха', 'доска', 'уродина',
'плоскодонка', 'скотина', 'омега',
'черешня', 'ватрушка', 'шишка',
'ракушка', 'свинья', 'какашка',
'гнилушка', 'лягушка', 'свинушка',
'картошка', 'волчара', 'дочь', 'пешка',
'давалка', 'пососательница',
'колбаса', 'собака', 'мохнатка', 'жижа',
'какашка', 'какуля', 'душа', 'вражина',
'падла', 'болезнь', 'бумажка', 'вонючка',
'тень', 'гадина', 'чикибамбони',
'микробамбони', 'мышь', 'мразь',
'мразина', 'мразота']
ddd = ['удобрение', 'уёбище', 'ебло', 'хуйло',
'чудище', 'говно', 'яблоко', 'животное',
'дерьмо', 'блядотище', 'дитя', 'порождение',
'очко', 'растение', 'ебало', 'ведро',
'мудило', 'хуепучило']
gens = ['03', '14', '25', '8',
'06', '16', '26', '30',
'41', '52', '303', '330', '0',
'414', '441', '1', '8',
'525', '552', '2', '067',
'167', '267', '306', '416',
'526', '07', '8', '8', '8',
'17', '27', '8', '8', '8',
'307', '417', '527', '8', '8',
'3067', '4167', '5267']
array = [d, dd, ddd, m, f, s, k, n, o]
def generate(word_count: int, caps_rate: int, name: str):
res = []
priv = ''
if name:
priv += f'Привет, {name}! '
caps_rate %= 100
priv += 'Ты, '
word_count_now = 0
while word_count_now < word_count:
tempi = word_count + 1
while word_count_now + tempi > word_count:
random.seed()
y = random.choice(gens)
x = []
for j in y:
x.append(random.choice(array[int(j)]))
x = ' '.join(x)
tempi = len(x.split())
res.append(x)
word_count_now += tempi
res = ', '.join(res)
res = res.split()
count = 0
kek = random.randint(sentence_min, sentence_max)
for v in range(len(res)):
if res[v].endswith(','):
count += 1
if count % kek == 0:
count = 0
random.seed()
kek = random.randint(sentence_min, sentence_max)
res[v] = res[v][:-1] + '.'
if v < len(res) - 1:
res[v + 1] = res[v + 1][0].upper() + res[v + 1][1:]
res[0] = priv + res[0]
res = ' '.join(res).split()
for v in range(len(res)):
random.seed()
z = random.randint(0, 99)
if z < caps_rate:
res[v] = res[v].upper()
return ' '.join(res) + '.'
# КТО ПРОЧИТАЛ ТОТ ЗДОХНЕТ
def register(cb):
cb(TralkaMod())
@loader.tds
class TralkaMod(loader.Module):
"""Generates pastes"""
strings = {"name": "Tralka"}
def __init__(self):
self.config = loader.ModuleConfig()
self.name = self.strings['name']
async def tralkacmd(self, message):
""".tralka <word_count> <caps_rate (in %)> <recepient name>"""
args = utils.get_args(message)
if len(args) < 2:
await utils.answer(message, "Not enough arguments")
elif len(args) == 2:
await utils.answer(message, generate(int(args[0]), int(args[1]), None))
else:
await utils.answer(message, generate(int(args[0]), int(args[1]), args[2]))

View File

@@ -0,0 +1,94 @@
from .. import loader, utils
import logging
import datetime
import time
import asyncio
logger = logging.getLogger(__name__)
def register(cb):
cb(WAITMod())
@loader.tds
class WAITMod(loader.Module):
"""Этот модуль поможет вам удалить сообщение через n секунд/минут"""
strings = {"name": "wait"}
def __init__(self):
self.name = self.strings["name"]
def config_complete(self):
pass
async def wait5cmd(self, message):
"""Эта команда удаляет сообхение черезе 5 секунд"""
await utils.answer(message, "Через 5 секунд это сообщение удалится")
for i in range(4, -1, -1):
await asyncio.sleep(1)
await utils.answer(message, "Через " + str(i) + " секунд это сообщение удалится")
await message.delete()
async def waitcmd(self, message):
"""Эта команда удаляет сообхение через n секунд, \nписать нужно так: .wait <n>, если хотите секунды\nи так .wait <n>m, если хотите ждать в минутах\n(например .wait 5m)"""
args = utils.get_args(message)
if not args or len(args) > 1:
await utils.answer(message, "Вы не указали число секунд или указали несколько параметров")
else:
try:
g = -1
h = ""
try:
g = int(args[0][:len(args[0])])
except:
try:
g = int(args[0][:len(args[0]) - 1])
h = args[0][len(args[0]) - 1]
except:
await utils.answer(message, "Вы указали не число!")
if g > 0:
if h == 's' or h == '':
x = g
lst = "Через " + str(x) + " секунд это сообщение удалится"
await utils.answer(message, lst)
dd = time.time()
while time.time() - dd < x:
now = "Через " + str(x - round(time.time() - dd)) + " секунд это сообщение удалится"
if now != lst:
await utils.answer(message, now)
lst = now
await message.delete()
elif h == 'm':
x = g
lst = "Через " + str(x) + " минут это сообщение удалится"
await utils.answer(message, lst)
dd = time.time()
ff = x * 60
llst = x
while time.time() - dd < ff:
oo = round((ff - round(time.time() - dd)) / 60)
nw = oo
if nw == llst:
await asyncio.sleep(0.1)
continue
now = "Через " + str(nw) + " минут это сообщение удалится"
await utils.answer(message, now)
llst = nw
await message.delete()
else:
await utils.answer(message, "Вы указали не число!")
except:
await utils.answer(message, "Упс, ошибочка вышла! Напшите @gerasikoff, он вам поможет")
async def tagcmd(self, message):
"""Эта команда для троллинга друзей. \nЕй вы можете тегнуть друга, а сообщение само удалится!"""
await message.delete()