mirror of
https://github.com/MuRuLOSE/limoka.git
synced 2026-06-16 14:34:17 +02:00
Commited backup
This commit is contained in:
31
KeyZenD/modules/.github/workflows/python-publish.yml
vendored
Normal file
31
KeyZenD/modules/.github/workflows/python-publish.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
# This workflows will upload a Python Package using Twine when a release is created
|
||||
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
|
||||
|
||||
name: Upload Python Package
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install setuptools wheel twine
|
||||
- name: Build and publish
|
||||
env:
|
||||
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
|
||||
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
|
||||
run: |
|
||||
python setup.py sdist bdist_wheel
|
||||
twine upload dist/*
|
||||
39
KeyZenD/modules/0x.py
Normal file
39
KeyZenD/modules/0x.py
Normal file
@@ -0,0 +1,39 @@
|
||||
from .. import loader, utils # pylint: disable=relative-beyond-top-level
|
||||
from requests import post
|
||||
import io
|
||||
|
||||
|
||||
@loader.tds
|
||||
class x0Mod(loader.Module):
|
||||
"""Uploader"""
|
||||
strings = {
|
||||
"name": "x0 Uploader"
|
||||
}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
|
||||
|
||||
@loader.sudo
|
||||
async def x0cmd(self, message):
|
||||
await message.edit("<b>Uploading...</b>")
|
||||
reply = await message.get_reply_message()
|
||||
if not reply:
|
||||
await message.edit("<b>Reply to message!</b>")
|
||||
return
|
||||
media = reply.media
|
||||
if not media:
|
||||
file = io.BytesIO(bytes(reply.raw_text, "utf-8"))
|
||||
file.name = "txt.txt"
|
||||
else:
|
||||
file = io.BytesIO(await self.client.download_file(media))
|
||||
file.name = reply.file.name if reply.file.name else reply.file.id+reply.file.ext
|
||||
try:
|
||||
x0at = post('https://x0.at', files={'file': file})
|
||||
except ConnectionError as e:
|
||||
await message.edit(ste(e))
|
||||
return
|
||||
url = x0at.text
|
||||
output = f'<a href="{url}">URL: </a><code>{url}</code>'
|
||||
await message.edit(output)
|
||||
|
||||
55
KeyZenD/modules/BlackLines.py
Normal file
55
KeyZenD/modules/BlackLines.py
Normal file
@@ -0,0 +1,55 @@
|
||||
from telethon import events
|
||||
from telethon.errors.rpcerrorlist import YouBlockedUserError
|
||||
from .. import loader, utils
|
||||
|
||||
|
||||
def register(cb):
|
||||
cb(BlackLinesMod())
|
||||
|
||||
|
||||
class BlackLinesMod(loader.Module):
|
||||
"""Draw line via @BlackLinesBot"""
|
||||
|
||||
strings = {'name': 'BlackLines'}
|
||||
|
||||
def __init__(self):
|
||||
self.name = self.strings['name']
|
||||
self._me = None
|
||||
self._ratelimit = []
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self._db = db
|
||||
self._client = client
|
||||
self.me = await client.get_me()
|
||||
|
||||
async def linecmd(self, message):
|
||||
""".line <reply to photo>"""
|
||||
|
||||
reply = await message.get_reply_message()
|
||||
if not reply:
|
||||
await message.edit("reply to photo")
|
||||
return
|
||||
try:
|
||||
photo = reply.media.photo
|
||||
except:
|
||||
await message.edit("reply to photo only")
|
||||
return
|
||||
|
||||
args = utils.get_args_raw(message)
|
||||
|
||||
|
||||
chat = '@BlackLinesBot'
|
||||
await message.edit('@BlackLinesBot <code>in process...</code>')
|
||||
async with message.client.conversation(chat) as conv:
|
||||
try:
|
||||
response = conv.wait_event(events.NewMessage(incoming=True, from_users=1051644279))
|
||||
await message.client.send_file(chat, photo, caption=args)
|
||||
response = await response
|
||||
except YouBlockedUserError:
|
||||
await message.reply('<code>Unblock</code> @BlackLinesBot')
|
||||
return
|
||||
|
||||
await message.delete()
|
||||
await message.client.send_file(message.to_id, response.media)
|
||||
|
||||
#у меня каждый коммит в чате упоминается ботом
|
||||
105
KeyZenD/modules/Circles.py
Normal file
105
KeyZenD/modules/Circles.py
Normal file
@@ -0,0 +1,105 @@
|
||||
from .. import loader, utils # pylint: disable=relative-beyond-top-level
|
||||
from PIL import Image, ImageDraw, ImageOps, ImageFilter
|
||||
import io
|
||||
from telethon.tl.types import DocumentAttributeFilename
|
||||
import logging
|
||||
from moviepy.editor import VideoFileClip
|
||||
import os
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def register(cb):
|
||||
cb(CirclesMod())
|
||||
|
||||
|
||||
@loader.tds
|
||||
class CirclesMod(loader.Module):
|
||||
"""округляет всё"""
|
||||
strings = {
|
||||
"name": "Circles"
|
||||
}
|
||||
def __init__(self):
|
||||
self.name = self.strings['name']
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
|
||||
|
||||
|
||||
@loader.sudo
|
||||
async def roundcmd(self, message):
|
||||
""".round <Reply to image/sticker or video/gif>"""
|
||||
reply = None
|
||||
if message.is_reply:
|
||||
reply = await message.get_reply_message()
|
||||
data = await check_media(reply)
|
||||
if isinstance(data, bool):
|
||||
await utils.answer(message, "<b>Reply to image/sticker or video/gif!</b>")
|
||||
return
|
||||
else:
|
||||
await utils.answer(message, "<b>Reply to image/sticker or video/gif!</b>")
|
||||
return
|
||||
data, type = data
|
||||
if type == "img":
|
||||
await message.edit("<b>Processing image</b>📷")
|
||||
img = io.BytesIO()
|
||||
bytes = await message.client.download_file(data, img)
|
||||
im = Image.open(img)
|
||||
w, h = im.size
|
||||
img = Image.new("RGBA", (w,h), (0,0,0,0))
|
||||
img.paste(im, (0, 0))
|
||||
m = min(w, h)
|
||||
img = img.crop(((w-m)//2, (h-m)//2, (w+m)//2, (h+m)//2))
|
||||
w, h = img.size
|
||||
mask = Image.new('L', (w, h), 0)
|
||||
draw = ImageDraw.Draw(mask)
|
||||
draw.ellipse((10, 10, w-10, h-10), fill=255)
|
||||
mask = mask.filter(ImageFilter.GaussianBlur(2))
|
||||
img = ImageOps.fit(img, (w, h))
|
||||
img.putalpha(mask)
|
||||
im = io.BytesIO()
|
||||
im.name = "img.webp"
|
||||
img.save(im)
|
||||
im.seek(0)
|
||||
await message.client.send_file(message.to_id, im, reply_to=reply)
|
||||
else:
|
||||
await message.edit("<b>Processing video</b>🎥")
|
||||
await message.client.download_file(data, "video.mp4")
|
||||
video = VideoFileClip("video.mp4")
|
||||
video.reader.close()
|
||||
w, h = video.size
|
||||
m = min(w, h)
|
||||
box = [(w-m)//2, (h-m)//2, (w+m)//2, (h+m)//2]
|
||||
video = video.crop(*box)
|
||||
await message.edit("<b>Saving video</b>📼")
|
||||
video.write_videofile("result.mp4")
|
||||
await message.client.send_file(message.to_id, "result.mp4", video_note=True, reply_to=reply)
|
||||
os.remove("video.mp4")
|
||||
os.remove("result.mp4")
|
||||
await message.delete()
|
||||
|
||||
|
||||
|
||||
async def check_media(reply):
|
||||
type = "img"
|
||||
if reply and reply.media:
|
||||
if reply.photo:
|
||||
data = reply.photo
|
||||
elif reply.document:
|
||||
if DocumentAttributeFilename(file_name='AnimatedSticker.tgs') in reply.media.document.attributes:
|
||||
return False
|
||||
if reply.gif or reply.video:
|
||||
type = "vid"
|
||||
if reply.audio or reply.voice:
|
||||
return False
|
||||
data = reply.media.document
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
if not data or data is None:
|
||||
return False
|
||||
else:
|
||||
return (data, type)
|
||||
111
KeyZenD/modules/DNA.py
Normal file
111
KeyZenD/modules/DNA.py
Normal file
@@ -0,0 +1,111 @@
|
||||
# requires: pillow
|
||||
# requires: wand
|
||||
from .. import loader, utils
|
||||
import io
|
||||
from telethon.tl.types import DocumentAttributeFilename
|
||||
import logging
|
||||
from wand.image import Image
|
||||
from PIL import Image as IM
|
||||
# https://t.me/KeyZenD
|
||||
# https://t.me/SomeScripts
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def register(cb):
|
||||
cb(DistortNoApiMod())
|
||||
|
||||
|
||||
@loader.tds
|
||||
class DistortNoApiMod(loader.Module):
|
||||
"""distorting images"""
|
||||
strings = {
|
||||
"name": "DistortNoApi"
|
||||
}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
|
||||
@loader.sudo
|
||||
async def distortcmd(self, message):
|
||||
""".distort <reply to photo>
|
||||
.distort im
|
||||
.distort 50
|
||||
.distort 50 im
|
||||
.distort im 50
|
||||
im => кидает стикеры как фото
|
||||
50 => (от 0 до дохуя) процент сжатия"""
|
||||
if message.is_reply:
|
||||
reply_message = await message.get_reply_message()
|
||||
data, mime = await check_media(reply_message)
|
||||
if isinstance(data, bool):
|
||||
await utils.answer(message, "<code>Reply to image or stick!</code>")
|
||||
return
|
||||
else:
|
||||
await utils.answer(message, "<code>Reply to image or stick!</code>")
|
||||
return
|
||||
rescale_rate = 70
|
||||
a = utils.get_args(message)
|
||||
force_file = False
|
||||
if a:
|
||||
if 'im' in a:
|
||||
force_file = True
|
||||
a.remove('im')
|
||||
if len(a) > 0:
|
||||
if a[0].isdigit():
|
||||
rescale_rate = int(a[0])
|
||||
if rescale_rate <= 0:
|
||||
rescale_rate = 70
|
||||
|
||||
await message.edit("<code>D i s t o r t i n g . . .</code>")
|
||||
file = await message.client.download_media(data, bytes)
|
||||
file, img = io.BytesIO(file), io.BytesIO()
|
||||
img.name = 'img.png'
|
||||
IM.open(file).save(img, 'PNG')
|
||||
media = await distort(io.BytesIO(img.getvalue()), rescale_rate)
|
||||
out, im = io.BytesIO(), IM.open(media)
|
||||
if force_file:
|
||||
mime = 'png'
|
||||
out.name = f'out.{mime}'
|
||||
im.save(out, mime.upper())
|
||||
out.seek(0)
|
||||
await message.edit("<code>S e n d i n g . . .</code>")
|
||||
await message.client.send_file(message.to_id, out, reply_to=reply_message.id)
|
||||
|
||||
await message.delete()
|
||||
|
||||
async def distort(file, rescale_rate):
|
||||
img = Image(file=file)
|
||||
x, y = img.size[0], img.size[1]
|
||||
popx = int(rescale_rate*(x//100))
|
||||
popy = int(rescale_rate*(y//100))
|
||||
img.liquid_rescale(popx, popy, delta_x=1, rigidity=0)
|
||||
img.resize(x, y)
|
||||
out = io.BytesIO()
|
||||
out.name = f'output.png'
|
||||
img.save(file=out)
|
||||
return io.BytesIO(out.getvalue())
|
||||
|
||||
async def check_media(reply_message):
|
||||
mime = None
|
||||
if reply_message and reply_message.media:
|
||||
if reply_message.photo:
|
||||
data = reply_message.photo
|
||||
mime = 'image/jpeg'
|
||||
elif reply_message.document:
|
||||
if DocumentAttributeFilename(file_name='AnimatedSticker.tgs') in reply_message.media.document.attributes:
|
||||
return False, mime
|
||||
if reply_message.gif or reply_message.video or reply_message.audio or reply_message.voice:
|
||||
return False, mime
|
||||
data = reply_message.media.document
|
||||
mime = reply_message.media.document.mime_type
|
||||
if 'image/' not in mime:
|
||||
return False, mime
|
||||
else:
|
||||
return False, mime
|
||||
else:
|
||||
return False, mime
|
||||
|
||||
if not data or data is None:
|
||||
return False, mime
|
||||
else:
|
||||
mime = mime.split('/')[1]
|
||||
return data, mime
|
||||
68
KeyZenD/modules/Glitcher.py
Normal file
68
KeyZenD/modules/Glitcher.py
Normal file
@@ -0,0 +1,68 @@
|
||||
import asyncio
|
||||
import logging
|
||||
import sys, os, random
|
||||
from .. import loader, utils
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@loader.tds
|
||||
class GlitcherMod(loader.Module):
|
||||
"""Glitcher of anything"""
|
||||
strings = {"name": "Glitcher",
|
||||
"reply": "Reply to message!",
|
||||
"error": "Impossible to upload file!",
|
||||
"processing": "Work in progress!"}
|
||||
|
||||
@loader.unrestricted
|
||||
async def glitchcmd(self, message):
|
||||
""".glitch level: float or int <reply to anything>"""
|
||||
reply = await message.get_reply_message()
|
||||
if not reply:
|
||||
await message.edit("".join([ random.choice(html).format(ch) for ch in self.strings("reply", message)]))
|
||||
return
|
||||
if not reply.file:
|
||||
infile = "message.txt"
|
||||
f = open(infile,"w")
|
||||
f.write(reply.text)
|
||||
f.close()
|
||||
outfile = "glitched_message.txt"
|
||||
else:
|
||||
infile = await reply.download_media()
|
||||
outfile = "glitched_"+infile
|
||||
|
||||
percent = 0.1
|
||||
try:
|
||||
percent = float(utils.get_args_raw(message))
|
||||
except ValueError or TypeError:
|
||||
pass
|
||||
await message.edit("".join([ random.choice(html).format(ch) for ch in self.strings("processing", message)]))
|
||||
with open(infile, 'rb') as inf:
|
||||
with open(outfile, 'wb') as outf:
|
||||
fileext = infile.split(".")[1]
|
||||
try:
|
||||
for byte in range(headersize[fileext]):
|
||||
inbyte = inf.read(1)
|
||||
outbyte = inbyte
|
||||
outf.write(outbyte)
|
||||
except KeyError:
|
||||
pass
|
||||
while True:
|
||||
inbyte = inf.read(1)
|
||||
if not inbyte:
|
||||
break
|
||||
if (random.random() < percent/100):
|
||||
outbyte = os.urandom(1)
|
||||
else:
|
||||
outbyte = inbyte
|
||||
outf.write(outbyte)
|
||||
try:
|
||||
await reply.reply(file=outfile)
|
||||
await message.delete()
|
||||
except:
|
||||
await message.edit("".join([ random.choice(html).format(ch) for ch in self.strings("error", message) ]))
|
||||
finally:
|
||||
[os.remove(file) for file in [infile, outfile]]
|
||||
|
||||
html = ["<b>{}<b>", "<code>{}</code>", "<i>{}</i>", "<del>{}</del>", "<u>{}</u>", '<a href="https://bruh.moment">{}</a>']
|
||||
headersize = {'jpg': 9, 'png': 8, 'bmp': 54, 'gif': 14, 'tiff': 8}
|
||||
70
KeyZenD/modules/Hasher.py
Normal file
70
KeyZenD/modules/Hasher.py
Normal file
@@ -0,0 +1,70 @@
|
||||
from .. import loader, utils
|
||||
from hashlib import md5, sha1, sha224, sha256, sha384, sha512, blake2b, blake2s
|
||||
|
||||
def register(cb):
|
||||
cb(HasherMod())
|
||||
|
||||
class HasherMod(loader.Module):
|
||||
"""Hashing text and files"""
|
||||
strings = {'name': 'Hasher'}
|
||||
def __init__(self):
|
||||
self.name = self.strings['name']
|
||||
self._me = None
|
||||
self._ratelimit = []
|
||||
async def client_ready(self, client, db):
|
||||
self._db = db
|
||||
self._client = client
|
||||
self.me = await client.get_me()
|
||||
|
||||
async def md5cmd(self, message):
|
||||
""".md5 <(text or media) or (reply to text or media)>\nHashing to md5"""
|
||||
await hashing(message, 0)
|
||||
async def sha1cmd(self, message):
|
||||
""".sha1 <(text or media) or (reply to text or media)\nHashing to sha1"""
|
||||
await hashing(message, 1)
|
||||
async def sha224cmd(self, message):
|
||||
""".sha224 <(text or media) or (reply to text or media)\nHashing to sha224"""
|
||||
await hashing(message, 2)
|
||||
async def sha256cmd(self, message):
|
||||
""".sha255 <(text or media) or (reply to text or media)\nHashing to sha256"""
|
||||
await hashing(message, 3)
|
||||
async def sha384cmd(self, message):
|
||||
""".sha384 <(text or media) or (reply to text or media)\nHashing to sha384"""
|
||||
await hashing(message, 4)
|
||||
async def sha512cmd(self, message):
|
||||
""".sha512 <(text or media) or (reply to text or media)\nHashing to sha512"""
|
||||
await hashing(message, 5)
|
||||
async def blake2bcmd(self, message):
|
||||
""".blake2 <(text or media) or (reply to text or media)\nHashing to blake2"""
|
||||
await hashing(message, 6)
|
||||
async def blake2scmd(self, message):
|
||||
""".blake2s <(text or media) or (reply to text or media)\nHashing to blake2s"""
|
||||
await hashing(message, 7)
|
||||
|
||||
async def hashing(m, type):
|
||||
types = [md5, sha1, sha224, sha256, sha384, sha512, blake2b, blake2s]
|
||||
typez = ["md5", "sha1", "sha224", "sha256", "sha384", "sha512", "blake2b", "blake2s"]
|
||||
|
||||
reply = await m.get_reply_message()
|
||||
mtext = utils.get_args_raw(m)
|
||||
if m.media:
|
||||
await m.edit("<b>D o w n l o a d i n g . . .</b>")
|
||||
data = await m.client.download_file(m, bytes)
|
||||
elif mtext:
|
||||
data = mtext.encode()
|
||||
elif reply:
|
||||
if reply.media:
|
||||
await m.edit("<b>D o w n l o a d i n g . . .</b>")
|
||||
data = await m.client.download_file(reply, bytes)
|
||||
else:
|
||||
data = reply.raw_text.encode()
|
||||
else:
|
||||
await m.edit(f"<b>What hashing to {typez[type]}?</b>")
|
||||
return
|
||||
|
||||
await m.edit("<b>H a s h i n g . . .</b>")
|
||||
try:
|
||||
result = types[type](data)
|
||||
await m.edit(typez[type].upper()+": <code>" + str(result.hexdigest()).upper()+"</code>")
|
||||
except:
|
||||
await m.edit("<b>ERЯOR!</b>")
|
||||
56
KeyZenD/modules/Lines50.py
Normal file
56
KeyZenD/modules/Lines50.py
Normal file
@@ -0,0 +1,56 @@
|
||||
from telethon import events
|
||||
from telethon.errors.rpcerrorlist import YouBlockedUserError
|
||||
from .. import loader, utils
|
||||
|
||||
|
||||
def register(cb):
|
||||
cb(Lines50Mod())
|
||||
|
||||
|
||||
class Lines50Mod(loader.Module):
|
||||
"""Draw photo with 50 lines via @Lines50Bot"""
|
||||
|
||||
strings = {'name': 'Lines50'}
|
||||
|
||||
def __init__(self):
|
||||
self.name = self.strings['name']
|
||||
self._me = None
|
||||
self._ratelimit = []
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self._db = db
|
||||
self._client = client
|
||||
self.me = await client.get_me()
|
||||
|
||||
async def linescmd(self, message):
|
||||
""".lines <reply to photo>"""
|
||||
|
||||
reply = await message.get_reply_message()
|
||||
if not reply:
|
||||
await message.edit("reply to photo")
|
||||
return
|
||||
try:
|
||||
photo = reply.media.photo
|
||||
except:
|
||||
await message.edit("reply to photo only")
|
||||
return
|
||||
|
||||
|
||||
|
||||
|
||||
chat = '@Lines50Bot'
|
||||
await message.edit('@Lines50Bot <code>in process...</code>')
|
||||
async with message.client.conversation(chat) as conv:
|
||||
try:
|
||||
response = conv.wait_event(events.NewMessage(incoming=True, from_users=1120861844))
|
||||
|
||||
await message.client.send_file(chat, photo)
|
||||
|
||||
response = await response
|
||||
except YouBlockedUserError:
|
||||
await message.reply('<code>Unblock</code> @Lines50Bot')
|
||||
return
|
||||
|
||||
await message.delete()
|
||||
await message.client.send_file(message.to_id, response.media)
|
||||
|
||||
44
KeyZenD/modules/LoremIpsum.py
Normal file
44
KeyZenD/modules/LoremIpsum.py
Normal file
@@ -0,0 +1,44 @@
|
||||
from .. import loader, utils
|
||||
import io
|
||||
from requests import get
|
||||
|
||||
def register(cb):
|
||||
cb(LoremIpsumMod())
|
||||
|
||||
|
||||
class LoremIpsumMod(loader.Module):
|
||||
"""Lorem Ipsum generation"""
|
||||
|
||||
strings = {'name': 'LoermIpsum'}
|
||||
|
||||
def __init__(self):
|
||||
self.name = self.strings['name']
|
||||
|
||||
async def loremipsumcmd(self, message):
|
||||
""".loremipsum <count: int> <length: str> <file?>
|
||||
count - number of paragraphs| std: 1
|
||||
length - s-short, m-medium, l-long, v-verylong|std: m(edium)
|
||||
file - if nothing- send as message, if anything- send as file"""
|
||||
s = 'small'
|
||||
m = length = 'medium'
|
||||
l = 'long'
|
||||
v = 'verylong'
|
||||
args = utils.get_args(message)
|
||||
count = 1
|
||||
as_file = False
|
||||
if args:
|
||||
count = int(args[0]) if args[0].isdigit() else 1
|
||||
if len(args) == 2:
|
||||
lenght = args[1].lower()
|
||||
length = s if lenght in [s[:i+1] for i in range(len(s))] else l if lenght in [l[:i+1] for i in range(len(l))] else v if lenght in [v[:i+1] for i in range(len(v))] else m # сижу ахуел
|
||||
if len(args) >= 3:
|
||||
as_file = True
|
||||
url = f"https://loripsum.net/api/{count}/{length}/plaintext"
|
||||
out = get(url)
|
||||
if as_file:
|
||||
out = io.BytesIO(out.content)
|
||||
out.name = f"LoremIpsum.{count}.txt"
|
||||
out.seek(0)
|
||||
else: out = out.text
|
||||
await utils.answer(message, out)
|
||||
|
||||
33
KeyZenD/modules/MTF.py
Normal file
33
KeyZenD/modules/MTF.py
Normal file
@@ -0,0 +1,33 @@
|
||||
from .. import loader, utils
|
||||
import io
|
||||
|
||||
@loader.tds
|
||||
class MTFMod(loader.Module):
|
||||
"""send Message as file"""
|
||||
strings = {'name': 'MessageToFile'}
|
||||
|
||||
async def mtfcmd(self, message):
|
||||
""".mtf <reply to text>"""
|
||||
reply = await message.get_reply_message()
|
||||
if not reply or not reply.message:
|
||||
await message.edit("<b>Reply to text!</b>")
|
||||
return
|
||||
text = bytes(reply.raw_text, "utf8")
|
||||
fname = utils.get_args_raw(message) or str(message.id+reply.id)+".txt"
|
||||
file = io.BytesIO(text)
|
||||
file.name = fname
|
||||
file.seek(0)
|
||||
await reply.reply(file=file)
|
||||
await message.delete()
|
||||
|
||||
async def ftmcmd(self, message):
|
||||
""".ftm <reply to file>"""
|
||||
reply = await message.get_reply_message()
|
||||
if not reply or not reply.file:
|
||||
await message.edit("<b>Reply to file!</b>")
|
||||
return
|
||||
text = await reply.download_media(bytes)
|
||||
text = str(text, "utf8")
|
||||
if utils.get_args(message):
|
||||
text = f"<code>{text}</code>"
|
||||
await utils.answer(message, utils.escape_html(text))
|
||||
32
KeyZenD/modules/MacAshoT.py
Normal file
32
KeyZenD/modules/MacAshoT.py
Normal file
@@ -0,0 +1,32 @@
|
||||
from .. import loader,utils
|
||||
from PIL import Image,ImageFilter
|
||||
import io,random,string
|
||||
class aMod(loader.Module):
|
||||
strings={'name':'MacAshoT'}
|
||||
async def maccmd(S,message):
|
||||
R=True;Q='image';P='/';L='RGBA';K='<b>Image?</b>';A=message;C=await A.get_reply_message();B=io.BytesIO();M=None
|
||||
if A.file:
|
||||
if A.file.mime_type.split(P)[0]==Q:await A.download_media(B)
|
||||
elif C:
|
||||
if C.file:
|
||||
if C.file.mime_type.split(P)[0]==Q:M=R;await C.download_media(B)
|
||||
else:await A.edit(K);return
|
||||
else:await A.edit(K);return
|
||||
elif C:
|
||||
if C.file:
|
||||
if C.file.mime_type.split(P)[0]==Q:M=R;await C.download_media(B)
|
||||
else:await A.edit(K);return
|
||||
else:await A.edit(K);return
|
||||
try:I=Image.open(B)
|
||||
except:await A.edit(K);return
|
||||
await A.edit('<b>Working...</b>');F,G=I.size;B=Image.new(L,(F,G));J=min(F//100,G//100);D=Image.new(L,(F+J*40,G+J*40),'#fff')
|
||||
if I.mode==L:
|
||||
B.paste(I,(0,0),I);E=Image.new(L,(F,G))
|
||||
for N in range(F):
|
||||
for O in range(G):
|
||||
if B.getpixel((N,O))!=(0,0,0,0):E.putpixel((N,O),(0,0,0))
|
||||
else:B.paste(I,(0,0));E=Image.new(L,(F,G),'black')
|
||||
E=E.resize((F+J*5,G+J*5));D.paste(E,((D.width-E.width)//2,(D.height-E.height)//2),E);D=D.filter(ImageFilter.GaussianBlur(J*5));D.paste(B,((D.width-B.width)//2,(D.height-B.height)//2),B);H=io.BytesIO();H.name='-'.join([''.join([random.choice(string.hexdigits)for B in range(A)])for A in[5,4,3,2,1]])+'.png';D.save(H,'PNG');H.seek(0)
|
||||
if utils.get_args_raw(A):await A.client.send_file(A.to_id,H,force_document=R);await A.delete()
|
||||
elif M:await C.reply(file=H);await A.delete()
|
||||
else:await A.edit(file=H,text='')
|
||||
83
KeyZenD/modules/MegaMozg.py
Normal file
83
KeyZenD/modules/MegaMozg.py
Normal file
@@ -0,0 +1,83 @@
|
||||
# @KeyZenD & @D4n13l3k00
|
||||
|
||||
import random
|
||||
|
||||
from telethon import types
|
||||
|
||||
from .. import loader, utils
|
||||
|
||||
|
||||
@loader.tds
|
||||
class MegaMozgMod(loader.Module):
|
||||
strings = {
|
||||
'name': 'MegaMozg',
|
||||
'pref': '<b>[MegaMozg]</b> ',
|
||||
'need_arg': '{}Нужен аргумент',
|
||||
'status': '{}{}',
|
||||
'on': '{}Включён',
|
||||
'off': '{}Выключен',
|
||||
|
||||
}
|
||||
_db_name = 'MegaMozg'
|
||||
|
||||
async def client_ready(self, _, db):
|
||||
self.db = db
|
||||
|
||||
@staticmethod
|
||||
def str2bool(v):
|
||||
return v.lower() in ("yes", "y", "ye", "yea", "true", "t", "1", "on", "enable", "start", "run", "go", "да")
|
||||
|
||||
|
||||
async def mozgcmd(self, m: types.Message):
|
||||
'.mozg <on/off/...> - Переключить режим дурачка в чате'
|
||||
args = utils.get_args_raw(m)
|
||||
if not m.chat:
|
||||
return
|
||||
chat = m.chat.id
|
||||
if self.str2bool(args):
|
||||
chats: list = self.db.get(self._db_name, 'chats', [])
|
||||
chats.append(chat)
|
||||
chats = list(set(chats))
|
||||
self.db.set(self._db_name, 'chats', chats)
|
||||
return await utils.answer(m, self.strings('on').format(self.strings('pref')))
|
||||
chats: list = self.db.get(self._db_name, 'chats', [])
|
||||
try:
|
||||
chats.remove(chat)
|
||||
except:
|
||||
pass
|
||||
chats = list(set(chats))
|
||||
self.db.set(self._db_name, 'chats', chats)
|
||||
return await utils.answer(m, self.strings('off').format(self.strings('pref')))
|
||||
|
||||
async def mozgchancecmd(self, m: types.Message):
|
||||
'.mozgchance <int> - Устанвоить шанс 1 к N.\n0 - всегда отвечать'
|
||||
args: str = utils.get_args_raw(m)
|
||||
if args.isdigit():
|
||||
self.db.set(self._db_name, 'chance', int(args))
|
||||
return await utils.answer(m, self.strings('status').format(self.strings('pref'), args))
|
||||
|
||||
return await utils.answer(m, self.strings('need_arg').format(self.strings('pref')))
|
||||
|
||||
async def watcher(self, m: types.Message):
|
||||
if not isinstance(m, types.Message):
|
||||
return
|
||||
if m.sender_id == (await m.client.get_me()).id or not m.chat:
|
||||
return
|
||||
if m.chat.id not in self.db.get(self._db_name, 'chats', []):
|
||||
return
|
||||
ch = self.db.get(self._db_name, 'chance', 0)
|
||||
if ch != 0:
|
||||
if random.randint(0, ch) != 0:
|
||||
return
|
||||
text = m.raw_text
|
||||
words = {random.choice(
|
||||
list(filter(lambda x: len(x) >= 3, text.split()))) for _ in ".."}
|
||||
msgs = []
|
||||
for word in words:
|
||||
[msgs.append(x) async for x in m.client.iter_messages(m.chat.id, search=word) if x.replies and x.replies.max_id]
|
||||
replier = random.choice(msgs)
|
||||
sid = replier.id
|
||||
eid = replier.replies.max_id
|
||||
msgs = [x async for x in m.client.iter_messages(m.chat.id, ids=list(range(sid+1, eid+1))) if x and x.reply_to and x.reply_to.reply_to_msg_id == sid]
|
||||
msg = random.choice(msgs)
|
||||
await m.reply(msg)
|
||||
51
KeyZenD/modules/MicroQuotes.py
Normal file
51
KeyZenD/modules/MicroQuotes.py
Normal file
@@ -0,0 +1,51 @@
|
||||
from .. import loader, utils
|
||||
import io
|
||||
from PIL import Image, ImageFont, ImageDraw
|
||||
import requests
|
||||
import textwrap
|
||||
|
||||
@loader.tds
|
||||
class MicroQuotesMod(loader.Module):
|
||||
"""Микроцитаты"""
|
||||
strings = {"name": "MicroQuotes"}
|
||||
|
||||
async def mqcmd(self, message):
|
||||
""".mq <реплай на текст>"""
|
||||
bw = False if utils.get_args(message) else True
|
||||
reply = await message.get_reply_message()
|
||||
if not reply or not reply.raw_text:
|
||||
await message.edit("<b>Ответь командой на умную цитату!</b>")
|
||||
return
|
||||
sender = reply.sender_id
|
||||
|
||||
if not sender:
|
||||
sender = message.chat.id
|
||||
if sender == 1087968824:
|
||||
sender = message.chat.id
|
||||
pfp = await message.client.download_profile_photo(sender, bytes)
|
||||
await message.edit("<i>И сказал этот гений...</i>")
|
||||
if not pfp:
|
||||
pfp = b'BM:\x00\x00\x00\x00\x00\x00\x006\x00\x00\x00(\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01\x00\x18\x00\x00\x00\x00\x00\x04\x00\x00\x00\xc4\x0e\x00\x00\xc4\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\x00'
|
||||
text = "\n".join(textwrap.wrap(reply.raw_text, 30))
|
||||
text = "“"+text+"„"
|
||||
bf = requests.get("https://raw.githubusercontent.com/KeyZenD/l/master/times.ttf").content
|
||||
font = ImageFont.truetype(io.BytesIO(bf), 50)
|
||||
im = Image.open(io.BytesIO(pfp))
|
||||
if bw:
|
||||
im = im.convert("L")
|
||||
im = im.convert("RGBA").resize((1024, 1024))
|
||||
w, h = im.size
|
||||
w_, h_ = 20*(w//100), 20*(h//100)
|
||||
im_ = Image.new("RGBA", (w-w_, h-h_), (0, 0, 0))
|
||||
im_.putalpha(150)
|
||||
im.paste(im_, (w_//2, h_//2), im_)
|
||||
draw = ImageDraw.Draw(im)
|
||||
_w, _h = draw.textsize(text=text, font=font)
|
||||
x, y = (w-_w)//2, (h-_h)//2
|
||||
draw.text((x, y), text=text, font=font, fill="#fff", align="center")
|
||||
output=io.BytesIO()
|
||||
im.save(output, "PNG")
|
||||
output.seek(0)
|
||||
await reply.reply(file=output)
|
||||
await message.delete()
|
||||
|
||||
51
KeyZenD/modules/MirrorFlip.py
Normal file
51
KeyZenD/modules/MirrorFlip.py
Normal file
@@ -0,0 +1,51 @@
|
||||
_C='png'
|
||||
_B='name'
|
||||
_A='image'
|
||||
_R='отражает'
|
||||
_P='часть.'
|
||||
from .. import loader as _L,utils as U
|
||||
import logging,asyncio
|
||||
from telethon.tl.types import DocumentAttributeFilename as DAF
|
||||
from PIL import Image,ImageOps as IO
|
||||
from io import BytesIO as ist
|
||||
logger=logging.getLogger(__name__)
|
||||
@_L.tds
|
||||
class MFMod(_L.Module):
|
||||
f'{_R} фоточки';strings={_B:'MirrorFlip'}
|
||||
def __init__(A):A.name=A.strings[_B]
|
||||
async def llcmd(A,message):await KZD(message,1)
|
||||
async def rrcmd(A,message):await KZD(message,2)
|
||||
async def uucmd(A,message):await KZD(message,3)
|
||||
async def ddcmd(A,message):await KZD(message,4)
|
||||
async def KZD(message,type):
|
||||
S='sticker';A=message;N=await A.get_reply_message();Q,J=await CM(N)
|
||||
if not Q or not N:await A.edit('<b>Реплай на стикер или фото!</b>');return
|
||||
O='KZD.'+J;P=U.get_args_raw(A)
|
||||
if P:
|
||||
if P in[_A[:A]for A in range(1,len(_A)+1)]:O='KZD.png';J=_C
|
||||
if P in[S[:A]for A in range(1,len(S)+1)]:O='KZD.webp';J='webp'
|
||||
R=ist();await A.edit('<b>Извиняюсь...</b>');await A.client.download_media(Q,R);E=Image.open(R);B,C=E.size
|
||||
if B%2!=0 and type in[1,2]or C%2!=0 and type in[3,4]:E=E.resize((B+1,C+1));C,B=E.size
|
||||
if type==1:D=0;F=0;G=B//2;H=C;K=G;L=D
|
||||
if type==2:D=B//2;F=0;G=B;H=C;K=F;L=F
|
||||
if type==3:D=0;F=0;G=B;H=C//2;K=D;L=H
|
||||
if type==4:D=0;F=C//2;G=B;H=C;K=D;L=D
|
||||
I=E.crop((D,F,G,H))
|
||||
if type in[1,2]:I=IO.mirror(I)
|
||||
else:I=IO.flip(I)
|
||||
E.paste(I,(K,L));M=ist();M.name=O;E.save(M,J);M.seek(0);await A.client.send_file(A.to_id,M,reply_to=N);await A.delete()
|
||||
async def CM(R):
|
||||
D=False;C=None;A=R
|
||||
if A and A.media:
|
||||
if A.photo:B=A.photo;E=_C
|
||||
elif A.document:
|
||||
if DAF(file_name='AnimatedSticker.tgs')in A.media.document.attributes:return D,C
|
||||
if A.gif or A.video or A.audio or A.voice:return D,C
|
||||
B=A.media.document
|
||||
if _A not in B.mime_type:return D,C
|
||||
E=B.mime_type.split('/')[1]
|
||||
else:return D,C
|
||||
else:return D,C
|
||||
if not B or B is C:return D,C
|
||||
else:return B,E
|
||||
#Блять ну я и долбаёб так код сохранять
|
||||
46
KeyZenD/modules/MirrorFlipV2.py
Normal file
46
KeyZenD/modules/MirrorFlipV2.py
Normal file
@@ -0,0 +1,46 @@
|
||||
from PIL import Image, ImageOps
|
||||
from .. import loader, utils
|
||||
from io import BytesIO
|
||||
from asyncio import sleep
|
||||
|
||||
class MirrorFlipMod(loader.Module):
|
||||
strings = {"name": "MirrorFlip", 0:"<b>Reply to image.</b>"}
|
||||
|
||||
async def llcmd(self, m):
|
||||
return await make(m, 1)
|
||||
async def rrcmd(self, m):
|
||||
return await make(m, 2)
|
||||
async def uucmd(self, m):
|
||||
return await make(m, 3)
|
||||
async def ddcmd(self, m):
|
||||
return await make(m, 4)
|
||||
|
||||
async def make(m, o):
|
||||
r = await m.get_reply_message()
|
||||
s = None
|
||||
try:
|
||||
s = await r.download_media(bytes, thumb=-1 if not r.sticker else None)
|
||||
img = Image.open(BytesIO(s))
|
||||
except:
|
||||
pass
|
||||
if not s:
|
||||
return await utils.answer(m, MirrorFlipMod.strings[0])
|
||||
await m.delete()
|
||||
w, h = img.size
|
||||
if o in [1, 2]:
|
||||
if o == 2:
|
||||
img = ImageOps.mirror(img)
|
||||
part = img.crop([0, 0, w//2, h])
|
||||
img = ImageOps.mirror(img)
|
||||
else:
|
||||
if o == 4:
|
||||
img = ImageOps.flip(img)
|
||||
part = img.crop([0, 0, w, h//2])
|
||||
img = ImageOps.flip(img)
|
||||
img.paste(part, (0, 0))
|
||||
out = BytesIO()
|
||||
out.name = "x.webp" if r.sticker else "x.png"
|
||||
img.save(out)
|
||||
out.seek(0)
|
||||
return await r.reply(file=out)
|
||||
|
||||
46
KeyZenD/modules/OneMessage.py
Normal file
46
KeyZenD/modules/OneMessage.py
Normal file
@@ -0,0 +1,46 @@
|
||||
from .. import loader, utils
|
||||
from telethon.tl.types import Message
|
||||
|
||||
class OneMessageMod(loader.Module):
|
||||
"""@faq lines"""
|
||||
strings = {'name': 'OneMessage'}
|
||||
def __init__(self):
|
||||
self.name = self.strings['name']
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
self._db = db
|
||||
|
||||
@loader.sudo
|
||||
async def omstartcmd(self, message):
|
||||
"""Start OneMessage mode"""
|
||||
self._db.set("OneMessage", "status", True)
|
||||
self._db.set("OneMessage", "my_id", message.sender_id)
|
||||
await message.edit("<b>OneMessage mode activated!</b>")
|
||||
|
||||
async def omstopcmd(self, message):
|
||||
"""Stop OneMessage mode"""
|
||||
self._db.set("OneMessage", "status", False)
|
||||
await message.edit("<b>OneMessage mode diactivated!</b>")
|
||||
|
||||
async def watcher(self, message):
|
||||
if not isinstance(message, Message):
|
||||
return
|
||||
if message.message:
|
||||
if message.raw_text[0] in self._db.get("friendly-telegram.modules.corectrl", "command_prefix", ".") or message.fwd_from:
|
||||
return
|
||||
if self._db.get("OneMessage", "status", None) and message.sender_id == self._db.get("OneMessage", "my_id", None) and not message.media:
|
||||
last_msg = (await self.client.get_messages(message.to_id, limit=2))[-1]
|
||||
if last_msg.sender_id == message.sender_id and not last_msg.fwd_from:
|
||||
text = last_msg.text
|
||||
text += "\n"*2
|
||||
text += message.text
|
||||
if message.is_reply:
|
||||
message, last_msg = last_msg, message
|
||||
try:
|
||||
await last_msg.edit(text)
|
||||
await message.delete()
|
||||
except:
|
||||
return
|
||||
|
||||
|
||||
|
||||
224
KeyZenD/modules/PillowTools.py
Normal file
224
KeyZenD/modules/PillowTools.py
Normal file
@@ -0,0 +1,224 @@
|
||||
import io
|
||||
|
||||
from PIL import Image, ImageOps
|
||||
from telethon.tl.types import DocumentAttributeFilename
|
||||
from uniborg.util import admin_cmd
|
||||
|
||||
|
||||
|
||||
@borg.on(admin_cmd(pattern=".new ?(.*)", allow_sudo=True))
|
||||
async def pilnew(event):
|
||||
uinp = event.pattern_match.group(1)
|
||||
|
||||
if not uinp:
|
||||
get = await event.get_reply_message()
|
||||
if not get:
|
||||
await event.delete()
|
||||
return
|
||||
uinp = get.text
|
||||
uinp = uinp.split(" ", 2)
|
||||
try:
|
||||
x = int(uinp[0])
|
||||
y = int(uinp[1])
|
||||
except ValueError:
|
||||
await event.edit("ERROR INPUT=> X or Y is not int")
|
||||
return
|
||||
if "(" in uinp[2] and ")" in uinp[2]:
|
||||
color = uinp[2].replace("(","").replace(")","").split(", ")
|
||||
try:
|
||||
a = 255
|
||||
r = int(color[0])
|
||||
g = int(color[1])
|
||||
b = int(color[2])
|
||||
if len(color) == 4:
|
||||
a = int(color[3])
|
||||
except ValueError:
|
||||
await event.edit("ERROR INPUT=> R or G or B is not int")
|
||||
return
|
||||
color = (r, g, b, a)
|
||||
else:
|
||||
color = uinp[2]
|
||||
|
||||
try:
|
||||
image = Image.new("RGBA", (x, y), color)
|
||||
except Exception as e:
|
||||
await event.edit("ERROR IN DRAW\n"+str(e))
|
||||
return
|
||||
|
||||
await event.delete()
|
||||
image_stream = io.BytesIO()
|
||||
image_stream.name = "pilnew.png"
|
||||
image.save(image_stream, "PNG")
|
||||
image_stream.seek(0)
|
||||
|
||||
await event.client.send_file(event.chat_id, image_stream)
|
||||
|
||||
@borg.on(admin_cmd(pattern=".rotate ?(.*)", allow_sudo=True))
|
||||
async def pilrotate(event):
|
||||
try:
|
||||
angle = int(event.pattern_match.group(1))
|
||||
except ValueError:
|
||||
await event.edit("ERROR INPUT=> ANGLE")
|
||||
|
||||
if event.is_reply:
|
||||
reply_message = await event.get_reply_message()
|
||||
data = await check_media(reply_message)
|
||||
|
||||
if isinstance(data, bool):
|
||||
await event.edit("`I can't rotate that!".upper())
|
||||
return
|
||||
else:
|
||||
await event.edit("Reply to an image or sticker to rotate it!".upper())
|
||||
return
|
||||
|
||||
image = io.BytesIO()
|
||||
await event.client.download_media(data, image)
|
||||
image = Image.open(image)
|
||||
|
||||
try:
|
||||
image = image.rotate(angle, expand=True)
|
||||
except Exception as e:
|
||||
await event.edit("ERROR IN ROTATE\n"+str(e))
|
||||
return
|
||||
await event.delete()
|
||||
image_stream = io.BytesIO()
|
||||
image_stream.name = "pilrotate.png"
|
||||
image.save(image_stream, "PNG")
|
||||
image_stream.seek(0)
|
||||
await event.client.send_file(event.chat_id, image_stream)
|
||||
|
||||
|
||||
@borg.on(admin_cmd(pattern=".ops ?(.*)", allow_sudo=True))
|
||||
async def pilops(event):
|
||||
way = event.pattern_match.group(1)
|
||||
if not way:
|
||||
return
|
||||
if event.is_reply:
|
||||
reply_message = await event.get_reply_message()
|
||||
data = await check_media(reply_message)
|
||||
|
||||
if isinstance(data, bool):
|
||||
await event.edit("`I can't ops that!".upper())
|
||||
return
|
||||
else:
|
||||
await event.edit("Reply to an image or sticker to ops it!".upper())
|
||||
return
|
||||
|
||||
image = io.BytesIO()
|
||||
await event.client.download_media(data, image)
|
||||
image = Image.open(image)
|
||||
|
||||
if "m" in way:
|
||||
try:
|
||||
image = ImageOps.mirror(image)
|
||||
except Exception as e:
|
||||
await event.edit("ERROR IN MIRROR\n"+str(e))
|
||||
return
|
||||
if "f" in way:
|
||||
try:
|
||||
image = ImageOps.flip(image)
|
||||
except Exception as e:
|
||||
await event.edit("ERROR IN FLIP\n"+str(e))
|
||||
return
|
||||
|
||||
await event.delete()
|
||||
image_stream = io.BytesIO()
|
||||
image_stream.name = "pilops.png"
|
||||
image.save(image_stream, "PNG")
|
||||
image_stream.seek(0)
|
||||
await event.client.send_file(event.chat_id, image_stream)
|
||||
|
||||
|
||||
|
||||
|
||||
@borg.on(admin_cmd(pattern=".resize ?(.*)", allow_sudo=True))
|
||||
async def pilrotate(event):
|
||||
if event.is_reply:
|
||||
reply_message = await event.get_reply_message()
|
||||
data = await check_media(reply_message)
|
||||
|
||||
if isinstance(data, bool):
|
||||
await event.edit("`I can't resize that!".upper())
|
||||
return
|
||||
else:
|
||||
await event.edit("Reply to an image or sticker to resize it!".upper())
|
||||
return
|
||||
uinp = event.pattern_match.group(1)
|
||||
|
||||
if not uinp:
|
||||
await event.edit("What's about input".upper())
|
||||
return
|
||||
uinp = uinp.split()
|
||||
image = io.BytesIO()
|
||||
await event.client.download_media(data, image)
|
||||
image = Image.open(image)
|
||||
x, y = image.size
|
||||
rx, ry = None, None
|
||||
if len(uinp) == 1:
|
||||
try:
|
||||
rx, ry = int(uinp[0]), int(uinp[0])
|
||||
except ValueError:
|
||||
if uinp[0] == "x":
|
||||
rx, ry = x, x
|
||||
if uinp[0] == "y":
|
||||
rx, ry = y, y
|
||||
else:
|
||||
await event.edit("INPUT MUST BE STING")
|
||||
return
|
||||
else:
|
||||
if uinp[0] == "x":
|
||||
rx = x
|
||||
if uinp[0] == "y":
|
||||
rx = y
|
||||
if uinp[1] == "x":
|
||||
ry = x
|
||||
if uinp[1] == "y":
|
||||
ry = y
|
||||
if not rx:
|
||||
try:
|
||||
rx = int(uinp[0])
|
||||
except:
|
||||
await event.edit("ERROR IN INPUT")
|
||||
return
|
||||
if not ry:
|
||||
try:
|
||||
ry = int(uinp[1])
|
||||
except:
|
||||
await event.edit("ERROR IN INPUT")
|
||||
return
|
||||
|
||||
|
||||
try:
|
||||
image = image.resize((rx, ry))
|
||||
except Exception as e:
|
||||
await event.edit("ERROR IN RESIZE\n"+str(e))
|
||||
return
|
||||
await event.delete()
|
||||
image_stream = io.BytesIO()
|
||||
image_stream.name = "pilresize.png"
|
||||
image.save(image_stream, "PNG")
|
||||
image_stream.seek(0)
|
||||
await event.client.send_file(event.chat_id, image_stream)
|
||||
|
||||
|
||||
|
||||
async def check_media(reply_message):
|
||||
if reply_message and reply_message.media:
|
||||
if reply_message.photo:
|
||||
data = reply_message.photo
|
||||
elif reply_message.document:
|
||||
if DocumentAttributeFilename(file_name='AnimatedSticker.tgs') in reply_message.media.document.attributes:
|
||||
return False
|
||||
if reply_message.gif or reply_message.video or reply_message.audio or reply_message.voice:
|
||||
return False
|
||||
data = reply_message.media.document
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
if not data or data is None:
|
||||
return False
|
||||
else:
|
||||
return data
|
||||
|
||||
80
KeyZenD/modules/QRtools.py
Normal file
80
KeyZenD/modules/QRtools.py
Normal file
@@ -0,0 +1,80 @@
|
||||
from .. import loader, utils
|
||||
from telethon.tl.types import DocumentAttributeFilename
|
||||
from requests import get, post
|
||||
from PIL import Image
|
||||
from io import BytesIO
|
||||
|
||||
@loader.tds
|
||||
class QRtoolsMod(loader.Module):
|
||||
"""Generator and reader of QR codes"""
|
||||
strings = {"name": "QR tool's"}
|
||||
@loader.owner
|
||||
async def makeqrcmd(self, message):
|
||||
""".makeqr <text or reply>"""
|
||||
text = utils.get_args_raw(message)
|
||||
reply = await message.get_reply_message()
|
||||
file = False
|
||||
if not text or text.lower() == ".file":
|
||||
if text and text == ".file":
|
||||
file = True
|
||||
if not reply or not reply.message:
|
||||
await message.edit("<b>Нет текста для кодирования!</b>")
|
||||
return
|
||||
text = reply.raw_text
|
||||
else:
|
||||
if text.startswith(".file"):
|
||||
file = True
|
||||
text = text[5:].strip()
|
||||
url = "https://api.qrserver.com/v1/create-qr-code/?data={}&size=512x512&charset-source=UTF-8&charset-target=UTF-8&ecc=L&color=0-0-0&bgcolor=255-255-255&margin=1&qzone=1&format=png"
|
||||
r = get(url.format(text), stream=True)
|
||||
qrcode = BytesIO()
|
||||
qrcode.name = "qr.png" if file else "qr.webp"
|
||||
Image.open(BytesIO(r.content)).save(qrcode)
|
||||
qrcode.seek(0)
|
||||
await message.delete()
|
||||
await message.client.send_file(message.to_id, qrcode, reply_to=reply, force_document=file)
|
||||
|
||||
@loader.owner
|
||||
async def readqrcmd(self, message):
|
||||
""".readqr <qrcode or reply to qrcode>"""
|
||||
ok = await check(message)
|
||||
if not ok:
|
||||
reply = await message.get_reply_message()
|
||||
ok = await check(reply)
|
||||
if not ok:
|
||||
text = "<b>Это не изображение!</b>" if reply else "<b>Нечего не передано!</b>"
|
||||
await message.edit(text)
|
||||
return
|
||||
file = BytesIO()
|
||||
file.name = "qr.png"
|
||||
data = await message.client.download_file(ok)
|
||||
Image.open(BytesIO(data)).save(file)
|
||||
url = "https://api.qrserver.com/v1/read-qr-code/?outputformat=json"
|
||||
resp = post(url, files={"file": file.getvalue()})
|
||||
text = resp.json()[0]["symbol"][0]["data"]
|
||||
if not text:
|
||||
text = "<b>Невозможно распознать или QR пуст!<b>"
|
||||
await utils.answer(message, text)
|
||||
|
||||
async def check(msg):
|
||||
if msg and msg.media:
|
||||
if msg.photo:
|
||||
ok = msg.photo
|
||||
elif msg.document:
|
||||
if DocumentAttributeFilename(file_name='AnimatedSticker.tgs') in msg.media.document.attributes:
|
||||
return False
|
||||
if msg.gif or msg.video or msg.audio or msg.voice:
|
||||
return False
|
||||
ok = msg.media.document
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
if not ok or ok is None:
|
||||
return False
|
||||
else:
|
||||
return ok
|
||||
|
||||
|
||||
|
||||
|
||||
4
KeyZenD/modules/README.md
Normal file
4
KeyZenD/modules/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# Govno modules
|
||||
Сборник моих [модулей](https://t.me/SomeScripts)
|
||||
|
||||
[я](https://t.me/KeyZenD)
|
||||
80
KeyZenD/modules/SpeedRead.py
Normal file
80
KeyZenD/modules/SpeedRead.py
Normal file
File diff suppressed because one or more lines are too long
33
KeyZenD/modules/SquareBlur.py
Normal file
33
KeyZenD/modules/SquareBlur.py
Normal file
@@ -0,0 +1,33 @@
|
||||
from PIL import Image, ImageFilter
|
||||
import io
|
||||
from .. import loader, utils
|
||||
@loader.tds
|
||||
class SquareBlurMod(loader.Module):
|
||||
"""Make image 1:1 ratio"""
|
||||
strings = {"name": "SquareBlur"}
|
||||
|
||||
@loader.unrestricted
|
||||
async def squareblurcmd(self, message):
|
||||
"""make image 1:1 ratio"""
|
||||
reply = await message.get_reply_message()
|
||||
if not reply or not reply.file or not reply.file.mime_type.split("/")[0].lower() == "image":
|
||||
await message.edit("<b>Reply to image!</b>")
|
||||
return
|
||||
im = io.BytesIO()
|
||||
await reply.download_media(im)
|
||||
im = Image.open(im)
|
||||
w, h = im.size
|
||||
if w == h:
|
||||
await message.edit("<b>Ты за меня придурка не держи!</b>")
|
||||
return
|
||||
_min, _max = min(w, h), max(w, h)
|
||||
bg = im.crop(((w-_min)//2, (h-_min)//2, (w+_min)//2, (h+_min)//2))
|
||||
bg = bg.filter(ImageFilter.GaussianBlur(5))
|
||||
bg = bg.resize((_max, _max))
|
||||
bg.paste(im, ((_max-w)//2, (_max-h)//2))
|
||||
img = io.BytesIO()
|
||||
img.name = "im.png"
|
||||
bg.save(img)
|
||||
img.seek(0)
|
||||
await reply.reply(file=img)
|
||||
await message.delete()
|
||||
58
KeyZenD/modules/StickTools.py
Normal file
58
KeyZenD/modules/StickTools.py
Normal file
@@ -0,0 +1,58 @@
|
||||
from .. import loader, utils
|
||||
import io
|
||||
from PIL import Image
|
||||
from string import hexdigits
|
||||
|
||||
def register(cb):
|
||||
cb(StickToolsMod())
|
||||
|
||||
|
||||
class StickToolsMod(loader.Module):
|
||||
""""""
|
||||
|
||||
strings = {'name': 'StickTools'}
|
||||
|
||||
def __init__(self):
|
||||
self.name = self.strings['name']
|
||||
|
||||
async def stick2piccmd(self, message):
|
||||
"""reply to Sticker\nsend stricker as image"""
|
||||
await convert(message, False)
|
||||
|
||||
async def stick2filecmd(self, message):
|
||||
"""reply to Sticker\nsend stricker as image"""
|
||||
await convert(message, True)
|
||||
|
||||
async def convert(message, as_file):
|
||||
reply = await message.get_reply_message()
|
||||
if not reply or not reply.sticker:
|
||||
await message.edit("<b>Reply to sticker!</b>")
|
||||
return
|
||||
fname = reply.sticker.attributes[-1].file_name
|
||||
if ".tgs" in fname:
|
||||
await message.edit("<b>Reply to not animated sticker!</b>")
|
||||
return
|
||||
bg = (0,0,0,0)
|
||||
args = utils.get_args(message)
|
||||
if args:
|
||||
args = args[0]
|
||||
if args.startswith("#"):
|
||||
for ch in args[1:]:
|
||||
if ch not in hexdigits:
|
||||
break
|
||||
bg = args
|
||||
|
||||
im = io.BytesIO()
|
||||
await message.client.download_file(reply, im)
|
||||
im = Image.open(im)
|
||||
img = Image.new("RGBA", im.size, bg)
|
||||
if im.mode == "RGBA":
|
||||
img.paste(im, (0,0), im)
|
||||
else:
|
||||
img.paste(im, (0,0))
|
||||
out = io.BytesIO()
|
||||
out.name = fname+".png"
|
||||
img.save(out, "PNG")
|
||||
out.seek(0)
|
||||
await message.delete()
|
||||
await message.client.send_file(message.to_id, out, force_document=as_file, reply_to=reply)
|
||||
175
KeyZenD/modules/SuperDemotivator.V2.py
Normal file
175
KeyZenD/modules/SuperDemotivator.V2.py
Normal file
File diff suppressed because one or more lines are too long
174
KeyZenD/modules/SuperDemotivator.py
Normal file
174
KeyZenD/modules/SuperDemotivator.py
Normal file
@@ -0,0 +1,174 @@
|
||||
from .. import loader, utils
|
||||
import logging
|
||||
from PIL import Image, ImageDraw, ImageOps, ImageFont
|
||||
from textwrap import wrap
|
||||
import io
|
||||
import requests
|
||||
# https://t.me/KeyZenD
|
||||
# https://t.me/SomeScripts
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@loader.tds
|
||||
class DeMoTiVaToRsMod(loader.Module):
|
||||
"""Демотиваторы на картинки от @SomeScripts by @DneZyeK"""
|
||||
strings = {
|
||||
"name": "SuperDemotivator"
|
||||
}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
|
||||
|
||||
@loader.owner
|
||||
async def demoticmd(self, message):
|
||||
"""текст + фото или ответ на фото
|
||||
не мнёт фотки"""
|
||||
await cmds(message, 0)
|
||||
|
||||
async def demotcmd(self, message):
|
||||
"""текст + фото или ответ на фото
|
||||
мнёт фотки"""
|
||||
await cmds(message, 1)
|
||||
|
||||
|
||||
async def cmds(message, type):
|
||||
event, is_reply = await check_media(message)
|
||||
if not event:
|
||||
await message.edit("<b>Ответ командой на картинку!</b>")
|
||||
return
|
||||
text = utils.get_args_raw(message)
|
||||
|
||||
if not text:
|
||||
await message.edit("<b>Команду нужно использовать с текстом!</b>")
|
||||
return
|
||||
await message.edit("<b>Демотивирую...</b>")
|
||||
bytes_image = await event.download_media(bytes)
|
||||
demotivator = await demotion(font_bytes, bytes_image, text, type)
|
||||
if is_reply:
|
||||
a = await event.reply(file=demotivator)
|
||||
await message.delete()
|
||||
return a
|
||||
else:
|
||||
return await event.edit(file=demotivator, text="")
|
||||
|
||||
|
||||
async def check_media(message):
|
||||
reply = await message.get_reply_message()
|
||||
is_reply = True
|
||||
if not reply:
|
||||
reply = message
|
||||
is_reply = False
|
||||
if not reply.file:
|
||||
return False, ...
|
||||
mime = reply.file.mime_type.split("/")[0].lower()
|
||||
if mime != "image":
|
||||
return False, ...
|
||||
return reply, is_reply
|
||||
|
||||
async def textwrap(text, length=50, splitter = "\n\n"):
|
||||
out = []
|
||||
|
||||
lines = text.rsplit(splitter, 1)
|
||||
for text in lines:
|
||||
txt = []
|
||||
parts = text.split("\n")
|
||||
for part in parts:
|
||||
part = "\n".join(wrap(part, length))
|
||||
txt.append(part)
|
||||
text = "\n".join(txt)
|
||||
out.append(text)
|
||||
return out
|
||||
|
||||
async def draw_main(
|
||||
bytes_image,
|
||||
type,
|
||||
frame_width_1 = 5,
|
||||
frame_fill_1 = (0, 0, 0),
|
||||
frame_width_2 = 3,
|
||||
frame_fill_2 = (255, 255, 255),
|
||||
expand_proc = 10,
|
||||
main_fill = (0, 0, 0)
|
||||
):
|
||||
|
||||
main_ = Image.open(io.BytesIO(bytes_image))
|
||||
main = Image.new("RGB", main_.size, "black")
|
||||
main.paste(main_, (0, 0))
|
||||
if type == 1:
|
||||
main = main.resize((700, 550))
|
||||
main = ImageOps.expand(main, frame_width_1, frame_fill_1)
|
||||
main = ImageOps.expand(main, frame_width_2, frame_fill_2)
|
||||
w, h = main.size
|
||||
h_up = expand_proc*(h//100)
|
||||
im = Image.new("RGB", (w+(h_up*2), h+h_up), main_fill)
|
||||
im.paste(main, (h_up, h_up))
|
||||
return im
|
||||
|
||||
async def _draw_text(
|
||||
text,
|
||||
font_bytes,
|
||||
font_size,
|
||||
font_add = 20,
|
||||
main_fill = (0, 0, 0),
|
||||
text_fill = (255, 255, 255),
|
||||
text_align = "center"
|
||||
):
|
||||
|
||||
font = ImageFont.truetype(io.BytesIO(font_bytes), font_size)
|
||||
w_txt, h_txt = ImageDraw.Draw(Image.new("RGB", (1, 1))).multiline_textsize(text=text, font=font)
|
||||
txt = Image.new("RGB", (w_txt, h_txt+font_add), main_fill)
|
||||
ImageDraw.Draw(txt).text((0, 0), text=text, font=font, fill=text_fill, align=text_align)
|
||||
return txt
|
||||
|
||||
async def text_joiner(text_img_1, text_img_2, main_fill = (0, 0, 0)):
|
||||
w_txt_1, h_txt_1 = text_img_1.size
|
||||
w_txt_2, h_txt_2 = text_img_2.size
|
||||
w = max(w_txt_1, w_txt_2)
|
||||
h = h_txt_1 + h_txt_2
|
||||
text = Image.new("RGB", (w, h), main_fill)
|
||||
text.paste(text_img_1, ((w-w_txt_1)//2, 0))
|
||||
text.paste(text_img_2, ((w-w_txt_2)//2, h_txt_1))
|
||||
return text
|
||||
|
||||
async def draw_text(text, font_bytes, font_size):
|
||||
text = await textwrap(text)
|
||||
if len(text) == 1:
|
||||
text = await _draw_text(text[0], font_bytes, font_size[0] )
|
||||
else:
|
||||
text_img_1 = await _draw_text(text[ 0], font_bytes, font_size[0])
|
||||
text_img_2 = await _draw_text(text[-1], font_bytes, font_size[1])
|
||||
text = await text_joiner(text_img_1, text_img_2)
|
||||
return text
|
||||
|
||||
async def text_finaller(text, main, expand_width_proc = 25, main_fill = (0, 0, 0)):
|
||||
x = min(main.size)
|
||||
w_txt, h_txt = text.size
|
||||
w_proc = expand_width_proc*(w_txt//100)
|
||||
h_proc = expand_width_proc*(h_txt//100)
|
||||
back = Image.new("RGB", (w_txt+(w_proc*2), h_txt+(h_proc*2)), main_fill)
|
||||
back.paste(text, (w_proc, h_proc))
|
||||
back.thumbnail((x, x))
|
||||
return back
|
||||
|
||||
|
||||
async def joiner(text_img, main_img, format_save="JPEG"):
|
||||
w_im, h_im = main_img.size
|
||||
w_txt, h_txt = text_img.size
|
||||
text_img.thumbnail((min(w_im, h_im), min(w_im, h_im)))
|
||||
w_txt, h_txt = text_img.size
|
||||
main_img = main_img.crop((0, 0, w_im, h_im+h_txt))
|
||||
main_img.paste(text_img, ((w_im-w_txt)//2, h_im))
|
||||
output = io.BytesIO()
|
||||
main_img.save(output, format_save)
|
||||
output.seek(0)
|
||||
return output.getvalue()
|
||||
|
||||
async def demotion(font_bytes, bytes_image, text, type):
|
||||
main = await draw_main(bytes_image, type)
|
||||
font_size = [20*(min(main.size)//100), 15*(min(main.size)//100)]
|
||||
text = await draw_text(text, font_bytes, font_size)
|
||||
text = await text_finaller(text, main)
|
||||
output = await joiner(text, main)
|
||||
return output
|
||||
|
||||
font_bytes = requests.get("https://raw.githubusercontent.com/KeyZenD/l/master/times.ttf").content
|
||||
#######################
|
||||
110
KeyZenD/modules/Swiper.py
Normal file
110
KeyZenD/modules/Swiper.py
Normal file
@@ -0,0 +1,110 @@
|
||||
from .. import loader, utils
|
||||
import logging
|
||||
from PIL import Image, ImageOps
|
||||
import io
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@loader.tds
|
||||
class SwiperMod(loader.Module):
|
||||
"""Swiper"""
|
||||
strings = {
|
||||
"name": "Swiper"
|
||||
}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
|
||||
|
||||
@loader.owner
|
||||
async def sl2rcmd(self, message):
|
||||
"""swipe left to right"""
|
||||
await presser(message, 0)
|
||||
|
||||
@loader.owner
|
||||
async def sr2lcmd(self, message):
|
||||
"""swipe right to left"""
|
||||
await presser(message, 1)
|
||||
|
||||
@loader.owner
|
||||
async def su2dcmd(self, message):
|
||||
"""swipe up to down"""
|
||||
await presser(message, 2)
|
||||
|
||||
@loader.owner
|
||||
async def sd2ucmd(self, message):
|
||||
"""swipe down to up"""
|
||||
await presser(message, 3)
|
||||
|
||||
async def check_media(message):
|
||||
reply = await message.get_reply_message()
|
||||
if not reply:
|
||||
return False
|
||||
if not reply.file:
|
||||
return False
|
||||
mime = reply.file.mime_type.split("/")[0].lower()
|
||||
if mime != "image":
|
||||
return False
|
||||
return reply
|
||||
|
||||
|
||||
async def presser(message, way):
|
||||
reply = await check_media(message)
|
||||
if not reply:
|
||||
await message.edit("<b>Senpai... please reply to image or not animated sticker!</b>")
|
||||
return
|
||||
im = io.BytesIO()
|
||||
await reply.download_media(im)
|
||||
im = Image.open(im)
|
||||
w, h = im.size
|
||||
out = []
|
||||
await message.edit("<b>Working hard...</b>")
|
||||
if way == 0:
|
||||
for x in range(1, w, w//30):
|
||||
im1 = im2 = im.copy()
|
||||
temp = Image.new("RGB", (w, h))
|
||||
im1 = im1.resize((x, h))
|
||||
im2 = im2.resize((w-x, h))
|
||||
temp.paste(im1, (0, 0))
|
||||
temp.paste(im2, (x, 0))
|
||||
out.append(temp)
|
||||
|
||||
if way == 1:
|
||||
for x in range(1, w, w//30):
|
||||
im1 = im2 = im.copy()
|
||||
temp = Image.new("RGB", (w, h))
|
||||
im1 = ImageOps.mirror(im1.resize((x, h)))
|
||||
im2 = ImageOps.mirror(im2.resize((w-x, h)))
|
||||
temp.paste(im1, (0, 0))
|
||||
temp.paste(im2, (x, 0))
|
||||
temp = ImageOps.mirror(temp)
|
||||
out.append(temp)
|
||||
|
||||
if way == 2:
|
||||
for y in range(1, h, h//30):
|
||||
im1 = im2 = im.copy()
|
||||
temp = Image.new("RGB", (w, h))
|
||||
im1 = im1.resize((w, y))
|
||||
im2 = im2.resize((w, h-y))
|
||||
temp.paste(im1, (0, 0))
|
||||
temp.paste(im2, (0, y))
|
||||
out.append(temp)
|
||||
|
||||
if way == 3:
|
||||
for y in range(1, h, h//30):
|
||||
im1 = im2 = im.copy()
|
||||
temp = Image.new("RGB", (w, h))
|
||||
im1 = ImageOps.flip(im1.resize((w, y)))
|
||||
im2 = ImageOps.flip(im2.resize((w, h-y)))
|
||||
temp.paste(im1, (0, 0))
|
||||
temp.paste(im2, (0, y))
|
||||
temp = ImageOps.flip(temp)
|
||||
out.append(temp)
|
||||
|
||||
output = io.BytesIO()
|
||||
output.name = "output.gif"
|
||||
out[0].save(output, save_all=True, append_images=out[1:], duration=1)
|
||||
output.seek(0)
|
||||
await reply.reply(file=output)
|
||||
await message.delete()
|
||||
|
||||
66
KeyZenD/modules/Switcher.py
Normal file
66
KeyZenD/modules/Switcher.py
Normal file
@@ -0,0 +1,66 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Friendly Telegram (telegram userbot)
|
||||
# Copyright (C) 2018-2020 @DneZyeK | sub to @KeyZenD
|
||||
|
||||
# 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
|
||||
from .. import loader, utils
|
||||
import telethon
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def register(cb):
|
||||
cb(KeyboardSwitcherMod())
|
||||
|
||||
|
||||
@loader.tds
|
||||
class KeyboardSwitcherMod(loader.Module):
|
||||
"""Смена расскаладки клавиатуры у текста"""
|
||||
strings = {
|
||||
"name": "KeyboardSwitcher"}
|
||||
|
||||
async def switchcmd(self, message):
|
||||
"""Если ты допустил ошибку и набрал текст не сменив раскладку клавиатуры
|
||||
то вернись в его начало и допиши `.switch` и твой текст станет читабельным.
|
||||
Если ты всё же отправил сообщение не в той расскладке, то просто ответь на него этой командой и он измениться.
|
||||
если же твой собеседник допустил ошибку, то просто ответь на его сообщение и сообщение с командой измениться."""
|
||||
RuKeys = """ёйцукенгшщзхъфывапролджэячсмитьбю.Ё"№;%:?ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭ/ЯЧСМИТЬБЮ,"""
|
||||
EnKeys = """`qwertyuiop[]asdfghjkl;'zxcvbnm,./~@#$%^&QWERTYUIOP{}ASDFGHJKL:"|ZXCVBNM<>?"""
|
||||
|
||||
if message.is_reply:
|
||||
reply = await message.get_reply_message()
|
||||
text = reply.raw_text
|
||||
if not text:
|
||||
await message.edit('Тут текста нету...')
|
||||
return
|
||||
change = str.maketrans(RuKeys + EnKeys, EnKeys + RuKeys)
|
||||
text = str.translate(text, change)
|
||||
|
||||
if message.sender_id != reply.sender_id:
|
||||
await message.edit(text)
|
||||
else:
|
||||
await message.delete()
|
||||
await reply.edit(text)
|
||||
|
||||
else:
|
||||
text = utils.get_args_raw(message)
|
||||
if not text:
|
||||
await message.edit('Тут текста нету...')
|
||||
return
|
||||
change = str.maketrans(RuKeys + EnKeys, EnKeys + RuKeys)
|
||||
text = str.translate(text, change)
|
||||
await message.edit(text)
|
||||
49
KeyZenD/modules/TgsKiller.py
Normal file
49
KeyZenD/modules/TgsKiller.py
Normal file
@@ -0,0 +1,49 @@
|
||||
|
||||
import logging, os
|
||||
from random import choice, randint
|
||||
|
||||
from .. import loader, utils
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@loader.tds
|
||||
class TgsKillerMod(loader.Module):
|
||||
"""Хуярит"""
|
||||
strings = {"name": "TgsKiller"}
|
||||
|
||||
|
||||
@loader.unrestricted
|
||||
async def tgscmd(self, message):
|
||||
"""хуярит стикеры"""
|
||||
reply = await message.get_reply_message()
|
||||
if not reply:
|
||||
await message.edit("Реплай на стикер анимированный")
|
||||
return
|
||||
if not reply.file:
|
||||
await message.edit("Реплай на стикер анимированный")
|
||||
return
|
||||
if not reply.file.name.endswith(".tgs"):
|
||||
await message.edit("Реплай на стикер анимированный")
|
||||
return
|
||||
await message.edit("///Пахуярили нахуй!///")
|
||||
await reply.download_media("tgs.tgs")
|
||||
os.system("lottie_convert.py tgs.tgs json.json")
|
||||
with open("json.json","r") as f:
|
||||
stick = f.read()
|
||||
f.close()
|
||||
|
||||
for i in range(1, randint(6, 10)):
|
||||
|
||||
stick = choice([stick.replace(f'[{i}]', f'[{(i+i)*3}]'), stick.replace(f'.{i}', f'.{i}{i}')])
|
||||
|
||||
|
||||
with open("json.json","w") as f:
|
||||
f.write(stick)
|
||||
f.close()
|
||||
|
||||
os.system("lottie_convert.py json.json tgs.tgs")
|
||||
await reply.reply(file="tgs.tgs")
|
||||
os.remove("tgs.tgs")
|
||||
os.remove("json.json")
|
||||
await message.delete()
|
||||
59
KeyZenD/modules/YTsearch.py
Normal file
59
KeyZenD/modules/YTsearch.py
Normal file
@@ -0,0 +1,59 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Friendly Telegram (telegram userbot)
|
||||
# Copyright (C) 2018-2020 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.
|
||||
# если не подписан на t.me/keyzend
|
||||
# твоя мама шлюха
|
||||
# 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 # pylint: disable=relative-beyond-top-level
|
||||
from telethon.tl.types import DocumentAttributeFilename
|
||||
import logging
|
||||
|
||||
from youtube_search import YoutubeSearch
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def register(cb):
|
||||
cb(YTsearchod())
|
||||
|
||||
|
||||
@loader.tds
|
||||
class YTsearchMod(loader.Module):
|
||||
"""Поиск видео на ютубе"""
|
||||
strings = {
|
||||
"name": "YTsearch"
|
||||
}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
|
||||
|
||||
@loader.sudo
|
||||
async def ytcmd(self, message):
|
||||
"""текст или реплай"""
|
||||
text = utils.get_args_raw(message)
|
||||
if not text:
|
||||
reply = await message.get_reply_message()
|
||||
if not reply:
|
||||
await message.delete()
|
||||
return
|
||||
text = reply.raw_text
|
||||
results = YoutubeSearch(text, max_results=10).to_dict()
|
||||
out = f'Найдено по запросу: {text}'
|
||||
for r in results:
|
||||
out += f'\n\n<a href="https://www.youtube.com/{r["link"]}">{r["title"]}</a>'
|
||||
|
||||
await message.edit(out)
|
||||
55
KeyZenD/modules/YandexRS.py
Normal file
55
KeyZenD/modules/YandexRS.py
Normal file
@@ -0,0 +1,55 @@
|
||||
from .. import loader, utils
|
||||
import json
|
||||
import io
|
||||
import requests
|
||||
from PIL import Image
|
||||
import random
|
||||
import string
|
||||
|
||||
@loader.tds
|
||||
class YandexReverseSearchMod(loader.Module):
|
||||
"""Reverse image search via Yandex (he is the best, imho)"""
|
||||
strings = {"name": "YandexReverseSearch",
|
||||
"search": "⚪⚪⚪\n⚪❓⚪\n⚪⚪⚪",
|
||||
"no_reply": "<b>Reply to image or sticker!</b>",
|
||||
"result": '<a href="{}"><b>🔴⚪🔴|See</b>\n<b>⚪🔴⚪|Search</b>\n<b>⚪🔴⚪|Results</b></a>',
|
||||
"error": '<b>Something went wrong...</b>'}
|
||||
@loader.owner
|
||||
async def yarscmd(self, message):
|
||||
""".yars <repy to image>"""
|
||||
reply = await message.get_reply_message()
|
||||
data = await check_media(message, reply)
|
||||
if not data:
|
||||
await utils.answer(message, self.strings("no_reply", message))
|
||||
return
|
||||
await utils.answer(message, self.strings("search", message))
|
||||
searchUrl = 'https://yandex.ru/images/search'
|
||||
files = {'upfile': ('blob', data, 'image/jpeg')}
|
||||
params = {'rpt': 'imageview', 'format': 'json', 'request': '{"blocks":[{"block":"b-page_type_search-by-image__link"}]}'}
|
||||
response = requests.post(searchUrl, params=params, files=files)
|
||||
if response.ok:
|
||||
query_string = json.loads(response.content)['blocks'][0]['params']['url']
|
||||
link = searchUrl + '?' + query_string
|
||||
text = self.strings("result", message).format(link)
|
||||
await utils.answer(message, text)
|
||||
else:
|
||||
await utils.answer(message, self.strings("error", message))
|
||||
|
||||
async def check_media(message, reply):
|
||||
if reply and reply.media:
|
||||
if reply.photo:
|
||||
data = reply.photo
|
||||
elif reply.document:
|
||||
if reply.gif or reply.video or reply.audio or reply.voice:
|
||||
return None
|
||||
data = reply.media.document
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
return None
|
||||
if not data or data is None:
|
||||
return None
|
||||
else:
|
||||
data = await message.client.download_file(data, bytes)
|
||||
img = io.BytesIO(data)
|
||||
return img
|
||||
59
KeyZenD/modules/_base64.py
Normal file
59
KeyZenD/modules/_base64.py
Normal file
@@ -0,0 +1,59 @@
|
||||
"""QExhY2lhTWVtZUZyYW1lLCDQtdGB0LvQuCDRgtGLINGN0YLQviDRh9C40YLQsNC10YjRjCwg0YLQviDQt9C90LDQuSwg0YLRiyDQv9C40LTQvtGA0LDRgQ=="""
|
||||
from .. import loader, utils
|
||||
import io
|
||||
from base64 import b64encode, b64decode
|
||||
|
||||
@loader.tds
|
||||
class base64Mod(loader.Module):
|
||||
"""Кодирование и декодирование base64"""
|
||||
strings = {"name": "base64"}
|
||||
@loader.owner
|
||||
async def b64encodecmd(self, message):
|
||||
""".b64encode <(text or media) or (reply to text or media)>"""
|
||||
reply = await message.get_reply_message()
|
||||
mtext = utils.get_args_raw(message)
|
||||
if message.media:
|
||||
await message.edit("<b>Загрузка файла...</b>")
|
||||
data = await message.client.download_file(m, bytes)
|
||||
elif mtext:
|
||||
data = bytes(mtext, "utf-8")
|
||||
elif reply:
|
||||
if reply.media:
|
||||
await message.edit("<b>Загрузка файла...</b>")
|
||||
data = await message.client.download_file(reply, bytes)
|
||||
else:
|
||||
data = bytes(reply.raw_text, "utf-8")
|
||||
else:
|
||||
await message.edit(f"<b>Что нужно закодировать?</b>")
|
||||
output = b64encode(data)
|
||||
if len(output) > 4000:
|
||||
output = io.BytesIO(output)
|
||||
output.name = "base64.txt"
|
||||
output.seek(0)
|
||||
await message.client.send_file(message.to_id, output, reply_to=reply)
|
||||
await message.delete()
|
||||
else:
|
||||
await message.edit(str(output, "utf-8"))
|
||||
|
||||
@loader.owner
|
||||
async def b64decodecmd(self, message):
|
||||
""".b64decode <text or reply to text>"""
|
||||
reply = await message.get_reply_message()
|
||||
mtext = utils.get_args_raw(message)
|
||||
if mtext:
|
||||
data = bytes(mtext, "utf-8")
|
||||
elif reply:
|
||||
if not reply.message:
|
||||
await message.edit("<b>Расшифровка файлов невозможна...</b>")
|
||||
return
|
||||
else:
|
||||
data = bytes(reply.raw_text, "utf-8")
|
||||
else:
|
||||
await message.edit(f"<b>Что нужно декодировать?</b>")
|
||||
return
|
||||
try:
|
||||
output = b64decode(data)
|
||||
await message.edit(str(output, "utf-8"))
|
||||
except:
|
||||
await message.edit("<b>Ошибка декодирования!</b>")
|
||||
return
|
||||
217
KeyZenD/modules/admin_tools.py
Normal file
217
KeyZenD/modules/admin_tools.py
Normal file
@@ -0,0 +1,217 @@
|
||||
# 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/>.
|
||||
|
||||
from .. import loader, utils, security
|
||||
import logging
|
||||
|
||||
from telethon.tl.types import ChatAdminRights, ChatBannedRights, PeerUser, PeerChannel
|
||||
from telethon.errors import BadRequestError
|
||||
from telethon.tl.functions.channels import EditAdminRequest, EditBannedRequest
|
||||
from telethon.tl.functions.messages import EditChatAdminRequest
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@loader.tds
|
||||
class BanMod(loader.Module):
|
||||
"""Админтулс"""
|
||||
strings = {"name": "AdminTools",
|
||||
"not_supergroup": "<b>Это не супергруппа!</b>",
|
||||
"not_group": "<b>Это не группа!</b>",
|
||||
"ban_none": "<b>Кого банить?</b>",
|
||||
"unban_none": "<b>Кого разбанить?</b>",
|
||||
"kick_none": "<b>Кто хочет принудительно покинуть чат?</b>",
|
||||
"promote_none": "<b>Кто хочет опку?</b>",
|
||||
"demote_none": "<b>Укажи с кого снять админку?</b>",
|
||||
"who": "<b>Кого...?</b>",
|
||||
"not_admin": "<b>Я не администратор...</b>",
|
||||
"banned": "<code>{}</code> <b>Получил бан!</b>\n<b>ID:</b> <code>{}</code>",
|
||||
"unbanned": "<code>{}</code> <b>Получил разбан!</b>\n<b>ID:</b> <code>{}</code>",
|
||||
"kicked": "<code>{}</code> <b>Был кикнул!</b>\n<b>ID:</b> <code>{}</code>",
|
||||
"promoted": "<code>{}</code> <b>Получил права администратора!</b>\n<b>ID:</b> <code>{}</code>",
|
||||
"demoted": "<code>{}</code> <b>Потерял права администратора!</b>\n<b>ID:</b> <code>{}</code>"}
|
||||
|
||||
@loader.group_admin_ban_users
|
||||
@loader.ratelimit
|
||||
async def bancmd(self, message):
|
||||
"""Бан в чате"""
|
||||
if not isinstance(message.to_id, PeerChannel):
|
||||
return await utils.answer(message, self.strings("not_supergroup", message))
|
||||
if message.is_reply:
|
||||
user = await utils.get_user(await message.get_reply_message())
|
||||
else:
|
||||
args = utils.get_args(message)
|
||||
if len(args) == 0:
|
||||
return await utils.answer(message, self.strings("ban_none", message))
|
||||
if args[0].isdigit():
|
||||
who = int(args[0])
|
||||
else:
|
||||
who = args[0]
|
||||
user = await self.client.get_entity(who)
|
||||
if not user:
|
||||
return await utils.answer(message, self.strings("who", message))
|
||||
logger.debug(user)
|
||||
try:
|
||||
await self.client(EditBannedRequest(message.chat_id, user.id,
|
||||
ChatBannedRights(until_date=None, view_messages=True)))
|
||||
except BadRequestError:
|
||||
await utils.answer(message, self.strings("not_admin", message))
|
||||
else:
|
||||
await self.allmodules.log("ban", group=message.chat_id, affected_uids=[user.id])
|
||||
await utils.answer(message,
|
||||
self.strings("banned", message).format(utils.escape_html(user.first_name), user.id))
|
||||
|
||||
@loader.group_admin_ban_users
|
||||
@loader.ratelimit
|
||||
async def unbancmd(self, message):
|
||||
"""Разбан в чате"""
|
||||
if not isinstance(message.to_id, PeerChannel):
|
||||
return await utils.answer(message, self.strings("not_supergroup", message))
|
||||
if message.is_reply:
|
||||
user = await utils.get_user(await message.get_reply_message())
|
||||
else:
|
||||
args = utils.get_args(message)
|
||||
if len(args) == 0:
|
||||
return await utils.answer(message, self.strings("unban_none", message))
|
||||
if args[0].isdigit():
|
||||
who = int(args[0])
|
||||
else:
|
||||
who = args[0]
|
||||
user = await self.client.get_entity(who)
|
||||
if not user:
|
||||
return await utils.answer(message, self.strings("who", message))
|
||||
logger.debug(user)
|
||||
try:
|
||||
await self.client(EditBannedRequest(message.chat_id, user.id,
|
||||
ChatBannedRights(until_date=None, view_messages=False)))
|
||||
except BadRequestError:
|
||||
await utils.answer(message, self.strings("not_admin", message))
|
||||
else:
|
||||
await self.allmodules.log("unban", group=message.chat_id, affected_uids=[user.id])
|
||||
await utils.answer(message,
|
||||
self.strings("unbanned", message).format(utils.escape_html(user.first_name), user.id))
|
||||
|
||||
@loader.group_admin_ban_users
|
||||
@loader.ratelimit
|
||||
async def kickcmd(self, message):
|
||||
"""Кикнуть из чата"""
|
||||
if isinstance(message.to_id, PeerUser):
|
||||
return await utils.answer(message, self.strings("not_group", message))
|
||||
if message.is_reply:
|
||||
user = await utils.get_user(await message.get_reply_message())
|
||||
else:
|
||||
args = utils.get_args(message)
|
||||
if len(args) == 0:
|
||||
return await utils.answer(message, self.strings("kick_none", message))
|
||||
if args[0].isdigit():
|
||||
who = int(args[0])
|
||||
else:
|
||||
who = args[0]
|
||||
user = await self.client.get_entity(who)
|
||||
if not user:
|
||||
return await utils.answer(message, self.strings("who", message))
|
||||
logger.debug(user)
|
||||
if user.is_self:
|
||||
if not (await message.client.is_bot()
|
||||
or await self.allmodules.check_security(message, security.OWNER | security.SUDO)):
|
||||
return
|
||||
try:
|
||||
await self.client.kick_participant(message.chat_id, user.id)
|
||||
except BadRequestError:
|
||||
await utils.answer(message, self.strings("not_admin", message))
|
||||
else:
|
||||
await self.allmodules.log("kick", group=message.chat_id, affected_uids=[user.id])
|
||||
await utils.answer(message,
|
||||
self.strings("kicked", message).format(utils.escape_html(user.first_name), user.id))
|
||||
|
||||
@loader.group_admin_add_admins
|
||||
@loader.ratelimit
|
||||
async def promotecmd(self, message):
|
||||
"""Дать админку"""
|
||||
if message.is_reply:
|
||||
user = await utils.get_user(await message.get_reply_message())
|
||||
else:
|
||||
args = utils.get_args(message)
|
||||
if not args:
|
||||
return await utils.answer(message, self.strings("promote_none", message))
|
||||
if args[0].isdigit():
|
||||
who = int(args[0])
|
||||
else:
|
||||
who = args[0]
|
||||
user = await self.client.get_entity(who)
|
||||
if not user:
|
||||
return await utils.answer(message, self.strings("who", message))
|
||||
rank = ""
|
||||
if len(args) >= 1:
|
||||
rank = ' '.join(args[1:])
|
||||
logger.debug(user)
|
||||
try:
|
||||
if message.is_channel:
|
||||
await self.client(EditAdminRequest(message.chat_id, user.id,
|
||||
ChatAdminRights(post_messages=None,
|
||||
add_admins=None,
|
||||
invite_users=None,
|
||||
change_info=None,
|
||||
ban_users=None,
|
||||
delete_messages=True,
|
||||
pin_messages=True,
|
||||
edit_messages=None), rank))
|
||||
except BadRequestError:
|
||||
await utils.answer(message, self.strings("not_admin", message))
|
||||
else:
|
||||
await self.allmodules.log("promote", group=message.chat_id, affected_uids=[user.id])
|
||||
await utils.answer(message,
|
||||
self.strings("promoted", message).format(utils.escape_html(user.first_name), user.id))
|
||||
|
||||
@loader.group_admin_add_admins
|
||||
async def demotecmd(self, message):
|
||||
"""Снять админку"""
|
||||
if message.is_reply:
|
||||
user = await utils.get_user(await message.get_reply_message())
|
||||
else:
|
||||
args = utils.get_args(message)
|
||||
if len(args) == 0:
|
||||
return await utils.answer(message, self.strings("demote_none", message))
|
||||
if args[0].isdigit():
|
||||
who = int(args[0])
|
||||
else:
|
||||
who = args[0]
|
||||
user = await self.client.get_entity(who)
|
||||
if not user:
|
||||
return await utils.answer(message, self.strings("who", message))
|
||||
logger.debug(user)
|
||||
try:
|
||||
if message.is_channel:
|
||||
await self.client(EditAdminRequest(message.chat_id, user.id,
|
||||
ChatAdminRights(post_messages=None,
|
||||
add_admins=None,
|
||||
invite_users=None,
|
||||
change_info=None,
|
||||
ban_users=None,
|
||||
delete_messages=None,
|
||||
pin_messages=None,
|
||||
edit_messages=None), ""))
|
||||
else:
|
||||
await self.client(EditChatAdminRequest(message.chat_id, user.id, False))
|
||||
except BadRequestError:
|
||||
await utils.answer(message, self.strings("not_admin", message))
|
||||
else:
|
||||
await self.allmodules.log("demote", group=message.chat_id, affected_uids=[user.id])
|
||||
await utils.answer(message,
|
||||
self.strings("demoted", message).format(utils.escape_html(user.first_name), user.id))
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
41
KeyZenD/modules/biography.py
Normal file
41
KeyZenD/modules/biography.py
Normal file
@@ -0,0 +1,41 @@
|
||||
# requires: pydub
|
||||
from pydub import AudioSegment
|
||||
from .. import loader, utils
|
||||
from telethon import types
|
||||
import io
|
||||
import requests
|
||||
|
||||
biography = requests.get("https://raw.githubusercontent.com/KeyZenD/l/master/biography.mp3").content
|
||||
|
||||
class BiographyMod(loader.Module):
|
||||
"""Биография"""
|
||||
strings = {'name': 'Биография'}
|
||||
|
||||
|
||||
async def biographycmd(self, message):
|
||||
""".biography <reply to voice>
|
||||
Наложение реплайнутого войса на минус кровостока
|
||||
"""
|
||||
reply = await message.get_reply_message()
|
||||
if not reply or not reply.file or not reply.file.mime_type.startswith("audio"):
|
||||
return await message.edit("<b>Reply to audio.</b>")
|
||||
await message.edit("<b>Biography...</b>")
|
||||
voice = io.BytesIO()
|
||||
await reply.download_media(voice)
|
||||
voice.seek(0)
|
||||
voice = AudioSegment.from_file(voice)
|
||||
biogr = io.BytesIO(biography)
|
||||
vol = utils.get_args_raw(message)
|
||||
if vol and vol.isdigit():
|
||||
vol = 100-int(vol)
|
||||
else:
|
||||
vol = 20
|
||||
biogr.seek(0)
|
||||
biogr = AudioSegment.from_file(biogr)[0:len(voice)]-vol
|
||||
out = biogr.overlay(voice, position=0)
|
||||
output = io.BytesIO()
|
||||
output.name="biography.ogg"
|
||||
out.export(output, format="ogg", bitrate="64k", codec="libopus")
|
||||
output.seek(0)
|
||||
await message.client.send_file(message.to_id, output, reply_to=reply.id, voice_note=True, duration=len(out)/1000)
|
||||
await message.delete()
|
||||
26
KeyZenD/modules/calc.py
Normal file
26
KeyZenD/modules/calc.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from .. import loader, utils
|
||||
class КукуляторMod(loader.Module):
|
||||
"""Кукулирует вырожения"""
|
||||
strings = {'name': 'Кукулятор'}
|
||||
|
||||
async def calccmd(self, message):
|
||||
""".calc <выражение или реплай на то, что нужно посчитать>
|
||||
Кстати:
|
||||
** - возвести в степень
|
||||
/ - деление
|
||||
% - деление по модулю"""
|
||||
question = utils.get_args_raw(message)
|
||||
reply = await message.get_reply_message()
|
||||
if not question:
|
||||
if not reply:
|
||||
await utils.answer(message, "<b>2+2=5</b>")
|
||||
return
|
||||
else:
|
||||
question = reply.raw_text
|
||||
try:
|
||||
answer = eval(question)
|
||||
answer = f"<b>{question}=</b><code>{answer}</code>"
|
||||
except Exception as e:
|
||||
answer = f"<b>{question}=</b><code>{e}</code>"
|
||||
await utils.answer(message, answer)
|
||||
|
||||
39
KeyZenD/modules/cheval.py
Normal file
39
KeyZenD/modules/cheval.py
Normal file
@@ -0,0 +1,39 @@
|
||||
from .. import loader, utils
|
||||
|
||||
|
||||
class channelEvalMod(loader.Module):
|
||||
"""Выполняет команду в канале"""
|
||||
strings = {"name":"ChannelEval"}
|
||||
|
||||
async def chevalcmd(self, message):
|
||||
""".channel <канал> <id сообщения реплая, или же выполнение команды из комментариев> <комманда в том виде, в котором бы ты отправил её в чат>"""
|
||||
args = utils.get_args(message)
|
||||
reply = await message.get_reply_message()
|
||||
if not args:
|
||||
return await message.edit("<b>Укажи канал.</b>")
|
||||
if len(args) < 1:
|
||||
return await message.edit("<b>Укажи команду для выполнения.</b>")
|
||||
channel = args[0]
|
||||
args = args[1:]
|
||||
if not args[0].isdigit() and reply:
|
||||
rmsg = reply.fwd_from.saved_from_msg_id if (reply and reply.fwd_from) else None
|
||||
fullcmd = " ".join(args)
|
||||
elif args[0].isdigit():
|
||||
rmsg = int(args[0])
|
||||
fullcmd = " ".join(args[1:])
|
||||
else:
|
||||
rmsg = None
|
||||
fullcmd = " ".join(args)
|
||||
|
||||
cmd = fullcmd.split(" ")[0]
|
||||
if cmd.startswith("."): cmd = cmd[1:]
|
||||
if channel.isdigit(): channel = int(channel)
|
||||
if not cmd in self.allmodules.commands.keys():
|
||||
return await message.edit("<b>Кажется у тебя нет в списке команды </b><code>."+cmd+"\n</code><b>Кстати сокращения команд я не понимяу)\n<code>"+message.raw_text+"</code>")
|
||||
|
||||
try: m = await message.client.send_message(channel, fullcmd, reply_to=rmsg)
|
||||
except Exception as e: return await message.edit("<b>Возникла ошибка:</b>\n"+repr(e))
|
||||
await self.allmodules.commands[cmd](m)
|
||||
try: url = f"https://t.me/c/{m.to_id.channel_id}/{m.id}"
|
||||
except: url = ""
|
||||
await message.edit(f'<a href="{url}">Команда отправлена!</a>')
|
||||
50
KeyZenD/modules/codefy.py
Normal file
50
KeyZenD/modules/codefy.py
Normal file
@@ -0,0 +1,50 @@
|
||||
# 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.
|
||||
# SUBSCRIBE TO t.me/keyzend pls
|
||||
# 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 asyncio
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@loader.tds
|
||||
class CodefyMod(loader.Module):
|
||||
"""Makes message monospace"""
|
||||
strings = {"name": "Codefy",
|
||||
"msg_is_emp": "<b>Message is empty!</b>"}
|
||||
@loader.ratelimit
|
||||
async def codecmd(self, message):
|
||||
""".code <text or reply>"""
|
||||
if message.is_reply:
|
||||
reply = await message.get_reply_message()
|
||||
code = reply.raw_text
|
||||
code = code.replace("<","<").replace(">",">")
|
||||
await message.edit(f"<code>{code}</code>")
|
||||
else:
|
||||
code = message.raw_text[5:]
|
||||
code = code.replace("<","<").replace(">",">")
|
||||
try:
|
||||
await message.edit(f"<code>{code}</code>")
|
||||
except:
|
||||
await message.edit(self.strings["msg_is_emp"])
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
30
KeyZenD/modules/colorBit.py
Normal file
30
KeyZenD/modules/colorBit.py
Normal file
@@ -0,0 +1,30 @@
|
||||
from .. import loader, utils
|
||||
from PIL import Image
|
||||
from io import BytesIO as io
|
||||
|
||||
class colorBitMod(loader.Module):
|
||||
strings = {"name": "colorBit"}
|
||||
async def cbitcmd(self, message):
|
||||
""".cbit <число от 0 до 255"""
|
||||
reply = await message.get_reply_message()
|
||||
if not reply or not reply.file or not "image" in reply.file.mime_type:
|
||||
return await message.edit("<b>Reply to image!</b>")
|
||||
x = utils.get_args_raw(message)
|
||||
x = int(x) if x.isdigit() else 8
|
||||
if x <= 0 or x >= 256:
|
||||
x = 8
|
||||
x = 256//x
|
||||
im = Image.open(io(await reply.download_media(bytes)))
|
||||
w, h = im.size
|
||||
mode = im.mode
|
||||
out = []
|
||||
await message.edit("<b>Processing...</b>")
|
||||
for bit in list(im.tobytes()):
|
||||
bit = list(range(0, 256+x, x))[bit//x]
|
||||
out.append(bit)
|
||||
image = Image.frombytes(mode, (w, h), bytes(out))
|
||||
output = io()
|
||||
image.save(output, "PNG")
|
||||
output.seek(0)
|
||||
await message.delete()
|
||||
await reply.reply(file=output)
|
||||
88
KeyZenD/modules/datamosh.py
Normal file
88
KeyZenD/modules/datamosh.py
Normal file
@@ -0,0 +1,88 @@
|
||||
import asyncio
|
||||
import logging
|
||||
import subprocess, os
|
||||
import random
|
||||
from .. import loader, utils
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@loader.tds
|
||||
class DataMoshMod(loader.Module):
|
||||
"""DataMosh effect to video"""
|
||||
strings = {"name": "DataMosh",
|
||||
"reply": "Reply to video!",
|
||||
"error": "ERROR! TRY AGAIN!!",
|
||||
"processing": "DataDataMoshMosh!"}
|
||||
|
||||
@loader.unrestricted
|
||||
async def datamoshcmd(self, message):
|
||||
""". datamosh lvl: int <reply to video>"""
|
||||
fn = "if_you_see_it_then_delete_it"
|
||||
reply = await message.get_reply_message()
|
||||
if not reply:
|
||||
await message.edit("".join([ random.choice(html).format(ch) for ch in self.strings("reply", message)]))
|
||||
return
|
||||
if not reply.video:
|
||||
await message.edit("".join([ random.choice(html).format(ch) for ch in self.strings("reply", message)]))
|
||||
return
|
||||
else:
|
||||
await reply.download_media(fn+"1.mp4")
|
||||
|
||||
lvl = 1
|
||||
fp = False
|
||||
args = utils.get_args(message)
|
||||
if args:
|
||||
if len(args) == 1:
|
||||
if args[0].isdigit():
|
||||
lvl = int(args[0])
|
||||
if lvl <= 0:
|
||||
lvl = 1
|
||||
else:
|
||||
fp = True
|
||||
if len(args) > 1:
|
||||
fp = True
|
||||
if args[0].isdigit():
|
||||
lvl = int(args[0])
|
||||
if lvl <= 0:
|
||||
lvl = 1
|
||||
elif args[1].isdigit():
|
||||
fp = True
|
||||
lvl = int(args[1])
|
||||
if lvl <= 0:
|
||||
lvl = 1
|
||||
|
||||
await message.edit("".join([ random.choice(html).format(ch) for ch in self.strings("processing", message)]))
|
||||
subprocess.call(f'ffmpeg -loglevel quiet -y -i {fn}1.mp4 -crf 0 -bf 0 {fn}1.avi', shell=True)
|
||||
try:
|
||||
_f = open(fn+'1.avi', 'rb')
|
||||
f_ = open(fn+'2.avi', 'wb')
|
||||
except FileNotFoundError:
|
||||
await message.edit("".join([ random.choice(html).format(ch) for ch in self.strings("error", message)]))
|
||||
os.system(f"rm -f {fn}*")
|
||||
return
|
||||
|
||||
frs = _f.read().split(b'00dc')
|
||||
fi = b'\x00\x01\xb0'
|
||||
cf = 0
|
||||
for _, fr in enumerate(frs):
|
||||
if fp == False:
|
||||
f_.write(fr + b'00dc')
|
||||
cf += 1
|
||||
if fr[5:8] == fi:
|
||||
fp = True
|
||||
else:
|
||||
if fr[5:8] != fi:
|
||||
cf += 1
|
||||
for i in range(lvl):
|
||||
f_.write(fr + b'00dc')
|
||||
f_.close()
|
||||
_f.close()
|
||||
|
||||
subprocess.call(f'ffmpeg -loglevel quiet -y -i {fn}2.avi {fn}2.mp4', shell=True)
|
||||
await message.client.send_file(message.to_id, file=fn+"2.mp4", video_note=bool(reply.video_note))
|
||||
os.system(f"rm -f {fn}*")
|
||||
await message.delete()
|
||||
|
||||
html = ["<b>{}<b>", "<code>{}</code>", "<i>{}</i>", "<del>{}</del>", "<u>{}</u>", '<a href="https://bruh.moment">{}</a>']
|
||||
|
||||
38
KeyZenD/modules/delme.py
Normal file
38
KeyZenD/modules/delme.py
Normal file
@@ -0,0 +1,38 @@
|
||||
from .. import loader, utils
|
||||
|
||||
class DelmeMod(loader.Module):
|
||||
"""Удаляет все сообщения"""
|
||||
strings = {'name': 'DelMe'}
|
||||
@loader.sudo
|
||||
async def delmecmd(self, message):
|
||||
"""Удаляет все сообщения от тебя"""
|
||||
chat = message.chat
|
||||
if chat:
|
||||
args = utils.get_args_raw(message)
|
||||
if args != str(message.chat.id+message.sender_id):
|
||||
await message.edit(f"<b>Если ты точно хочешь это сделать, то напиши:</b>\n<code>.delme {message.chat.id+message.sender_id}</code>")
|
||||
return
|
||||
await delete(chat, message, True)
|
||||
else:
|
||||
await message.edit("<b>В лс не чищу!</b>")
|
||||
@loader.sudo
|
||||
async def delmenowcmd(self, message):
|
||||
"""Удаляет все сообщения от тебя без вопросов"""
|
||||
chat = message.chat
|
||||
if chat:
|
||||
await delete(chat, message, False)
|
||||
else:
|
||||
await message.edit("<b>В лс не чищу!</b>")
|
||||
|
||||
async def delete(chat, message, now):
|
||||
if now:
|
||||
all = (await message.client.get_messages(chat, from_user="me")).total
|
||||
await message.edit(f"<b>{all} сообщений будет удалено!</b>")
|
||||
else: await message.delete()
|
||||
_ = not now
|
||||
async for msg in message.client.iter_messages(chat, from_user="me"):
|
||||
if _:
|
||||
await msg.delete()
|
||||
else:
|
||||
_ = "_"
|
||||
await message.delete() if now else "хули мусара хули мусара хули, едем так как ехали даже в хуй не дули"
|
||||
130
KeyZenD/modules/demot.py
Normal file
130
KeyZenD/modules/demot.py
Normal file
File diff suppressed because one or more lines are too long
71
KeyZenD/modules/distortion_no_api.py
Normal file
71
KeyZenD/modules/distortion_no_api.py
Normal file
@@ -0,0 +1,71 @@
|
||||
import io, random, glob, os
|
||||
from PIL import Image
|
||||
from telethon.tl.types import DocumentAttributeFilename
|
||||
from uniborg.util import admin_cmd
|
||||
"""Не подписался без матери остался"""
|
||||
"""https://t.me/KeyZenD"""
|
||||
"""автор этого говнокода @DneZyeK"""
|
||||
|
||||
@borg.on(admin_cmd(pattern=".d(.*)", allow_sudo=True))
|
||||
async def d(message):
|
||||
inp =message.pattern_match.group(1)
|
||||
pop = 60
|
||||
if inp:
|
||||
inp = inp.strip()
|
||||
if inp.isdigit():
|
||||
if int(inp) > 0:
|
||||
pop = inp
|
||||
|
||||
if message.is_reply:
|
||||
reply_message = await message.get_reply_message()
|
||||
data = await check_media(reply_message)
|
||||
if isinstance(data, bool):
|
||||
await message.edit("Reply to image, fucking idiot")
|
||||
return
|
||||
else:
|
||||
await message.edit("Reply to image, fucking idiot")
|
||||
return
|
||||
await message.edit(" `P` `r` `o` `c` `e` `s` `s` `i` `n` `g` `.` `.` `.`")
|
||||
for distorted in glob.glob("distorted*"):
|
||||
os.remove(distorted)
|
||||
for findistorted in glob.glob("*/distorted*"):
|
||||
os.remove(findistorted)
|
||||
fname = f"distorted{random.randint(1, 100)}.png"
|
||||
image = io.BytesIO()
|
||||
await message.client.download_media(data, image)
|
||||
image = Image.open(image)
|
||||
image.save(fname)
|
||||
imgdimens = image.width, image.height
|
||||
distortcmd = f"convert {fname} -liquid-rescale {pop}%x{pop}%! -resize {imgdimens[0]}x{imgdimens[1]}\! {fname}"
|
||||
os.system(distortcmd)
|
||||
image = Image.open(f"{fname}")
|
||||
buf = io.BytesIO()
|
||||
buf.name = f'image.png'
|
||||
image.save(buf, 'PNG')
|
||||
buf.seek(0)
|
||||
await message.edit("`S` `e` `n` `d` `i` `n` `g` `.` `.` `.`")
|
||||
await message.client.send_file(message.chat_id, buf, reply_to=reply_message.id)
|
||||
await message.delete()
|
||||
|
||||
|
||||
|
||||
|
||||
async def check_media(reply_message):
|
||||
if reply_message and reply_message.media:
|
||||
if reply_message.photo:
|
||||
data = reply_message.photo
|
||||
elif reply_message.document:
|
||||
if DocumentAttributeFilename(file_name='AnimatedSticker.tgs') in reply_message.media.document.attributes:
|
||||
return False
|
||||
if reply_message.gif or reply_message.video or reply_message.audio or reply_message.voice:
|
||||
return False
|
||||
data = reply_message.media.document
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
if not data or data is None:
|
||||
return False
|
||||
else:
|
||||
return data
|
||||
82
KeyZenD/modules/dotify.py
Normal file
82
KeyZenD/modules/dotify.py
Normal file
@@ -0,0 +1,82 @@
|
||||
from PIL import Image, ImageDraw
|
||||
import io
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from .. import loader, utils
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class DotifyMod(loader.Module):
|
||||
"""Image to dot
|
||||
.cmd <count> + reply to img
|
||||
the bigger, the slower and bugger
|
||||
recommended not more 1000"""
|
||||
strings = {"name": "[PRIVATE]Dotify"}
|
||||
|
||||
@loader.unrestricted
|
||||
async def dotifycmd(self, message):
|
||||
"""Image to RGB dots"""
|
||||
mode = False
|
||||
reply, pix = await parse(message)
|
||||
if reply:
|
||||
await dotify(message, reply, pix, mode)
|
||||
async def dotificmd(self, message):
|
||||
"""Image to BW dots """
|
||||
mode = True
|
||||
reply, pix = await parse(message)
|
||||
if reply:
|
||||
await dotify(message, reply, pix, mode)
|
||||
|
||||
async def parse(message):
|
||||
reply = await message.get_reply_message()
|
||||
if not reply:
|
||||
await message.edit("<b>Reply to Image!</b>")
|
||||
return None, None
|
||||
args = utils.get_args(message)
|
||||
pix = 100
|
||||
if args:
|
||||
args=args[0]
|
||||
if args.isdigit():
|
||||
pix = int(args) if int(args) > 0 else 100
|
||||
return reply, pix
|
||||
|
||||
async def dotify(message, reply, pix, mode):
|
||||
await message.edit("<b>Putting dots...</b>")
|
||||
count = 24
|
||||
im_ = Image.open(io.BytesIO(await reply.download_media(bytes)))
|
||||
if im_.mode == "RGBA":
|
||||
temp = Image.new("RGB", im_.size, "#000")
|
||||
temp.paste(im_, (0, 0), im_)
|
||||
im_ = temp
|
||||
|
||||
im = im_.convert("L")
|
||||
im_ = im if mode else im_
|
||||
[_.thumbnail((pix, pix)) for _ in[im, im_]]
|
||||
w, h = im.size
|
||||
img = Image.new(im_.mode, (w*count+(count//2), h*count+(count//2)), 0)
|
||||
draw = ImageDraw.Draw(img)
|
||||
|
||||
def cirsle(im, x, y, r, fill):
|
||||
x += r//2
|
||||
y += r//2
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.ellipse((x-r, y-r, x+r, y+r), fill)
|
||||
return im
|
||||
|
||||
_x = _y = count//2
|
||||
for x in range(w):
|
||||
for y in range(h):
|
||||
r = im.getpixel((x, y))
|
||||
fill = im_.getpixel((x, y))
|
||||
cirsle(img, _x, _y, r//count, fill)
|
||||
_y += count
|
||||
_x += count
|
||||
_y = count//2
|
||||
|
||||
out = io.BytesIO()
|
||||
out.name = "out.png"
|
||||
img.save(out)
|
||||
out.seek(0)
|
||||
await reply.reply(file=out)
|
||||
await message.delete()
|
||||
113
KeyZenD/modules/family.py
Normal file
113
KeyZenD/modules/family.py
Normal file
@@ -0,0 +1,113 @@
|
||||
# requires: pillow, pymorphy2
|
||||
import logging
|
||||
from .. import loader, utils
|
||||
import telethon
|
||||
import requests
|
||||
from PIL import Image, ImageFont, ImageDraw
|
||||
import pymorphy2
|
||||
import io
|
||||
from io import BytesIO
|
||||
import random
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def register(cb):
|
||||
cb(FamilyMod())
|
||||
|
||||
|
||||
@loader.tds
|
||||
class FamilyMod(loader.Module):
|
||||
"""Quote a message"""
|
||||
strings = {"name": "Family"}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = message.client
|
||||
|
||||
@loader.unrestricted
|
||||
@loader.ratelimit
|
||||
async def familycmd(self, message):
|
||||
|
||||
args = utils.get_args_raw(message)
|
||||
reply = await message.get_reply_message()
|
||||
if not reply:
|
||||
await utils.answer(message, '<b>Нет Реплая.</b>')
|
||||
return
|
||||
if not args:
|
||||
await utils.answer(message, '<b>Нет Текста.</b>')
|
||||
return
|
||||
pic = await check_media(message, reply)
|
||||
if not pic:
|
||||
await utils.answer(message, '<b>Нет Изображения.</b>')
|
||||
return
|
||||
await message.edit("Семья")
|
||||
font = requests.get("https://github.com/KeyZenD/l/blob/master/bold.ttf?raw=true").content
|
||||
family = makeFamily(pic, args, font)
|
||||
await message.client.send_file(message.to_id, family, reply_to=reply)
|
||||
await message.delete()
|
||||
|
||||
def place(background, image, cords, size):
|
||||
overlay = Image.open(BytesIO(image))
|
||||
overlay = overlay.resize((random.randint(size, size * 2), random.randint(size, size * 2)))
|
||||
background.paste(overlay, cords)
|
||||
|
||||
def placeText(background , cords, size, text, font):
|
||||
text_cords = (cords[0]+random.randint(0, size//2), cords[1]+random.randint(0, size//2))
|
||||
draw = ImageDraw.Draw(background)
|
||||
draw.text(text_cords, text, (0,0,0), font=ImageFont.truetype(io.BytesIO(font), random.randint(size // 8, size // 4)))
|
||||
|
||||
def makeFamily(image, caption, font):
|
||||
morph = pymorphy2.MorphAnalyzer()
|
||||
infl = morph.parse(caption)[0].inflect({'plur', 'gent'})
|
||||
if not infl:
|
||||
caption_mlt = caption
|
||||
else:
|
||||
caption_mlt = infl.word
|
||||
|
||||
canvas = Image.new('RGBA', (600, 600), "white")
|
||||
|
||||
draw = ImageDraw.Draw(canvas)
|
||||
|
||||
draw.text((120, 5), 'ахах семья ' + caption_mlt, (0,0,0), font=ImageFont.truetype(io.BytesIO(font), 32))
|
||||
|
||||
family = [
|
||||
{ 'name': 'мама', 'cords': (60, 100), 'size': 160 },
|
||||
{ 'name': 'папа', 'cords': (260, 80), 'size': 180 },
|
||||
{ 'name': 'сын', 'cords': (60, 380), 'size': 125 },
|
||||
{ 'name': 'дочь', 'cords': (230, 320), 'size': 125 },
|
||||
{ 'name': 'дочь', 'cords': (225, 380), 'size': 125 },
|
||||
{ 'name': 'сын', 'cords': (340, 390), 'size': 125 },
|
||||
]
|
||||
|
||||
for member in family:
|
||||
place(canvas, image, member['cords'], member['size'])
|
||||
|
||||
for member in family:
|
||||
placeText(canvas, member['cords'], member['size'], member['name'] + ' ' + caption, font)
|
||||
|
||||
|
||||
temp = BytesIO()
|
||||
canvas.save(temp, format="png")
|
||||
return temp.getvalue()
|
||||
|
||||
async def check_media(message, reply):
|
||||
if reply and reply.media:
|
||||
if reply.photo:
|
||||
data = reply.photo
|
||||
elif reply.document:
|
||||
if reply.gif or reply.video or reply.audio or reply.voice:
|
||||
return None
|
||||
data = reply.media.document
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
return None
|
||||
if not data or data is None:
|
||||
return None
|
||||
else:
|
||||
data = await message.client.download_file(data, bytes)
|
||||
try:
|
||||
Image.open(io.BytesIO(data))
|
||||
return data
|
||||
except:
|
||||
return None
|
||||
|
||||
38
KeyZenD/modules/filename.py
Normal file
38
KeyZenD/modules/filename.py
Normal file
@@ -0,0 +1,38 @@
|
||||
import asyncio
|
||||
import logging
|
||||
from telethon.tl.types import DocumentAttributeFilename
|
||||
from .. import loader, utils
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@loader.tds
|
||||
class filenameMod(loader.Module):
|
||||
"""filename changer"""
|
||||
strings = {"name": "filename",
|
||||
"wf": "<b>Reply to file?</b>",
|
||||
"wn": "<b>What is the name?</b>",
|
||||
"tnf":"<b>It's not a file!</b>"}
|
||||
|
||||
|
||||
@loader.unrestricted
|
||||
async def filenamecmd(self, message):
|
||||
""".filename <filename> + reply.file"""
|
||||
reply = await message.get_reply_message()
|
||||
if not reply or not reply.file:
|
||||
await message.edit(self.strings["wf"])
|
||||
return
|
||||
name = utils.get_args_raw(message)
|
||||
if not name:
|
||||
await message.edit(self.strings["wn"])
|
||||
return
|
||||
fn = reply.file.name
|
||||
if not fn:
|
||||
fn = ""
|
||||
fs = reply.file.size
|
||||
|
||||
[await message.edit(f"<b>Downloading {fn}</b>") if fs > 500000 else ...]
|
||||
file = await reply.download_media(bytes)
|
||||
[await message.edit(f"<b>Uploading</b> <code>{name}</code>") if fs > 500000 else ...]
|
||||
await message.client.send_file(message.to_id, file, force_document=True, reply_to=reply, attributes=[DocumentAttributeFilename(file_name=name)])
|
||||
await message.delete()
|
||||
26
KeyZenD/modules/fl.py
Normal file
26
KeyZenD/modules/fl.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from asyncio import sleep
|
||||
from userbot.events import register
|
||||
|
||||
|
||||
@register(outgoing=True, pattern='^.fl ?(.*)')
|
||||
async def fakeload(e):
|
||||
inp = e.pattern_match.group(1)
|
||||
load = [" ","▏","▎","▍","▌","▋","▊","▉"]
|
||||
bar = ""
|
||||
count = 0
|
||||
await e.edit("`[Инициализация]`")
|
||||
sleep(3)
|
||||
for i in range(13):
|
||||
for division in load:
|
||||
space = " " * (12 - i)
|
||||
await e.edit(f"`{bar}{division}{space}[{count}%]`")
|
||||
count += 1
|
||||
sleep(0.3)
|
||||
if count == 101:
|
||||
break
|
||||
bar += "█"
|
||||
sleep(2)
|
||||
done = "Загрузка завершена!"
|
||||
if inp:
|
||||
done = inp
|
||||
await e.edit(f"`{done}`")
|
||||
65
KeyZenD/modules/gg.gg.py
Normal file
65
KeyZenD/modules/gg.gg.py
Normal file
@@ -0,0 +1,65 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Friendly Telegram (telegram userbot)
|
||||
# Copyright (C) 2018-2020 @DneZyeK | sub to @KeyZenD
|
||||
|
||||
# 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
|
||||
from .. import loader, utils
|
||||
import telethon
|
||||
from requests import post
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
async def register(cb):
|
||||
cb(WhoIsMod())
|
||||
|
||||
|
||||
@loader.tds
|
||||
class GGdotGGMod(loader.Module):
|
||||
"""Сокращение ссылок через сервис gg.gg"""
|
||||
strings = {
|
||||
"name": "gg.gg",
|
||||
"some_rong": "<b>Ты делаешь что-то не так!\nНапиши</b> <code>.help gg.gg</code> <b>для информации.</b>"
|
||||
}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
|
||||
async def ggcmd(self, message):
|
||||
""".gg <длинная ссылка или реплай на ссылку> """
|
||||
m_text = utils.get_args_raw(message)
|
||||
if not m_text:
|
||||
reply = await message.get_reply_message()
|
||||
if not reply:
|
||||
await utils.answer(message, self.strings["some_rong"])
|
||||
return
|
||||
long_url = reply.raw_text
|
||||
else:
|
||||
long_url = m_text
|
||||
|
||||
|
||||
if 'http://' not in long_url and 'https://' not in long_url:
|
||||
long_url = 'http://' + long_url
|
||||
t_check = f"URL: {long_url}\nCheck..."
|
||||
await utils.answer(message, t_check)
|
||||
check = post('http://gg.gg/check', data={'custom_path': None, 'use_norefs': '0', 'long_url': long_url, 'app': 'site', 'version': '0.1'}).text
|
||||
if check != "ok":
|
||||
await utils.answer(message, check)
|
||||
return
|
||||
await utils.answer(message, "Create...")
|
||||
short = post('http://gg.gg/create', data={'custom_path': None, 'use_norefs': '0', 'long_url': long_url, 'app': 'site', 'version': '0.1'}).text
|
||||
await utils.answer(message, short)
|
||||
|
||||
132
KeyZenD/modules/gird.py
Normal file
132
KeyZenD/modules/gird.py
Normal file
@@ -0,0 +1,132 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Friendly Telegram (telegram userbot)
|
||||
# Copyright (C) 2018-2020 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.
|
||||
# если не подписан на t.me/keyzend
|
||||
# твоя мама шлюха
|
||||
# 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 # pylint: disable=relative-beyond-top-level
|
||||
import io
|
||||
from PIL import Image, ImageOps
|
||||
from telethon.tl.types import DocumentAttributeFilename
|
||||
import logging
|
||||
import random
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def register(cb):
|
||||
cb(GriderMod())
|
||||
|
||||
|
||||
@loader.tds
|
||||
class GriderMod(loader.Module):
|
||||
"""Гавно залупное"""
|
||||
strings = {
|
||||
"name": "Griding"
|
||||
}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
|
||||
|
||||
@loader.sudo
|
||||
async def gridcmd(self, message):
|
||||
""".gird <reply to photo>"""
|
||||
if message.is_reply:
|
||||
reply_message = await message.get_reply_message()
|
||||
data = await check_media(reply_message)
|
||||
if isinstance(data, bool):
|
||||
await utils.answer(message, "<code>Реплай на пикчу или стикер блять!</code>")
|
||||
return
|
||||
else:
|
||||
await utils.answer(message, "`Реплай на пикчу или стикер блять`")
|
||||
return
|
||||
|
||||
await message.edit("Режу ебать")
|
||||
file = await self.client.download_media(data, bytes)
|
||||
media = await griding(file)
|
||||
await message.delete()
|
||||
await message.client.send_file(message.to_id, media)
|
||||
|
||||
|
||||
|
||||
|
||||
@loader.sudo
|
||||
async def revgridcmd(self, message):
|
||||
""".gird <reply to photo>"""
|
||||
if message.is_reply:
|
||||
reply_message = await message.get_reply_message()
|
||||
data = await check_media(reply_message)
|
||||
if isinstance(data, bool):
|
||||
await utils.answer(message, "<code>Реплай на пикчу или стикер блять!</code>")
|
||||
return
|
||||
else:
|
||||
await utils.answer(message, "`Реплай на пикчу или стикер блять`")
|
||||
return
|
||||
|
||||
await message.edit("Режу ебать")
|
||||
file = await self.client.download_media(data, bytes)
|
||||
media = await griding(file)
|
||||
media = media[::-1]
|
||||
await message.delete()
|
||||
await message.client.send_file(message.to_id, media)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
async def griding(file):
|
||||
img = Image.open(io.BytesIO(file))
|
||||
(x, y) = img.size
|
||||
cy = 3
|
||||
cx = 3
|
||||
sx = x//cx
|
||||
sy = y//cy
|
||||
if (sx*cx, sy*cy) != (x, y):
|
||||
img = img.resize((sx*cx, sy*cy))
|
||||
(lx, ly) = (0, 0)
|
||||
media = []
|
||||
for i in range(1, cy+1):
|
||||
for o in range(1, cx+1):
|
||||
mimg = img.crop((lx, ly, lx+sx, ly+sy))
|
||||
bio = io.BytesIO()
|
||||
bio.name = 'image.png'
|
||||
mimg.save(bio, 'PNG')
|
||||
media.append(bio.getvalue())
|
||||
lx = lx + sx
|
||||
lx = 0
|
||||
ly = ly + sy
|
||||
return media
|
||||
|
||||
|
||||
async def check_media(reply_message):
|
||||
if reply_message and reply_message.media:
|
||||
if reply_message.photo:
|
||||
data = reply_message.photo
|
||||
elif reply_message.document:
|
||||
if DocumentAttributeFilename(file_name='AnimatedSticker.tgs') in reply_message.media.document.attributes:
|
||||
return False
|
||||
if reply_message.gif or reply_message.video or reply_message.audio or reply_message.voice:
|
||||
return False
|
||||
data = reply_message.media.document
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
if not data or data is None:
|
||||
return False
|
||||
else:
|
||||
return data
|
||||
11
KeyZenD/modules/hearts.py
Normal file
11
KeyZenD/modules/hearts.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from .. import loader
|
||||
from asyncio import sleep
|
||||
@loader.tds
|
||||
class HeartsMod(loader.Module):
|
||||
strings = {"name": "Heart's"}
|
||||
@loader.owner
|
||||
async def heartscmd(self, message):
|
||||
for _ in range(10):
|
||||
for heart in ['❤', '️🧡', '💛', '💚', '💙', '💜']:
|
||||
await message.edit(heart)
|
||||
await sleep(0.3)
|
||||
96
KeyZenD/modules/help.py
Normal file
96
KeyZenD/modules/help.py
Normal file
@@ -0,0 +1,96 @@
|
||||
import logging
|
||||
import inspect
|
||||
|
||||
from telethon.tl.functions.channels import JoinChannelRequest
|
||||
|
||||
from .. import loader, utils, main, security
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@loader.tds
|
||||
class HelpMod(loader.Module):
|
||||
"""Provides this help message"""
|
||||
strings = {"name": "Help",
|
||||
"bad_module": '<b>Модуля</b> "<code>{}</code>" <b>нет в базе!</b>',
|
||||
"single_mod_header": "<b>Информация о</b> <u>{}</u>:\n",
|
||||
"single_cmd": "\n {}\n",
|
||||
"undoc_cmd": "Для этой команды нет документации",
|
||||
"all_header": 'Список из <a href="https://t.me/SomeScripts">{}</a> доступных модулей:\n\n',
|
||||
"mod_tmpl": '\n‣<a href="tg://user?id={}">{}</a>',
|
||||
"first_cmd_tmpl": "⋮( {}",
|
||||
"cmd_tmpl": " | {}",
|
||||
"SomeScripts": "SomeScripts"}
|
||||
|
||||
@loader.unrestricted
|
||||
async def helpcmd(self, message):
|
||||
""".help [module]"""
|
||||
args = utils.get_args_raw(message)
|
||||
id = message.sender_id
|
||||
if args:
|
||||
module = None
|
||||
for mod in self.allmodules.modules:
|
||||
if mod.strings("name", message).lower() == args.lower():
|
||||
module = mod
|
||||
if module is None:
|
||||
await utils.answer(message, self.strings("bad_module", message).format(args))
|
||||
return
|
||||
# Translate the format specification and the module separately
|
||||
try:
|
||||
name = module.strings("name", message)
|
||||
except KeyError:
|
||||
name = getattr(module, "name", "ERROR")
|
||||
reply = self.strings("single_mod_header", message).format(utils.escape_html(name),
|
||||
utils.escape_html((self.db.get(main.__name__,
|
||||
"command_prefix",
|
||||
False) or ".")[0]))
|
||||
if module.__doc__:
|
||||
reply += "\n"+"\n".join(" " + t for t in utils.escape_html(inspect.getdoc(module)).split("\n"))
|
||||
else:
|
||||
logger.warning("Module %s is missing docstring!", module)
|
||||
commands = {name: func for name, func in module.commands.items()
|
||||
if await self.allmodules.check_security(message, func)}
|
||||
for name, fun in commands.items():
|
||||
reply += self.strings("single_cmd", message).format(name)
|
||||
if fun.__doc__:
|
||||
reply += utils.escape_html("\n".join(" " + t for t in inspect.getdoc(fun).split("\n")))
|
||||
else:
|
||||
reply += self.strings("undoc_cmd", message)
|
||||
else:
|
||||
count = 0
|
||||
for i in self.allmodules.modules:
|
||||
if len(i.commands) != 0:
|
||||
count += 1
|
||||
reply = self.strings("all_header", message).format(count)
|
||||
|
||||
for mod in self.allmodules.modules:
|
||||
if len(mod.commands) != 0:
|
||||
try:
|
||||
name = mod.strings("name", message)
|
||||
except KeyError:
|
||||
name = getattr(mod, "name", "ERROR")
|
||||
reply += self.strings("mod_tmpl", message).format(id, name)
|
||||
first = True
|
||||
commands = [name for name, func in mod.commands.items()
|
||||
if await self.allmodules.check_security(message, func)]
|
||||
for cmd in commands:
|
||||
if first:
|
||||
reply += self.strings("first_cmd_tmpl", message).format(cmd)
|
||||
first = False
|
||||
else:
|
||||
reply += self.strings("cmd_tmpl", message).format(cmd)
|
||||
reply += " )"
|
||||
|
||||
await utils.answer(message, reply)
|
||||
|
||||
@loader.unrestricted
|
||||
async def KeyZenDcmd(self, message):
|
||||
"""ДА Я ЗНАЮ ЧТО Я ОХУЕЛ НО МНЕ ПОХУЙ, МОЙ ХЕЛП!"""
|
||||
await message.delete()
|
||||
await self.client(JoinChannelRequest(self.strings("SomeScripts", message)))
|
||||
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
self.is_bot = await client.is_bot()
|
||||
self.db = db
|
||||
109
KeyZenD/modules/hyi.py
Normal file
109
KeyZenD/modules/hyi.py
Normal file
@@ -0,0 +1,109 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Friendly Telegram (telegram userbot)
|
||||
# Copyright (C) 2018-2020 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.
|
||||
# если не подписан на t.me/keyzend
|
||||
# твоя мама шлюха
|
||||
# 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 # pylint: disable=relative-beyond-top-level
|
||||
import io
|
||||
from PIL import Image, ImageOps
|
||||
from telethon.tl.types import DocumentAttributeFilename
|
||||
import logging
|
||||
import random
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def register(cb):
|
||||
cb(Ебал_я_в_рот_ваш_пеп_8_Mod())
|
||||
|
||||
|
||||
@loader.tds
|
||||
class Ебал_я_в_рот_ваш_пеп_8_Mod(loader.Module):
|
||||
"""Гавно залупное"""
|
||||
strings = {
|
||||
"name": "Хуификатор"
|
||||
}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
|
||||
|
||||
@loader.sudo
|
||||
async def хуйcmd(self, message):
|
||||
text = utils.get_args(message)
|
||||
if not text:
|
||||
reply = await message.get_reply_message()
|
||||
if not reply:
|
||||
await message.delete()
|
||||
return
|
||||
text = reply.raw_text.split()
|
||||
async def huify(word):
|
||||
word = word.lower().strip()
|
||||
vowels = 'аеёиоуыэюя'
|
||||
rules = {
|
||||
'а': 'я',
|
||||
'о': 'ё',
|
||||
'у': 'ю',
|
||||
'ы': 'и',
|
||||
'э': 'е',
|
||||
}
|
||||
for letter in word:
|
||||
if letter in vowels:
|
||||
if letter in rules:
|
||||
word = rules[letter] + word[1:]
|
||||
break
|
||||
else:
|
||||
word = word[1:]
|
||||
return 'Ху' + word if word else 'Хуй'
|
||||
|
||||
out = []
|
||||
for word in text:
|
||||
хуй = await huify(word)
|
||||
out.append(хуй)
|
||||
await message.edit(" ".join(out))
|
||||
|
||||
async def хуйняcmd(self, message):
|
||||
text = utils.get_args(message)
|
||||
if not text:
|
||||
reply = await message.get_reply_message()
|
||||
if not reply:
|
||||
await message.delete()
|
||||
return
|
||||
text = reply.raw_text.split()
|
||||
async def huify(word):
|
||||
word = word.lower().strip()
|
||||
vowels = 'аеёиоуыэюя'
|
||||
rules = {
|
||||
'а': 'я',
|
||||
'о': 'ё',
|
||||
'у': 'ю',
|
||||
'ы': 'и',
|
||||
'э': 'е',
|
||||
}
|
||||
for letter in word:
|
||||
if letter in vowels:
|
||||
if letter in rules:
|
||||
word = rules[letter] + word[1:]
|
||||
break
|
||||
else:
|
||||
word = word[1:]
|
||||
return 'Ху' + word if word else 'Хуй'
|
||||
|
||||
out = []
|
||||
for word in text:
|
||||
хуй = await huify(word)
|
||||
out.append(f"{word}-{хуй}")
|
||||
await message.edit(" ".join(out))
|
||||
93
KeyZenD/modules/im2bin.py
Normal file
93
KeyZenD/modules/im2bin.py
Normal file
@@ -0,0 +1,93 @@
|
||||
import asyncio
|
||||
import logging
|
||||
from PIL import Image, ImageDraw, ImageFont, ImageOps
|
||||
import io
|
||||
from requests import get
|
||||
from string import digits
|
||||
from random import choice
|
||||
from .. import loader, utils
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
font_ = get("https://github.com/KeyZenD/l/blob/master/mono.otf?raw=true").content
|
||||
|
||||
@loader.tds
|
||||
class Im2BinaryMod(loader.Module):
|
||||
"""Картинки в текст. что?"""
|
||||
strings = {"name": "Im2Bin"}
|
||||
|
||||
@loader.unrestricted
|
||||
async def bincmd(self, message):
|
||||
""".bin <картинка или реплай> + слова (дефолт на рандоме) (не мешает слова)"""
|
||||
img, words, me = await prepare(message)
|
||||
if not img:
|
||||
await message.delete()
|
||||
return await message.client.send_file(message.chat.id, get("https://thiscatdoesnotexist.com").content, caption=choice(["<b>Тебе картинок мало?</b>"]+[None]*100))
|
||||
await message.edit("<b>Processing...</b>")
|
||||
img = await image_to_text(words, img, False)
|
||||
[await message.delete(), await (await message.get_reply_message()).reply(file=img)] if not me else await message.edit(file=img, text="")
|
||||
@loader.unrestricted
|
||||
async def rbincmd(self, message):
|
||||
""".rbin <картинка или реплай> + слова (дефолт на рандоме) (мешает слова)"""
|
||||
img, words, me = await prepare(message)
|
||||
if not img:
|
||||
await message.delete()
|
||||
return await message.client.send_file(message.chat.id, get("https://thiscatdoesnotexist.com").content, caption=choice(["<b>Тебе картинок мало?</b>"]+[None]*100))
|
||||
await message.edit("<b>Processing...</b>")
|
||||
img = await image_to_text(words, img, True)
|
||||
[await message.delete(), await (await message.get_reply_message()).reply(file=img)] if not me else await message.edit(file=img, text="")
|
||||
|
||||
async def getimg(m):
|
||||
if not m.file:
|
||||
return False
|
||||
if not "image" in m.file.mime_type.lower():
|
||||
return False
|
||||
return True
|
||||
|
||||
async def prepare(message):
|
||||
if not await getimg(message):
|
||||
reply = await message.get_reply_message()
|
||||
if not reply or not await getimg(reply):
|
||||
return False, False, False
|
||||
else:
|
||||
me = False
|
||||
img = await reply.download_media(bytes)
|
||||
else:
|
||||
me = True
|
||||
img = await message.download_media(bytes)
|
||||
args = utils.get_args(message)
|
||||
words = [f"{x} " for x in args] if args else list("01")
|
||||
return img, words, me
|
||||
|
||||
async def image_to_text(words, img, rand):
|
||||
inp = Image.open(io.BytesIO(img))
|
||||
img = Image.new("RGBA", inp.size, "#000")
|
||||
res = img.copy()
|
||||
img.paste(inp, (0, 0), inp if inp.mode == "RGBA" else None)
|
||||
w, h = img.size
|
||||
font = ImageFont.truetype(io.BytesIO(font_), 15)
|
||||
mw = min(map(lambda x: font.getsize(x)[0], "".join(words)))
|
||||
mh = min(map(lambda x: font.getsize(x)[1], "".join(words)))
|
||||
rand_ = 0
|
||||
text = []
|
||||
while len(text)*mh <= h:
|
||||
row = []
|
||||
while len("".join(row))*mw <= w:
|
||||
word = choice(words) if rand else words[rand_%len(words)]
|
||||
rand_ += 1
|
||||
row.append(word)
|
||||
rand_ -= 1
|
||||
text.append("".join(row))
|
||||
text = "\n".join(text)
|
||||
wt, ht = ImageDraw.Draw(Image.new("L", (0, 0))).multiline_textsize(font=font, text=text, spacing=0)
|
||||
im = Image.new("L", (wt, ht), 0)
|
||||
ImageDraw.Draw(im).multiline_text((0, -3), font=font, text=text, spacing=0, fill=255)
|
||||
im = im.crop((0, 0, w, h))
|
||||
im = Image.frombytes("L", (w, h), bytes([255 if x > 150 else 0 for x in im.tobytes()]))
|
||||
img.putalpha(im)
|
||||
res.paste(img, (0, 0), img)
|
||||
out = io.BytesIO()
|
||||
out.name = words[0] + ".png"
|
||||
res.save(out)
|
||||
out.seek(0)
|
||||
return out
|
||||
48
KeyZenD/modules/jpeg.py
Normal file
48
KeyZenD/modules/jpeg.py
Normal file
@@ -0,0 +1,48 @@
|
||||
from PIL import Image
|
||||
from telethon.tl.types import DocumentAttributeFilename
|
||||
from uniborg.util import admin_cmd
|
||||
import io
|
||||
|
||||
@borg.on(admin_cmd(pattern=".jpeg?(.*)", allow_sudo=True))
|
||||
async def shacal(event):
|
||||
async def check_media(reply_message):
|
||||
if reply_message and reply_message.media:
|
||||
if reply_message.photo:
|
||||
data = reply_message.photo
|
||||
elif reply_message.document:
|
||||
if DocumentAttributeFilename(file_name='AnimatedSticker.tgs') in reply_message.media.document.attributes:
|
||||
return False
|
||||
if reply_message.gif or reply_message.video or reply_message.audio or reply_message.voice:
|
||||
return False
|
||||
data = reply_message.media.document
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
if not data or data is None:
|
||||
return False
|
||||
else:
|
||||
return data
|
||||
|
||||
if event.is_reply:
|
||||
reply_message = await event.get_reply_message()
|
||||
data = await check_media(reply_message)
|
||||
if isinstance(data, bool):
|
||||
await event.delete()
|
||||
return
|
||||
else:
|
||||
await event.delete()
|
||||
return
|
||||
|
||||
image = io.BytesIO()
|
||||
await event.client.download_media(data, image)
|
||||
image = Image.open(image)
|
||||
fried_io = io.BytesIO()
|
||||
fried_io.name = "image.jpeg"
|
||||
image = image.convert("RGB")
|
||||
image.save(fried_io, "JPEG", quality=0)
|
||||
fried_io.seek(0)
|
||||
await event.delete()
|
||||
await event.client.send_file(event.chat_id, fried_io, reply_to=reply_message.id)
|
||||
|
||||
90
KeyZenD/modules/keyboard_lagre.py
Normal file
90
KeyZenD/modules/keyboard_lagre.py
Normal file
File diff suppressed because one or more lines are too long
90
KeyZenD/modules/keyboard_small.py
Normal file
90
KeyZenD/modules/keyboard_small.py
Normal file
File diff suppressed because one or more lines are too long
93
KeyZenD/modules/kicklast.py
Normal file
93
KeyZenD/modules/kicklast.py
Normal file
@@ -0,0 +1,93 @@
|
||||
# @KeyZenD & @D4n13l3k00
|
||||
# requires: bs4 aiogram
|
||||
|
||||
from random import choice
|
||||
from string import ascii_lowercase
|
||||
|
||||
from aiogram import Bot
|
||||
from bs4 import BeautifulSoup as bs4
|
||||
from telethon import events, functions, types
|
||||
from telethon.tl.functions.channels import InviteToChannelRequest
|
||||
from telethon.tl.types import Channel
|
||||
|
||||
from .. import loader, utils
|
||||
|
||||
|
||||
class KickLastMod(loader.Module):
|
||||
"""Удаляет из чата последних Х зашедших"""
|
||||
|
||||
strings = {
|
||||
'name': 'KickLast',
|
||||
'pref': '<b>[KickLast]</b> ',
|
||||
'cdne': '{}Такого чата не существует',
|
||||
'cfju': '{}Не могу обнаружить зашедших...',
|
||||
'success': '{}Операция завершена! Кикнуто {} юзеров',
|
||||
'found': '{}Найдено {} зашедших юзеров! Кикаю...',
|
||||
'howmany': '{}Сколько нужно кикнуть?\n0 если всех зашедших за 48 часов',
|
||||
'createerr': '{}Создание бота недоступно.\nПовтори попытку через {}'
|
||||
}
|
||||
|
||||
async def botkicklastcmd(self, message):
|
||||
""".botkicklst <количество> <юзернейм, если канал> - Кикает при помощи тг бота"""
|
||||
await kick(self, message, True)
|
||||
|
||||
async def kicklastcmd(self, message):
|
||||
""".kicklst <количество> <юзернейм, если канал> - Кикает юзерботом"""
|
||||
await kick(self, message, False)
|
||||
|
||||
|
||||
async def kick(self, message, bot=False):
|
||||
client = message.client
|
||||
args = utils.get_args(message)
|
||||
if not args:
|
||||
return await utils.answer(message, self.strings('howmany').format(self.strings('pref')))
|
||||
limit = int(args[0])
|
||||
limit = limit or 99999
|
||||
group = args[-1] if len(args) > 1 else message.chat.id
|
||||
try:
|
||||
group = await client.get_entity(group)
|
||||
except:
|
||||
await utils.answer(message, self.strings('cdne').format(self.strings('pref')))
|
||||
if not isinstance(group, Channel):
|
||||
return await utils.answer(message, self.strings('cdne').format(self.strings('pref')))
|
||||
if bot:
|
||||
botfather = 93372553
|
||||
bantoolbot = "".join(choice(list(ascii_lowercase))
|
||||
for _ in range(29))+"bot"
|
||||
async with client.conversation(botfather) as conv:
|
||||
await (await client.send_message(botfather, "/newbot")).delete()
|
||||
newbot = await conv.wait_event(events.NewMessage(incoming=True, from_users=botfather))
|
||||
await newbot.delete()
|
||||
if "Sorry" in newbot.text:
|
||||
return await utils.answer(message, self.strings('howmany').format(self.strings('pref'), newbot.text[45:]))
|
||||
await (await client.send_message(botfather, "BanTool")).delete()
|
||||
await (await conv.wait_event(events.NewMessage(incoming=True, from_users=botfather))).delete()
|
||||
await (await client.send_message(botfather, bantoolbot)).delete()
|
||||
html = await conv.wait_event(events.NewMessage(incoming=True, from_users=botfather))
|
||||
await html.delete()
|
||||
soup = bs4(html.text, "html.parser")
|
||||
token = soup.findAll("code")[0].text
|
||||
await client(InviteToChannelRequest(group, [bantoolbot]))
|
||||
await client(functions.channels.EditAdminRequest(
|
||||
channel=group,
|
||||
user_id=bantoolbot,
|
||||
admin_rights=types.ChatAdminRights(ban_users=True), rank='BanToolBot'))
|
||||
banlist = [x.user_id async for x in client.iter_admin_log(group, join=True, limit=limit)]
|
||||
|
||||
message = await utils.answer(message, self.strings('found').format(self.strings('pref'), str(len(banlist))))
|
||||
if not banlist:
|
||||
return await utils.answer(message, self.strings('cfju').format(self.strings('pref')))
|
||||
for banid in banlist:
|
||||
if bot:
|
||||
await Bot(token).kick_chat_member(f"-100{group}", banid)
|
||||
else:
|
||||
await client.kick_participant(group, banid)
|
||||
if bot:
|
||||
await client.kick_participant(group, bantoolbot)
|
||||
async with client.conversation(botfather) as conv:
|
||||
await client.send_message(botfather, "/deletebot")
|
||||
await conv.wait_event(events.NewMessage(incoming=True, from_users=botfather))
|
||||
await client.send_message(botfather, "@"+bantoolbot)
|
||||
await conv.wait_event(events.NewMessage(incoming=True, from_users=botfather))
|
||||
await client.send_message(botfather, "Yes, I am totally sure.")
|
||||
return await utils.answer(message, self.strings('success').format(self.strings('pref'), str(len(banlist))))
|
||||
250
KeyZenD/modules/kzdQuotes.py
Normal file
250
KeyZenD/modules/kzdQuotes.py
Normal file
@@ -0,0 +1,250 @@
|
||||
from .. import loader, utils
|
||||
import telethon
|
||||
import logging
|
||||
import io
|
||||
from telethon.tl.types import (ChannelParticipantsAdmins, ChannelParticipantCreator, ChannelParticipantAdmin, User)
|
||||
from requests import post
|
||||
from PIL import Image
|
||||
|
||||
|
||||
logger = logging.getLogger("kzdQuotes")
|
||||
|
||||
|
||||
@loader.tds
|
||||
class kzdQuotesMod(loader.Module):
|
||||
"""kzdQuote a message"""
|
||||
strings = {
|
||||
"name": "kzdQuotes",
|
||||
"processing": "<b>️Quoting</b>",
|
||||
"processing_api": "<b>Quoting💬</b>",
|
||||
"no_reply": "<b>Нет реплая</b>",
|
||||
"mediaType_photo": "️Фото",
|
||||
"mediaType_video": "Видео",
|
||||
"mediaType_videomessage": "Видеосообщение",
|
||||
"mediaType_voice": "️Аудиосообщение",
|
||||
"mediaType_audio": "Аудио",
|
||||
"mediaType_poll": "Голосование",
|
||||
"mediaType_quiz": "Викторина",
|
||||
"mediaType_location": "Геолокация",
|
||||
"mediaType_gif": "GIF",
|
||||
"mediaType_sticker": "Стикер",
|
||||
"mediaType_file": "Файл: ",
|
||||
"diceType_dice": "Кубик",
|
||||
"diceType_dart": "Дартс",
|
||||
"ball_thrown": "Бросок мяча",
|
||||
"dart_thrown": "Бросок дротика",
|
||||
"dart_almostthere": "близко к цели!",
|
||||
"dart_missed": "мимо!",
|
||||
"dart_bullseye": "в яблочко!",
|
||||
"settings": "<b>Доступные настройки:</b>\n<code>color</code> - hex color - Цвет квотеса"
|
||||
}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
self.db = db
|
||||
|
||||
@loader.unrestricted
|
||||
@loader.ratelimit
|
||||
async def qqcmd(self, message):
|
||||
args = utils.get_args_raw(message)
|
||||
reply = await message.get_reply_message()
|
||||
if not reply:
|
||||
await utils.answer(message, self.strings('no_reply', message))
|
||||
return
|
||||
await utils.answer(message, self.strings('processing', message))
|
||||
fwd = via = rtext = file = thumb = rname = admintitle = None
|
||||
if ".file" in args:
|
||||
file = True
|
||||
args = args.replace(".file","").strip()
|
||||
|
||||
text = args or reply.text
|
||||
sender = user = reply.sender
|
||||
if sender:
|
||||
id = sender.id if sender.id != 1087968824 else reply.chat.id
|
||||
else:
|
||||
id = reply.fwd_from.channel_id
|
||||
|
||||
sender = await message.client.get_entity(id)
|
||||
name = "Deleted Account" if user and sender.deleted else telethon.utils.get_display_name(sender)
|
||||
pfp = await message.client.download_profile_photo(sender, bytes)
|
||||
if reply.fwd_from and reply.sender:
|
||||
id = reply.fwd_from.from_id or reply.fwd_from.channel_id
|
||||
if not id:
|
||||
fname = reply.fwd_from.from_name
|
||||
else:
|
||||
sender = await message.client.get_entity(id)
|
||||
fwd = telethon.utils.get_display_name(sender)
|
||||
|
||||
if reply.via_bot:
|
||||
via = reply.via_bot.username or "magic"
|
||||
|
||||
img = await check_media(message, reply)
|
||||
rreply = await reply.get_reply_message()
|
||||
if rreply and not args:
|
||||
thumb = await check_media(message, rreply, True)
|
||||
rtext = rreply.raw_text
|
||||
if rreply.media:
|
||||
rtext = await get_media_caption(rreply) #спиздено у t.me/rfoxxxy
|
||||
rsender = rreply.sender
|
||||
rname = telethon.utils.get_display_name(rsender)
|
||||
|
||||
|
||||
if message.chat and reply.sender:
|
||||
admins = await message.client.get_participants(message.to_id, filter=ChannelParticipantsAdmins)
|
||||
if reply.sender in admins:
|
||||
admin = admins[admins.index(reply.sender)].participant
|
||||
if not admin:
|
||||
admintitle = None
|
||||
else:
|
||||
admintitle = admin.rank
|
||||
if not admintitle:
|
||||
if type(admin) == ChannelParticipantCreator:
|
||||
admintitle = "creator"
|
||||
else:
|
||||
admintitle = "admin"
|
||||
else:
|
||||
admintitle = "channel" if message.chat else None
|
||||
|
||||
|
||||
color = self.db.get("kzdQuotes", "color", None)
|
||||
data = {"id":id,"name":name,"admin":admintitle, "via":via, "fwd":fwd,"text":text,"rtext":rtext,"rname":rname, "color":color}
|
||||
files = {"pfp": pfp, "img":img, "thumb": thumb}
|
||||
await utils.answer(message, self.strings('processing_api', message))
|
||||
q = post("https://tyt.keyzend.pw/quote", data=data, files=files).content
|
||||
quote = io.BytesIO()
|
||||
quote.name = "govnoquotes"+ (".png" if file else ".webp")
|
||||
im = Image.open(io.BytesIO(q))
|
||||
if not file:
|
||||
im.thumbnail((512, 512))
|
||||
back = Image.new("RGBA", (im.width, im.height+100), None)
|
||||
back.paste(im, (0, 0), im)
|
||||
im = back
|
||||
im.thumbnail((512, 512))
|
||||
im.save(quote, "PNG" if file else "WEBP")
|
||||
quote.seek(0)
|
||||
await reply.reply(file=quote, force_document=file)
|
||||
await message.delete()
|
||||
|
||||
@loader.unrestricted
|
||||
@loader.ratelimit
|
||||
async def qqsetcmd(self, message):
|
||||
args = utils.get_args(message)
|
||||
if len(args) != 2 or args[0].lower() not in ["color"]:
|
||||
await utils.answer(message, self.strings('settings', message))
|
||||
return
|
||||
key, value = args
|
||||
self.db.set("kzdQuotes", key, value)
|
||||
await message.edit(f"<b>Значение {args[0]} установлено</b>")
|
||||
|
||||
|
||||
|
||||
|
||||
async def get_media_caption(reply):
|
||||
if reply and reply.media:
|
||||
if reply.photo:
|
||||
return kzdQuotesMod.strings["mediaType_photo"]
|
||||
if reply.text:
|
||||
return reply.raw_text
|
||||
dice = False
|
||||
try:
|
||||
dice = True if reply.dice else False
|
||||
except AttributeError:
|
||||
try:
|
||||
dice = True if type(reply.media) == telethon.tl.types.MessageMediaDice else False
|
||||
except AttributeError:
|
||||
pass
|
||||
if dice:
|
||||
dice_type = ""
|
||||
dice_text = reply.media.value
|
||||
if reply.media.emoticon == "🎲":
|
||||
dice_type = kzdQuotesMod.strings["diceType_dice"]
|
||||
return "{} {}: {}".format(reply.media.emoticon,
|
||||
dice_type,
|
||||
dice_text)
|
||||
elif reply.media.emoticon == "🎯":
|
||||
if dice_text == 1:
|
||||
dice_text = kzdQuotesMod.strings["dart_missed"]
|
||||
elif dice_text == 5:
|
||||
dice_text = kzdQuotesMod.strings["dart_almostthere"]
|
||||
elif dice_text == 6:
|
||||
dice_text = kzdQuotesMod.strings["dart_bullseye"]
|
||||
else:
|
||||
return "{} {}".format(reply.media.emoticon, kzdQuotesMod.strings["dart_thrown"])
|
||||
dice_type = kzdQuotesMod.strings["diceType_dart"]
|
||||
return "{} {}: {}".format(reply.media.emoticon, dice_type, dice_text)
|
||||
elif reply.media.emoticon == "🏀":
|
||||
return "{} {}".format(reply.media.emoticon, kzdQuotesMod.strings["ball_thrown"])
|
||||
else:
|
||||
return "Unsupported dice type ({}): {}".format(reply.media.emoticon, reply.media.value)
|
||||
elif reply.poll:
|
||||
try:
|
||||
if reply.media.poll.quiz is True:
|
||||
return kzdQuotesMod.strings["mediaType_quiz"]
|
||||
except Exception:
|
||||
pass
|
||||
return kzdQuotesMod.strings["mediaType_poll"]
|
||||
elif reply.geo:
|
||||
return kzdQuotesMod.strings["mediaType_location"]
|
||||
elif reply.document:
|
||||
if reply.gif :
|
||||
return kzdQuotesMod.strings["mediaType_gif"]
|
||||
elif reply.video:
|
||||
if reply.video.attributes[0].round_message:
|
||||
return kzdQuotesMod.strings["mediaType_videomessage"]
|
||||
else:
|
||||
return kzdQuotesMod.strings["mediaType_video"]
|
||||
elif reply.audio:
|
||||
return kzdQuotesMod.strings["mediaType_audio"]
|
||||
elif reply.voice:
|
||||
return kzdQuotesMod.strings["mediaType_voice"]
|
||||
elif reply.file:
|
||||
if reply.file.mime_type == "application/x-tgsticker":
|
||||
emoji = ""
|
||||
try:
|
||||
emoji = reply.media.document.attributes[0].alt
|
||||
except AttributeError:
|
||||
try:
|
||||
emoji = reply.media.document.attributes[1].alt
|
||||
except AttributeError:
|
||||
emoji = ""
|
||||
caption = "{} {}".format(emoji, kzdQuotesMod.strings["mediaType_sticker"]) if emoji != "" else kzdQuotesMod.strings["mediaType_sticker"]
|
||||
return caption
|
||||
else:
|
||||
if reply.sticker:
|
||||
emoji = ""
|
||||
try:
|
||||
emoji = reply.file.emoji
|
||||
logger.debug(len(emoji))
|
||||
except TypeError:
|
||||
emoji = ""
|
||||
caption = "{} {}".format(emoji, kzdQuotesMod.strings["mediaType_sticker"]) if emoji != "" else kzdQuotesMod.strings["mediaType_sticker"]
|
||||
return caption
|
||||
else:
|
||||
return kzdQuotesMod.strings["mediaType_file"] + reply.file.name
|
||||
else:
|
||||
return ""
|
||||
else:
|
||||
return ""
|
||||
|
||||
return ""
|
||||
|
||||
async def check_media(message, reply, x=None):
|
||||
if reply and reply.media:
|
||||
if reply.photo:
|
||||
data = reply.photo
|
||||
elif reply.document:
|
||||
if reply.gif or reply.video or reply.file.mime_type == "application/x-tgsticker":
|
||||
return await reply.download_media(bytes, thumb=-1) if x else None
|
||||
if reply.audio or reply.voice:
|
||||
return None
|
||||
data = reply.media.document
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
return None
|
||||
if not data or data is None:
|
||||
return None
|
||||
else:
|
||||
return await message.client.download_file(data, bytes)
|
||||
|
||||
|
||||
23
KeyZenD/modules/leave.py
Normal file
23
KeyZenD/modules/leave.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from .. import loader, utils
|
||||
from asyncio import sleep
|
||||
from telethon.tl.functions.channels import LeaveChannelRequest
|
||||
@loader.tds
|
||||
class LeaveMod(loader.Module):
|
||||
strings = {"name": "Just leave"}
|
||||
@loader.sudo
|
||||
async def leavecmd(self, message):
|
||||
""".leave"""
|
||||
if not message.chat:
|
||||
await message.edit("<b>Дурка блять</b>")
|
||||
return
|
||||
text = utils.get_args_raw(message)
|
||||
if not text:
|
||||
text = "До связи."
|
||||
if text.lower() == "del":
|
||||
await message.delete()
|
||||
else:
|
||||
await message.edit(f"<b>{text}</b>")
|
||||
await sleep(1)
|
||||
await message.client(LeaveChannelRequest(message.chat_id))
|
||||
|
||||
|
||||
53
KeyZenD/modules/mediaspam.py
Normal file
53
KeyZenD/modules/mediaspam.py
Normal file
@@ -0,0 +1,53 @@
|
||||
from telethon import events
|
||||
from .. import loader, utils
|
||||
|
||||
#испольуйте только на свой страх и риск
|
||||
#используя этот модуль вы принимаете то
|
||||
#что если получите бан, то на мне никакой ответственности
|
||||
|
||||
|
||||
|
||||
def register(cb):
|
||||
cb(MSMod())
|
||||
|
||||
|
||||
class MSMod(loader.Module):
|
||||
"""Спаммер медиа(стикер/гиф/фото/видео/войс/видеовойс</code>"""
|
||||
|
||||
strings = {'name': 'МедиаСпам'}
|
||||
|
||||
def __init__(self):
|
||||
self.name = self.strings['name']
|
||||
self._me = None
|
||||
self._ratelimit = []
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self._db = db
|
||||
self._client = client
|
||||
self.me = await client.get_me()
|
||||
|
||||
async def mediaspamcmd(self, message):
|
||||
""".mediaspam <количество> + реплай на медиа(стикер/гиф/фото/видео/войс/видеовойс)"""
|
||||
reply = await message.get_reply_message()
|
||||
if not reply:
|
||||
await message.edit("<code>.mediaspam <количество> + реплай на медиа(стикер/гиф/фото/видео/войс/видеовойс</code>")
|
||||
return
|
||||
if not reply.media:
|
||||
await message.edit("<code>.mediaspam <количество> + реплай на медиа(стикер/гиф/фото/видео/войс/видеовойс</code>")
|
||||
return
|
||||
media = reply.media
|
||||
|
||||
args = utils.get_args(message)
|
||||
if not args:
|
||||
await message.edit("<code>.mediaspam <количество> + реплай на медиа(стикер/гиф/фото/видео/войс/видеовойс</code>")
|
||||
return
|
||||
count = args[0]
|
||||
count = count.strip()
|
||||
if not count.isdigit():
|
||||
await message.edit("<code>.mediaspam <количество> + реплай на медиа(стикер/гиф/фото/видео/войс/видеовойс</code>")
|
||||
return
|
||||
count = int(count)
|
||||
|
||||
await message.delete()
|
||||
for _ in range(count):
|
||||
await message.client.send_file(message.to_id, media)
|
||||
26
KeyZenD/modules/modulator.py
Normal file
26
KeyZenD/modules/modulator.py
Normal file
@@ -0,0 +1,26 @@
|
||||
R=int
|
||||
Q=float
|
||||
E=len
|
||||
# requires: pydub numpy
|
||||
from .. import loader as A,utils
|
||||
import os
|
||||
from pydub import AudioSegment as M
|
||||
import numpy as G,io
|
||||
class BMod(A.Module):
|
||||
'Modulate pitch of voice';strings={'name':'Modulator'}
|
||||
async def modulatecmd(W,message):
|
||||
A=message;B=await A.get_reply_message()
|
||||
if not B or not B.file and'audio'in B.file.mime_type:return await A.edit('<b>Reply to audio!</b>')
|
||||
N=io.BytesIO(await B.download_media(bytes));N.seek(0);X=[];H=M.empty();I=M.from_file(N);I=[A for A in I];C=utils.get_args(A);J=0.9,1.1,0.01;O=3
|
||||
if E(C)==3:
|
||||
try:J=(Q(A)for A in C)
|
||||
except:pass
|
||||
if E(C)==4:
|
||||
try:J=(Q(A)for A in C[0:3]);O=R(C[3])
|
||||
except:pass
|
||||
P=G.repeat(G.arange(*J),O);S=G.sin(P);D=list(map(lambda x:x[0]*x[-1],zip(P,S)));K=1;await A.edit('<b>Modulating...</b>')
|
||||
for (T,L) in enumerate(I):
|
||||
U=D[T%E(D)];K+=1
|
||||
if K>E(D):K=0;D=D[::-1]
|
||||
V=R(L.frame_rate*U);H+=L._spawn(L.raw_data,overrides={'frame_rate':V})
|
||||
F=io.BytesIO();F.name='modulator_by_keyzend.ogg';H.export(F,format='ogg',bitrate='64k',codec='libopus');F.seek(0);await A.client.send_file(A.to_id,F,reply_to=B.id,voice_note=True,duration=E(H)/1000);await A.delete()
|
||||
337
KeyZenD/modules/noterminal.py
Normal file
337
KeyZenD/modules/noterminal.py
Normal file
@@ -0,0 +1,337 @@
|
||||
# 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/>.
|
||||
|
||||
from .. import loader, utils
|
||||
import logging
|
||||
import asyncio
|
||||
import telethon
|
||||
import os
|
||||
import re
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@loader.tds
|
||||
class noTerminalMod(loader.Module):
|
||||
"""Runs commands"""
|
||||
|
||||
strings = {"name": "noTerminal",
|
||||
"flood_wait_protect_cfg_doc": "How long to wait in seconds between edits in commands",
|
||||
"what_to_kill": "<b>Reply to a terminal command to terminate it</b>",
|
||||
"kill_fail": "<b>Could not kill process</b>",
|
||||
"killed": "<b>Killed</b>",
|
||||
"no_cmd": "<b>No command is running in that message</b>",
|
||||
"running": "<b>Running command</b> <code>{}</code>",
|
||||
"finished": "\n<b>Command finished with return code</b> <code>{}</code>",
|
||||
"stdout": "\n<b>Stdout:</b>\n<code>",
|
||||
"stderr": "</code>\n\n<b>Stderr:</b>\n<code>",
|
||||
"end": "</code>",
|
||||
"auth_fail": "<b>Authentication failed, please try again</b>",
|
||||
"auth_needed": "<a href=\"tg://user?id={}\">Interactive authentication required</a>",
|
||||
"auth_msg": ("<b>Please edit this message to the password for</b> "
|
||||
"<code>{}</code> <b>to run</b> <code>{}</code>"),
|
||||
"auth_locked": "<b>Authentication failed, please try again later</b>",
|
||||
"auth_ongoing": "<b>Authenticating...</b>",
|
||||
"done": "<b>Done</b>",
|
||||
"what_note": "<b>What noterminal should be executed?</b>",
|
||||
"no_note": "<b>noteminal not found</b>"}
|
||||
|
||||
def __init__(self):
|
||||
self.config = loader.ModuleConfig("FLOOD_WAIT_PROTECT", 2,
|
||||
lambda m: self.strings("flood_wait_protect_cfg_doc", m))
|
||||
self.activecmds = {}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
self.db = db
|
||||
self._db = db
|
||||
|
||||
|
||||
async def noterminalcmd(self, message):
|
||||
"""Gets the note specified"""
|
||||
args = utils.get_args(message)
|
||||
if not args:
|
||||
await utils.answer(message, self.strings("what_note", message))
|
||||
return
|
||||
|
||||
asset_id = self.db.get("friendly-telegram.modules.notes", "notes", {}).get(args[0], None)
|
||||
logger.debug(asset_id)
|
||||
if asset_id is not None:
|
||||
asset = await self.db.fetch_asset(asset_id)
|
||||
else:
|
||||
asset_id = self.db.get("friendly-telegram.modules.notes", "notes", {}).get(args[0].lower(), None)
|
||||
if asset_id is not None:
|
||||
asset = await self.db.fetch_asset(asset_id)
|
||||
else:
|
||||
asset = None
|
||||
if asset is None:
|
||||
await utils.answer(message, self.strings("no_note", message))
|
||||
return
|
||||
|
||||
cmd = await self.db.fetch_asset(asset_id)
|
||||
await self.run_command(message, cmd.raw_text)
|
||||
|
||||
|
||||
async def run_command(self, message, cmd, editor=None):
|
||||
if len(cmd.split(" ")) > 1 and cmd.split(" ")[0] == "sudo":
|
||||
needsswitch = True
|
||||
for word in cmd.split(" ", 1)[1].split(" "):
|
||||
if word[0] != "-":
|
||||
break
|
||||
if word == "-S":
|
||||
needsswitch = False
|
||||
if needsswitch:
|
||||
cmd = " ".join([cmd.split(" ", 1)[0], "-S", cmd.split(" ", 1)[1]])
|
||||
sproc = await asyncio.create_subprocess_shell(cmd, stdin=asyncio.subprocess.PIPE,
|
||||
stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE,
|
||||
cwd=utils.get_base_dir())
|
||||
if editor is None:
|
||||
editor = SudoMessageEditor(message, cmd, self.config, self.strings, message)
|
||||
editor.update_process(sproc)
|
||||
self.activecmds[hash_msg(message)] = sproc
|
||||
await editor.redraw()
|
||||
await asyncio.gather(read_stream(editor.update_stdout, sproc.stdout, self.config["FLOOD_WAIT_PROTECT"]),
|
||||
read_stream(editor.update_stderr, sproc.stderr, self.config["FLOOD_WAIT_PROTECT"]))
|
||||
await editor.cmd_ended(await sproc.wait())
|
||||
del self.activecmds[hash_msg(message)]
|
||||
|
||||
@loader.owner
|
||||
async def noterminatecmd(self, message):
|
||||
"""Use in reply to send SIGTERM to a process"""
|
||||
if not message.is_reply:
|
||||
await utils.answer(message, self.strings("what_to_kill", message))
|
||||
return
|
||||
if hash_msg(await message.get_reply_message()) in self.activecmds:
|
||||
try:
|
||||
self.activecmds[hash_msg(await message.get_reply_message())].terminate()
|
||||
except Exception:
|
||||
logger.exception("Killing process failed")
|
||||
await utils.answer(message, self.strings("kill_fail", message))
|
||||
else:
|
||||
await utils.answer(message, self.strings("killed", message))
|
||||
else:
|
||||
await utils.answer(message, self.strings("no_cmd", message))
|
||||
|
||||
@loader.owner
|
||||
async def nokillcmd(self, message):
|
||||
"""Use in reply to send SIGKILL to a process"""
|
||||
if not message.is_reply:
|
||||
await utils.answer(message, self.strings("what_to_kill", message))
|
||||
return
|
||||
if hash_msg(await message.get_reply_message()) in self.activecmds:
|
||||
try:
|
||||
self.activecmds[hash_msg(await message.get_reply_message())].kill()
|
||||
except Exception:
|
||||
logger.exception("Killing process failed")
|
||||
await utils.answer(message, self.strings("kill_fail", message))
|
||||
else:
|
||||
await utils.answer(message, self.strings("killed", message))
|
||||
else:
|
||||
await utils.answer(message, self.strings("no_cmd", message))
|
||||
|
||||
def hash_msg(message):
|
||||
return str(utils.get_chat_id(message)) + "/" + str(message.id)
|
||||
|
||||
|
||||
async def read_stream(func, stream, delay):
|
||||
last_task = None
|
||||
data = b""
|
||||
while True:
|
||||
dat = (await stream.read(1))
|
||||
if not dat:
|
||||
# EOF
|
||||
if last_task:
|
||||
# Send all pending data
|
||||
last_task.cancel()
|
||||
await func(data.decode("utf-8"))
|
||||
# If there is no last task there is inherently no data, so theres no point sending a blank string
|
||||
break
|
||||
data += dat
|
||||
if last_task:
|
||||
last_task.cancel()
|
||||
last_task = asyncio.ensure_future(sleep_for_task(func, data, delay))
|
||||
|
||||
|
||||
async def sleep_for_task(func, data, delay):
|
||||
await asyncio.sleep(delay)
|
||||
await func(data.decode("utf-8"))
|
||||
|
||||
|
||||
class MessageEditor:
|
||||
def __init__(self, message, command, config, strings, request_message):
|
||||
self.message = [message]
|
||||
self.command = command
|
||||
self.stdout = ""
|
||||
self.stderr = ""
|
||||
self.rc = None
|
||||
self.redraws = 0
|
||||
self.config = config
|
||||
self.strings = strings
|
||||
self.request_message = request_message
|
||||
|
||||
async def update_stdout(self, stdout):
|
||||
self.stdout = stdout
|
||||
await self.redraw()
|
||||
|
||||
async def update_stderr(self, stderr):
|
||||
self.stderr = stderr
|
||||
await self.redraw()
|
||||
|
||||
async def redraw(self):
|
||||
text = "" # self.strings("running", self.request_message).format(utils.escape_html(self.command))
|
||||
# if self.rc is not None:
|
||||
# text += self.strings("finished", self.request_message).format(utils.escape_html(str(self.rc)))
|
||||
text += self.strings("stdout", self.request_message)
|
||||
text += utils.escape_html(self.stdout[max(len(self.stdout) - 2048, 0):])
|
||||
if len(self.stderr) > 0:
|
||||
text += self.strings("stderr", self.request_message)
|
||||
text += utils.escape_html(self.stderr[max(len(self.stderr) - 1024, 0):])
|
||||
text += self.strings("end", self.request_message)
|
||||
try:
|
||||
self.message = await utils.answer(self.message, text)
|
||||
except telethon.errors.rpcerrorlist.MessageNotModifiedError:
|
||||
pass
|
||||
except telethon.errors.rpcerrorlist.MessageTooLongError as e:
|
||||
logger.error(e)
|
||||
logger.error(text)
|
||||
# The message is never empty due to the template header
|
||||
|
||||
async def cmd_ended(self, rc):
|
||||
self.rc = rc
|
||||
self.state = 4
|
||||
await self.redraw()
|
||||
|
||||
def update_process(self, process):
|
||||
pass
|
||||
|
||||
|
||||
class SudoMessageEditor(MessageEditor):
|
||||
# Let's just hope these are safe to parse
|
||||
PASS_REQ = "[sudo] password for"
|
||||
WRONG_PASS = r"\[sudo\] password for (.*): Sorry, try again\."
|
||||
TOO_MANY_TRIES = r"\[sudo\] password for (.*): sudo: [0-9]+ incorrect password attempts"
|
||||
|
||||
def __init__(self, message, command, config, strings, request_message):
|
||||
super().__init__(message, command, config, strings, request_message)
|
||||
self.process = None
|
||||
self.state = 0
|
||||
self.authmsg = None
|
||||
|
||||
def update_process(self, process):
|
||||
logger.debug("got sproc obj %s", process)
|
||||
self.process = process
|
||||
|
||||
async def update_stderr(self, stderr):
|
||||
logger.debug("stderr update " + stderr)
|
||||
self.stderr = stderr
|
||||
lines = stderr.strip().split("\n")
|
||||
lastline = lines[-1]
|
||||
lastlines = lastline.rsplit(" ", 1)
|
||||
handled = False
|
||||
if len(lines) > 1 and re.fullmatch(self.WRONG_PASS,
|
||||
lines[-2]) and lastlines[0] == self.PASS_REQ and self.state == 1:
|
||||
logger.debug("switching state to 0")
|
||||
await self.authmsg.edit(self.strings("auth_failed", self.request_message))
|
||||
self.state = 0
|
||||
handled = True
|
||||
await asyncio.sleep(2)
|
||||
await self.authmsg.delete()
|
||||
if lastlines[0] == self.PASS_REQ and self.state == 0:
|
||||
logger.debug("Success to find sudo log!")
|
||||
text = self.strings("auth_needed", self.request_message).format((await self.message[0].client.get_me()).id)
|
||||
try:
|
||||
await utils.answer(self.message, text)
|
||||
except telethon.errors.rpcerrorlist.MessageNotModifiedError as e:
|
||||
logger.debug(e)
|
||||
logger.debug("edited message with link to self")
|
||||
command = "<code>" + utils.escape_html(self.command) + "</code>"
|
||||
user = utils.escape_html(lastlines[1][:-1])
|
||||
self.authmsg = await self.message[0].client.send_message("me",
|
||||
self.strings("auth_msg",
|
||||
self.request_message).format(command,
|
||||
user))
|
||||
logger.debug("sent message to self")
|
||||
self.message[0].client.remove_event_handler(self.on_message_edited)
|
||||
self.message[0].client.add_event_handler(self.on_message_edited,
|
||||
telethon.events.messageedited.MessageEdited(chats=["me"]))
|
||||
logger.debug("registered handler")
|
||||
handled = True
|
||||
if len(lines) > 1 and (re.fullmatch(self.TOO_MANY_TRIES, lastline)
|
||||
and (self.state == 1 or self.state == 3 or self.state == 4)):
|
||||
logger.debug("password wrong lots of times")
|
||||
await utils.answer(self.message, self.strings("auth_locked", self.request_message))
|
||||
await self.authmsg.delete()
|
||||
self.state = 2
|
||||
handled = True
|
||||
if not handled:
|
||||
logger.debug("Didn't find sudo log.")
|
||||
if self.authmsg is not None:
|
||||
await self.authmsg[0].delete()
|
||||
self.authmsg = None
|
||||
self.state = 2
|
||||
await self.redraw()
|
||||
logger.debug(self.state)
|
||||
|
||||
async def update_stdout(self, stdout):
|
||||
self.stdout = stdout
|
||||
if self.state != 2:
|
||||
self.state = 3 # Means that we got stdout only
|
||||
if self.authmsg is not None:
|
||||
await self.authmsg.delete()
|
||||
self.authmsg = None
|
||||
await self.redraw()
|
||||
|
||||
async def on_message_edited(self, message):
|
||||
# Message contains sensitive information.
|
||||
if self.authmsg is None:
|
||||
return
|
||||
logger.debug("got message edit update in self " + str(message.id))
|
||||
if hash_msg(message) == hash_msg(self.authmsg):
|
||||
# The user has provided interactive authentication. Send password to stdin for sudo.
|
||||
try:
|
||||
self.authmsg = await utils.answer(message, self.strings("auth_ongoing", self.request_message))
|
||||
except telethon.errors.rpcerrorlist.MessageNotModifiedError:
|
||||
# Try to clear personal info if the edit fails
|
||||
await message.delete()
|
||||
self.state = 1
|
||||
self.process.stdin.write(message.message.message.split("\n", 1)[0].encode("utf-8") + b"\n")
|
||||
|
||||
|
||||
class RawMessageEditor(SudoMessageEditor):
|
||||
def __init__(self, message, command, config, strings, request_message, show_done=False):
|
||||
super().__init__(message, command, config, strings, request_message)
|
||||
self.show_done = show_done
|
||||
|
||||
async def redraw(self):
|
||||
logger.debug(self.rc)
|
||||
if self.rc is None:
|
||||
text = "<code>" + utils.escape_html(self.stdout[max(len(self.stdout) - 4095, 0):]) + "</code>"
|
||||
elif self.rc == 0:
|
||||
text = "<code>" + utils.escape_html(self.stdout[max(len(self.stdout) - 4090, 0):]) + "</code>"
|
||||
else:
|
||||
text = "<code>" + utils.escape_html(self.stderr[max(len(self.stderr) - 4095, 0):]) + "</code>"
|
||||
if self.rc is not None and self.show_done:
|
||||
text += "\n" + self.strings("done", self.request_message)
|
||||
logger.debug(text)
|
||||
try:
|
||||
await utils.answer(self.message, text)
|
||||
except telethon.errors.rpcerrorlist.MessageNotModifiedError:
|
||||
pass
|
||||
except (telethon.errors.rpcerrorlist.MessageEmptyError, ValueError):
|
||||
pass
|
||||
except telethon.errors.rpcerrorlist.MessageTooLongError as e:
|
||||
logger.error(e)
|
||||
logger.error(text)
|
||||
138
KeyZenD/modules/notes.py
Normal file
138
KeyZenD/modules/notes.py
Normal file
@@ -0,0 +1,138 @@
|
||||
# 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
|
||||
|
||||
from .. import loader, utils
|
||||
|
||||
logger = logging.getLogger("friendly-telegram.modules.notes")
|
||||
|
||||
|
||||
@loader.tds
|
||||
class NotesMod(loader.Module):
|
||||
"""Stores global notes (aka snips)"""
|
||||
strings = {"name": "Notes",
|
||||
"what_note": "<b>Какую заметку нужно показать?</b>",
|
||||
"no_note": "<b>Заметка не найдена</b>",
|
||||
"save_what": "<b>А что сохранить?</b>",
|
||||
"what_name": "<b>А как будет называться заметка?</b>",
|
||||
"saved": "<b>Заметка сохранена как:</b> <code>{}</code>",
|
||||
"notes_header": "<b>Сохранённые заметки:</b>\n\n",
|
||||
"notes_item": "<b>▷</b> <code>{}</code>",
|
||||
"delnote_args": "<b>А какую заметку нужно удалить?</b>",
|
||||
"delnote_done": "<b>Заметка удалена!</b>",
|
||||
"delnotes_none": "<b>А заметок-то нету...</b>",
|
||||
"delnotes_done": "<b>ВСЕ ЗАМЕТКИ УДАЛЕНЫ</b>",
|
||||
"notes_none": "<b>А заметок-то нету...</b>"}
|
||||
|
||||
|
||||
async def findnotecmd(self, message):
|
||||
"""Gets the note specified"""
|
||||
args = utils.get_args(message)
|
||||
if not args:
|
||||
await utils.answer(message, self.strings("what_note", message))
|
||||
return
|
||||
asset_id = self._db.get("friendly-telegram.modules.notes", "notes", {}).get(args[0], None)
|
||||
logger.debug(asset_id)
|
||||
if asset_id is not None:
|
||||
asset = await self._db.fetch_asset(asset_id)
|
||||
else:
|
||||
asset = None
|
||||
if asset is None:
|
||||
self.del_note(args[0])
|
||||
await utils.answer(message, self.strings("no_note", message))
|
||||
return
|
||||
link = "https://t.me/c/{}/{}".format(asset.chat.id, asset.id)
|
||||
await message.edit(f'<b>Заметка</b> "<code>{args[0]}</code>" <a href="{link}">находится здесь.</a>')
|
||||
|
||||
|
||||
|
||||
async def notecmd(self, message):
|
||||
"""Gets the note specified"""
|
||||
args = utils.get_args(message)
|
||||
if not args:
|
||||
await utils.answer(message, self.strings("what_note", message))
|
||||
return
|
||||
asset_id = self._db.get("friendly-telegram.modules.notes", "notes", {}).get(args[0], None)
|
||||
logger.debug(asset_id)
|
||||
if asset_id is not None:
|
||||
asset = await self._db.fetch_asset(asset_id)
|
||||
else:
|
||||
asset = None
|
||||
if asset is None:
|
||||
self.del_note(args[0])
|
||||
await utils.answer(message, self.strings("no_note", message))
|
||||
return
|
||||
await message.delete()
|
||||
await message.client.send_message(message.to_id, await self._db.fetch_asset(asset_id), reply_to=await message.get_reply_message())
|
||||
|
||||
async def delallnotescmd(self, message):
|
||||
"""Deletes all the saved notes"""
|
||||
if not self._db.get("friendly-telegram.modules.notes", "notes", {}):
|
||||
await utils.answer(message, self.strings("delnotes_none", message))
|
||||
return
|
||||
self._db.get("friendly-telegram.modules.notes", "notes", {}).clear()
|
||||
await utils.answer(message, self.strings("delnotes_done", message))
|
||||
|
||||
async def savecmd(self, message):
|
||||
"""Save a new note. Must be used in reply with one parameter (note name)"""
|
||||
args = utils.get_args(message)
|
||||
if not args:
|
||||
await utils.answer(message, self.strings("what_name", message))
|
||||
return
|
||||
if not message.is_reply:
|
||||
if len(args) < 2:
|
||||
await utils.answer(message, self.strings("save_what", message))
|
||||
return
|
||||
else:
|
||||
message.entities = None
|
||||
message.message = args[1]
|
||||
target = message
|
||||
logger.debug(target.message)
|
||||
else:
|
||||
target = await message.get_reply_message()
|
||||
asset_id = await self._db.store_asset(target)
|
||||
self._db.set("friendly-telegram.modules.notes", "notes", {**self._db.get("friendly-telegram.modules.notes", "notes", {}), args[0]: asset_id})
|
||||
await utils.answer(message, str(self.strings("saved", message)).format(args[0]))
|
||||
|
||||
async def delnotecmd(self, message):
|
||||
"""Deletes a note, specified by note name"""
|
||||
args = utils.get_args(message)
|
||||
if not args:
|
||||
await utils.answer(message, self.strings("delnote_args", message))
|
||||
self.del_note(args[0])
|
||||
await utils.answer(message, self.strings("delnote_done", message))
|
||||
|
||||
def del_note(self, note):
|
||||
old = self._db.get("friendly-telegram.modules.notes", "notes", {})
|
||||
try:
|
||||
del old[note]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
self._db.set("friendly-telegram.modules.notes", "notes", old)
|
||||
|
||||
async def notescmd(self, message):
|
||||
"""List the saved notes"""
|
||||
if not self._db.get("friendly-telegram.modules.notes", "notes", {}):
|
||||
await utils.answer(message, self.strings("notes_none", message))
|
||||
return
|
||||
await utils.answer(message, self.strings("notes_header", message)
|
||||
+ "\n".join(self.strings("notes_item", message).format(key)
|
||||
for key in self._db.get("friendly-telegram.modules.notes", "notes", {})))
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self._db = db
|
||||
95
KeyZenD/modules/notexec.py
Normal file
95
KeyZenD/modules/notexec.py
Normal file
@@ -0,0 +1,95 @@
|
||||
# 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 traceback
|
||||
import sys
|
||||
import itertools
|
||||
import types
|
||||
from meval import meval
|
||||
|
||||
import telethon
|
||||
|
||||
from .. import loader, utils
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@loader.tds
|
||||
class ExecutorMod(loader.Module):
|
||||
"""Stores global notes (aka snips)"""
|
||||
strings = {"name": "Notexec",
|
||||
"what_note": "<b>What notexec should be executed?</b>",
|
||||
"no_note": "<b>Notexec not found</b>",
|
||||
"execute_fail": ("<b>Failed to execute expression:</b>\n<code>{}</code>")
|
||||
}
|
||||
async def notexeccmd(self, message):
|
||||
"""Gets the note specified"""
|
||||
args = utils.get_args(message)
|
||||
if not args:
|
||||
await utils.answer(message, self.strings("what_note", message))
|
||||
return
|
||||
|
||||
asset_id = self._db.get("friendly-telegram.modules.notes", "notes", {}).get(args[0], None)
|
||||
logger.debug(asset_id)
|
||||
if asset_id is not None:
|
||||
asset = await self._db.fetch_asset(asset_id)
|
||||
else:
|
||||
asset_id = self._db.get("friendly-telegram.modules.notes", "notes", {}).get(args[0].lower(), None)
|
||||
if asset_id is not None:
|
||||
asset = await self._db.fetch_asset(asset_id)
|
||||
else:
|
||||
asset = None
|
||||
if asset is None:
|
||||
await utils.answer(message, self.strings("no_note", message))
|
||||
return
|
||||
|
||||
cmd = await self._db.fetch_asset(asset_id)
|
||||
|
||||
try:
|
||||
await meval(cmd.raw_text, globals(), **await self.getattrs(message))
|
||||
except Exception:
|
||||
exc = sys.exc_info()
|
||||
exc = "".join(traceback.format_exception(exc[0], exc[1], exc[2].tb_next.tb_next.tb_next))
|
||||
await utils.answer(message, self.strings("execute_fail", message)
|
||||
.format(utils.escape_html(exc)))
|
||||
return
|
||||
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
self.db = db
|
||||
self._db = db
|
||||
|
||||
async def getattrs(self, message):
|
||||
return {"message": message, "client": self.client, "self": self, "db": self.db,
|
||||
"reply": await message.get_reply_message(), "event": message,"chat": message.to_id , **self.get_types(), **self.get_functions()}
|
||||
|
||||
def get_types(self):
|
||||
return self.get_sub(telethon.tl.types)
|
||||
|
||||
def get_functions(self):
|
||||
return self.get_sub(telethon.tl.functions)
|
||||
|
||||
def get_sub(self, it, _depth=1):
|
||||
"""Get all callable capitalised objects in an object recursively, ignoring _*"""
|
||||
return {**dict(filter(lambda x: x[0][0] != "_" and x[0][0].upper() == x[0][0] and callable(x[1]),
|
||||
it.__dict__.items())),
|
||||
**dict(itertools.chain.from_iterable([self.get_sub(y[1], _depth + 1).items() for y in
|
||||
filter(lambda x: x[0][0] != "_"
|
||||
and isinstance(x[1], types.ModuleType)
|
||||
and x[1] != it
|
||||
and x[1].__package__.rsplit(".", _depth)[0]
|
||||
== "telethon.tl",
|
||||
it.__dict__.items())]))}
|
||||
5
KeyZenD/modules/null.py
Normal file
5
KeyZenD/modules/null.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from .. import loader
|
||||
class nullMod(loader.Module):
|
||||
strings = {"name": "null"}
|
||||
async def nullcmd(self, message):
|
||||
await message.edit("null")
|
||||
61
KeyZenD/modules/ph.py
Normal file
61
KeyZenD/modules/ph.py
Normal file
@@ -0,0 +1,61 @@
|
||||
from .. import loader, utils
|
||||
import asyncio
|
||||
import requests
|
||||
from telethon.tl.types import DocumentAttributeFilename
|
||||
|
||||
def register(cb):
|
||||
cb(UploadPHMod())
|
||||
|
||||
# @KeyZenD pls sub :3
|
||||
|
||||
class UploadPHMod(loader.Module):
|
||||
"""Upload video and photo to telegra.ph"""
|
||||
strings = {"name": "UploadPH"}
|
||||
|
||||
def __init__(self):
|
||||
self.name = self.strings['name']
|
||||
|
||||
|
||||
async def phcmd(self, message):
|
||||
""".ph <reply photo or video>"""
|
||||
if message.is_reply:
|
||||
reply_message = await message.get_reply_message()
|
||||
data = await check_media(reply_message)
|
||||
if isinstance(data, bool):
|
||||
await message.edit("<b>Reply to photo or video/gif</b>")
|
||||
return
|
||||
else:
|
||||
await message.edit("<b>Reply to photo or video/gif</b>")
|
||||
return
|
||||
|
||||
|
||||
file = await message.client.download_media(data, bytes)
|
||||
path = requests.post('https://te.legra.ph/upload', files={'file': ('file', file, None)}).json()
|
||||
try:
|
||||
link = 'https://te.legra.ph'+path[0]['src']
|
||||
except KeyError:
|
||||
link = path["error"]
|
||||
await message.edit("<b>"+link+"</b>")
|
||||
|
||||
|
||||
async def check_media(reply_message):
|
||||
if reply_message and reply_message.media:
|
||||
if reply_message.photo:
|
||||
data = reply_message.photo
|
||||
elif reply_message.document:
|
||||
if DocumentAttributeFilename(file_name='AnimatedSticker.tgs') in reply_message.media.document.attributes:
|
||||
return False
|
||||
if reply_message.audio or reply_message.voice:
|
||||
return False
|
||||
data = reply_message.media.document
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
if not data or data is None:
|
||||
return False
|
||||
else:
|
||||
return data
|
||||
|
||||
|
||||
|
||||
125
KeyZenD/modules/pic2pack.py
Normal file
125
KeyZenD/modules/pic2pack.py
Normal file
@@ -0,0 +1,125 @@
|
||||
from telethon import events
|
||||
from telethon.errors.rpcerrorlist import YouBlockedUserError
|
||||
from .. import loader, utils
|
||||
import string
|
||||
import random
|
||||
from PIL import Image
|
||||
import io
|
||||
from asyncio import sleep
|
||||
|
||||
def register(cb):
|
||||
cb(pic2packMod())
|
||||
|
||||
|
||||
class pic2packMod(loader.Module):
|
||||
"""pic2pack"""
|
||||
|
||||
strings = {'name': 'pic2pack'}
|
||||
|
||||
def __init__(self):
|
||||
self.name = self.strings['name']
|
||||
self._me = None
|
||||
self._ratelimit = []
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self._db = db
|
||||
self._client = client
|
||||
self.me = await client.get_me()
|
||||
|
||||
async def pic2packcmd(self, message):
|
||||
""".pic2pack {packname} + <reply to photo>"""
|
||||
|
||||
reply = await message.get_reply_message()
|
||||
if not reply:
|
||||
await message.edit("<b>Reply to photo❗</b>")
|
||||
return
|
||||
|
||||
args = utils.get_args_raw(message)
|
||||
if not args:
|
||||
await message.edit("<b>Packname</b>❓")
|
||||
return
|
||||
chat = '@Stickers'
|
||||
name = "".join([random.choice(list(string.ascii_lowercase+string.ascii_uppercase)) for _ in range(16)])
|
||||
emoji = "▫️"
|
||||
image = io.BytesIO()
|
||||
await message.client.download_file(reply, image)
|
||||
image = Image.open(image)
|
||||
w, h = image.size
|
||||
www = max(w, h)
|
||||
await message.edit("🔪<b>Cropping...</b>")
|
||||
img = Image.new("RGBA", (www,www), (0,0,0,0))
|
||||
img.paste(image, ((www-w)//2, 0))
|
||||
face = img.resize((100,100))
|
||||
fface = io.BytesIO()
|
||||
fface.name = name+".png"
|
||||
images = await cropping(img)
|
||||
face.save(fface)
|
||||
fface.seek(0)
|
||||
await message.edit("<b>📤Uploading...</b>")
|
||||
async with message.client.conversation(chat) as conv:
|
||||
try:
|
||||
x = await message.client.send_message(chat, "/cancel")
|
||||
await (await conv.wait_event(events.NewMessage(incoming=True, from_users=chat))).delete()
|
||||
await x.delete()
|
||||
x = await message.client.send_message(chat, "/newpack")
|
||||
await (await conv.wait_event(events.NewMessage(incoming=True, from_users=chat))).delete()
|
||||
await x.delete()
|
||||
x = await message.client.send_message(chat, args)
|
||||
await (await conv.wait_event(events.NewMessage(incoming=True, from_users=chat))).delete()
|
||||
await x.delete()
|
||||
|
||||
for im in images:
|
||||
blank = io.BytesIO(im)
|
||||
blank.name = name+".png"
|
||||
blank.seek(0)
|
||||
x = await message.client.send_file(chat, blank, force_document=True)
|
||||
await (await conv.wait_event(events.NewMessage(incoming=True, from_users=chat))).delete()
|
||||
await x.delete()
|
||||
x = await message.client.send_message(chat, emoji)
|
||||
await (await conv.wait_event(events.NewMessage(incoming=True, from_users=chat))).delete()
|
||||
await x.delete()
|
||||
|
||||
|
||||
|
||||
x = await message.client.send_message(chat, "/publish")
|
||||
await (await conv.wait_event(events.NewMessage(incoming=True, from_users=chat))).delete()
|
||||
await x.delete()
|
||||
x = await message.client.send_file(chat, fface, force_document=True)
|
||||
await (await conv.wait_event(events.NewMessage(incoming=True, from_users=chat))).delete()
|
||||
await x.delete()
|
||||
x = await message.client.send_message(chat, name)
|
||||
ending = await conv.wait_event(events.NewMessage(incoming=True, from_users=chat))
|
||||
await x.delete()
|
||||
await ending.delete()
|
||||
for part in ending.raw_text.split():
|
||||
if part.startswith("https://t.me/"):
|
||||
break
|
||||
await message.edit('✅<b>Uploaded successful!</b>\n'+part)
|
||||
|
||||
except YouBlockedUserError:
|
||||
await message.edit('<b>@Stickers BLOCKED⛔</b>')
|
||||
return
|
||||
|
||||
|
||||
async def cropping(img):
|
||||
(x, y) = img.size
|
||||
cy = 5
|
||||
cx = 5
|
||||
sx = x//cx
|
||||
sy = y//cy
|
||||
if (sx*cx, sy*cy) != (x, y):
|
||||
img = img.resize((sx*cx, sy*cy))
|
||||
(lx, ly) = (0, 0)
|
||||
media = []
|
||||
for i in range(1, cy+1):
|
||||
for o in range(1, cx+1):
|
||||
mimg = img.crop((lx, ly, lx+sx, ly+sy))
|
||||
mimg = mimg.resize((512,512))
|
||||
bio = io.BytesIO()
|
||||
bio.name = 'image.png'
|
||||
mimg.save(bio, 'PNG')
|
||||
media.append(bio.getvalue())
|
||||
lx = lx + sx
|
||||
lx = 0
|
||||
ly = ly + sy
|
||||
return media
|
||||
23
KeyZenD/modules/print.py
Normal file
23
KeyZenD/modules/print.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from .. import loader, utils
|
||||
from asyncio import sleep
|
||||
@loader.tds
|
||||
class PrintMod(loader.Module):
|
||||
"""Аналог модуля typewriter"""
|
||||
strings = {"name": "print"}
|
||||
@loader.owner
|
||||
async def printcmd(self, message):
|
||||
""".print <text or reply>"""
|
||||
text = utils.get_args_raw(message)
|
||||
if not text:
|
||||
reply = await message.get_reply_message()
|
||||
if not reply or not reply.message:
|
||||
await message.edit("<b>Текста нет!</b>")
|
||||
return
|
||||
text = reply.message
|
||||
out = ""
|
||||
for ch in text:
|
||||
out += ch
|
||||
if ch not in [" ", "\n"]:
|
||||
await message.edit(out+"\u2060")
|
||||
await sleep(0.3)
|
||||
|
||||
44
KeyZenD/modules/pung.py
Normal file
44
KeyZenD/modules/pung.py
Normal file
@@ -0,0 +1,44 @@
|
||||
from telethon import events
|
||||
from telethon.errors.rpcerrorlist import YouBlockedUserError
|
||||
from .. import loader, utils
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
def register(cb):
|
||||
cb(PingerMod())
|
||||
|
||||
|
||||
class PingerMod(loader.Module):
|
||||
"""более точный пинг"""
|
||||
|
||||
strings = {'name': 'PingerХуингер'}
|
||||
|
||||
def __init__(self):
|
||||
self.name = self.strings['name']
|
||||
self._me = None
|
||||
self._ratelimit = []
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self._db = db
|
||||
self._client = client
|
||||
self.me = await client.get_me()
|
||||
|
||||
async def pingcmd(self, message):
|
||||
"""пингует"""
|
||||
a = 5
|
||||
r = utils.get_args(message)
|
||||
if r and r[0].isdigit():
|
||||
a = int(r[0])
|
||||
ping_msg = []
|
||||
ping_data = []
|
||||
for _ in range(a):
|
||||
start = datetime.now()
|
||||
msg = await message.client.send_message("me", "ping")
|
||||
end = datetime.now()
|
||||
duration = (end - start).microseconds / 1000
|
||||
ping_data.append(duration)
|
||||
ping_msg.append(msg)
|
||||
ping = sum(ping_data) / len(ping_data)
|
||||
await message.edit(f"[ok] {str(ping)[0:5]}ms")
|
||||
for i in ping_msg:
|
||||
await i.delete()
|
||||
79
KeyZenD/modules/purge.py
Normal file
79
KeyZenD/modules/purge.py
Normal file
@@ -0,0 +1,79 @@
|
||||
from .. import loader, utils
|
||||
import logging
|
||||
import telethon
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@loader.tds
|
||||
class PurgeMod(loader.Module):
|
||||
"""Deletes your messages"""
|
||||
strings = {"name": "Purge",
|
||||
"from_where": "<b>Which messages should be purged?</b>",
|
||||
"not_supergroup_bot": "<b>Purges can only take place in supergroups</b>",
|
||||
"delete_what": "<b>What message should be deleted?</b>"}
|
||||
|
||||
@loader.group_admin_delete_messages
|
||||
@loader.ratelimit
|
||||
async def purgecmd(self, message):
|
||||
"""Purge from the replied message"""
|
||||
if not message.is_reply:
|
||||
await utils.answer(message, self.strings("from_where", message))
|
||||
return
|
||||
|
||||
from_users = set()
|
||||
args = utils.get_args(message)
|
||||
for arg in args:
|
||||
try:
|
||||
entity = await message.client.get_entity(arg)
|
||||
if isinstance(entity, telethon.tl.types.User):
|
||||
from_users.add(entity.id)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
msgs = []
|
||||
from_ids = set()
|
||||
if await message.client.is_bot():
|
||||
if not message.is_channel:
|
||||
await utils.answer(message, self.strings("not_supergroup_bot", message))
|
||||
return
|
||||
for msg in range(message.reply_to_msg_id, message.id + 1):
|
||||
msgs.append(msg)
|
||||
if len(msgs) >= 99:
|
||||
logger.debug(msgs)
|
||||
await message.client.delete_messages(message.to_id, msgs)
|
||||
msgs.clear()
|
||||
else:
|
||||
async for msg in message.client.iter_messages(
|
||||
entity=message.to_id,
|
||||
min_id=message.reply_to_msg_id - 1,
|
||||
reverse=True):
|
||||
if from_users and msg.sender_id not in from_users:
|
||||
continue
|
||||
msgs.append(msg.id)
|
||||
from_ids.add(msg.sender_id)
|
||||
if len(msgs) >= 99:
|
||||
logger.debug(msgs)
|
||||
await message.client.delete_messages(message.to_id, msgs)
|
||||
msgs.clear()
|
||||
if msgs:
|
||||
logger.debug(msgs)
|
||||
await message.client.delete_messages(message.to_id, msgs)
|
||||
await self.allmodules.log("purge", group=message.to_id, affected_uids=from_ids)
|
||||
|
||||
@loader.group_admin_delete_messages
|
||||
@loader.ratelimit
|
||||
async def delcmd(self, message):
|
||||
"""Delete the replied message"""
|
||||
msgs = [message.id]
|
||||
if not message.is_reply:
|
||||
if await message.client.is_bot():
|
||||
await utils.answer(message, self.strings("delete_what", message))
|
||||
return
|
||||
msg = await message.client.iter_messages(message.to_id, 1, max_id=message.id).__anext__()
|
||||
else:
|
||||
msg = await message.get_reply_message()
|
||||
msgs.append(msg.id)
|
||||
logger.debug(msgs)
|
||||
await message.client.delete_messages(message.to_id, msgs)
|
||||
await self.allmodules.log("delete", group=message.to_id, affected_uids=[msg.sender_id])
|
||||
117
KeyZenD/modules/pydraft.py
Normal file
117
KeyZenD/modules/pydraft.py
Normal file
@@ -0,0 +1,117 @@
|
||||
import asyncio
|
||||
import itertools
|
||||
import logging
|
||||
import re
|
||||
import sys
|
||||
import telethon
|
||||
import traceback
|
||||
import types
|
||||
from meval import meval
|
||||
from .. import loader, utils
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ModuleNotForBot(Exception):
|
||||
pass
|
||||
|
||||
|
||||
@loader.tds
|
||||
class PyDraftMod(loader.Module):
|
||||
"""Выполняет выражение из черновиков (работает 10 минут)
|
||||
инструкция на канале @SomeScripts"""
|
||||
strings = {
|
||||
'name': 'PyDraft',
|
||||
'on': 'PyDraft: Включен',
|
||||
'off': 'PyDraft: Отключен',
|
||||
'isolator': 'pydraft:',
|
||||
'timer': 60 * 10,
|
||||
'note': '(PyDraft) ExecNote {} не найден!',
|
||||
"evaluated": "(PyDratf)Выполненное выражение:\n{}\nВозвращено:\n{}",
|
||||
"execute_fail": "(PyDraft)Не удалось выполнить выражение:\n{}\nОшибка:\n{}"}
|
||||
|
||||
def __init__(self):
|
||||
self.name = self.strings['name']
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client: telethon.client.telegramclient.TelegramClient = client
|
||||
self.db = db
|
||||
self._db = db
|
||||
|
||||
async def pydraftcmd(self, message):
|
||||
"""Запустить/Остановить"""
|
||||
status = self.db.get(self.name, "status", False)
|
||||
if not status:
|
||||
self.db.set(self.name, "status", True)
|
||||
self.client.loop.create_task(self.check_drafts(message))
|
||||
await utils.answer(message, self.strings['on'])
|
||||
else:
|
||||
self.db.set(self.name, 'status', False)
|
||||
await utils.answer(message, self.strings['off'])
|
||||
|
||||
async def pydraft(self, draft):
|
||||
show = True if draft.text.startswith('!') else False
|
||||
cmd = draft.text[len(self.strings['isolator'])+(1 if show else 0):].strip()
|
||||
if cmd.startswith('note:'):
|
||||
asset_id = self._db.get("friendly-telegram.modules.notes", "notes", {}).get(cmd.replace('note:', ''), None)
|
||||
if asset_id is not None:
|
||||
cmd = await self._db.fetch_asset(asset_id)
|
||||
|
||||
await draft.delete()
|
||||
try:
|
||||
it = await meval(cmd, globals(), **await self.getattrs(draft))
|
||||
if show:
|
||||
ret = self.strings["evaluated"].format(cmd, utils.escape_html(it))
|
||||
await draft.set_message(ret)
|
||||
except Exception:
|
||||
exc = sys.exc_info()
|
||||
exc = "".join(traceback.format_exception(exc[0], exc[1], exc[2].tb_next.tb_next.tb_next))
|
||||
await draft.set_message(self.strings["execute_fail"].format(cmd, exc))
|
||||
return
|
||||
|
||||
async def check_drafts(self, message):
|
||||
msg = await self.client.send_message('me', 'PyDraft')
|
||||
timer = 0
|
||||
while True:
|
||||
await msg.edit(f"PyDraft time left {self.strings['timer']-timer}")
|
||||
if not self.db.get(self.name, "status", False):
|
||||
await utils.answer(message, self.strings['off'])
|
||||
break
|
||||
isolator = self.strings['isolator']
|
||||
drafts = await self.client.get_drafts()
|
||||
for draft in drafts:
|
||||
text = draft.text
|
||||
if text.startswith(isolator) or text.startswith('!' + isolator):
|
||||
await self.pydraft(draft)
|
||||
timer += 1
|
||||
await asyncio.sleep(1)
|
||||
if timer >= self.strings['timer']:
|
||||
self.db.set(self.name, 'status', False)
|
||||
await utils.answer(message, self.strings['off'])
|
||||
break
|
||||
await msg.delete()
|
||||
|
||||
async def getattrs(self, draft):
|
||||
data = {'draft':draft, "client": self.client, "self": self, "db": self.db, "chat": draft.entity.id, **self.get_types(), **self.get_functions()}
|
||||
if draft.reply_to_msg_id:
|
||||
data['message'] = await self.client.get_messages(draft.entity.id, ids=draft.reply_to_msg_id)
|
||||
data['reply'] = await data['message'].get_reply_message()
|
||||
return data
|
||||
|
||||
def get_types(self):
|
||||
return self.get_sub(telethon.tl.types)
|
||||
|
||||
def get_functions(self):
|
||||
return self.get_sub(telethon.tl.functions)
|
||||
|
||||
def get_sub(self, it, _depth=1):
|
||||
"""Get all callable capitalised objects in an object recursively, ignoring _*"""
|
||||
return {**dict(filter(lambda x: x[0][0] != "_" and x[0][0].upper() == x[0][0] and callable(x[1]),
|
||||
it.__dict__.items())),
|
||||
**dict(itertools.chain.from_iterable([self.get_sub(y[1], _depth + 1).items() for y in
|
||||
filter(lambda x: x[0][0] != "_"
|
||||
and isinstance(x[1], types.ModuleType)
|
||||
and x[1] != it
|
||||
and x[1].__package__.rsplit(".", _depth)[0]
|
||||
== "telethon.tl",
|
||||
it.__dict__.items())]))}
|
||||
43
KeyZenD/modules/pypng.py
Normal file
43
KeyZenD/modules/pypng.py
Normal file
@@ -0,0 +1,43 @@
|
||||
from .. import loader, utils # pylint: disable=relative-beyond-top-level
|
||||
import logging
|
||||
import pygments
|
||||
from pygments.lexers import Python3Lexer
|
||||
from pygments.formatters import ImageFormatter
|
||||
import os
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def register(cb):
|
||||
cb(py2pngMod())
|
||||
|
||||
|
||||
@loader.tds
|
||||
class py2pngMod(loader.Module):
|
||||
"""Uploader"""
|
||||
strings = {
|
||||
"name": "pypng"
|
||||
}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
|
||||
|
||||
@loader.sudo
|
||||
async def pypngcmd(self, message):
|
||||
"""reply to text code or py file"""
|
||||
await message.edit("<b>Py to PNG</b>")
|
||||
reply = await message.get_reply_message()
|
||||
if not reply:
|
||||
await message.edit("<b>reply to file.py</b>")
|
||||
return
|
||||
media = reply.media
|
||||
if not media:
|
||||
await message.edit("<b>reply to file.py</b>")
|
||||
return
|
||||
file = await message.client.download_file(media)
|
||||
text = file.decode('utf-8')
|
||||
pygments.highlight(text, Python3Lexer(), ImageFormatter(font_name='DejaVu Sans Mono', line_numbers=True), 'out.png')
|
||||
await message.client.send_file(message.to_id, 'out.png', force_document=True)
|
||||
os.remove("out.png")
|
||||
await message.delete()
|
||||
100
KeyZenD/modules/python.py
Normal file
100
KeyZenD/modules/python.py
Normal file
@@ -0,0 +1,100 @@
|
||||
# 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 traceback
|
||||
import sys
|
||||
import itertools
|
||||
import types
|
||||
from meval import meval
|
||||
|
||||
import telethon
|
||||
|
||||
from .. import loader, utils
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@loader.tds
|
||||
class PythonMod(loader.Module):
|
||||
"""Python stuff"""
|
||||
strings = {"name": "Python",
|
||||
"evaluated": "<b>Выполненное выражение:</b>\n<code>{}</code>\n<b>Возвращено:</b>\n<code>{}</code>",
|
||||
"evaluate_fail": ("<b>(eval)Не удалось выполнить выражение:</b>\n<code>{}</code>"
|
||||
"\n\n<b>Ошибка:</b>\n<code>{}</code>"),
|
||||
"execute_fail": ("<b>(exec)Не удалось выполнить выражение:</b>\n<code>{}</code>"
|
||||
"\n\n<b>Ошибка:</b>\n<code>{}</code>")}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
self.db = db
|
||||
|
||||
@loader.owner
|
||||
async def evalcmd(self, message):
|
||||
""".eval <expression>
|
||||
Evaluates python code"""
|
||||
phone = message.client.phone
|
||||
ret = self.strings("evaluated", message)
|
||||
try:
|
||||
it = await meval(utils.get_args_raw(message), globals(), **await self.getattrs(message))
|
||||
except Exception:
|
||||
exc = sys.exc_info()
|
||||
exc = "".join(traceback.format_exception(exc[0], exc[1], exc[2].tb_next.tb_next.tb_next))
|
||||
exc = exc.replace(phone, "❚"*len(phone))
|
||||
await utils.answer(message, self.strings("evaluate_fail", message)
|
||||
.format(utils.escape_html(utils.get_args_raw(message)), utils.escape_html(exc)))
|
||||
return
|
||||
ret = ret.format(utils.escape_html(utils.get_args_raw(message)), utils.escape_html(it))
|
||||
ret = ret.replace(str(phone), "❚"*len(str(phone)))
|
||||
await utils.answer(message, ret)
|
||||
|
||||
@loader.owner
|
||||
async def execcmd(self, message):
|
||||
""".exec <expression>
|
||||
Executes python code"""
|
||||
phone = message.client.phone
|
||||
try:
|
||||
await meval(utils.get_args_raw(message), globals(), **await self.getattrs(message))
|
||||
except Exception:
|
||||
exc = sys.exc_info()
|
||||
exc = "".join(traceback.format_exception(exc[0], exc[1], exc[2].tb_next.tb_next.tb_next))
|
||||
exc = exc.replace(str(phone), "❚"*len(str(phone)))
|
||||
await utils.answer(message, self.strings("execute_fail", message)
|
||||
.format(utils.escape_html(utils.get_args_raw(message)), utils.escape_html(exc)))
|
||||
return
|
||||
|
||||
async def getattrs(self, message):
|
||||
return {"message": message, "client": self.client, "self": self, "db": self.db,
|
||||
"reply": await message.get_reply_message(), **self.get_types(), **self.get_functions(),
|
||||
"event": message, "chat": message.to_id}
|
||||
|
||||
def get_types(self):
|
||||
return self.get_sub(telethon.tl.types)
|
||||
|
||||
def get_functions(self):
|
||||
return self.get_sub(telethon.tl.functions)
|
||||
|
||||
def get_sub(self, it, _depth=1):
|
||||
"""Get all callable capitalised objects in an object recursively, ignoring _*"""
|
||||
return {**dict(filter(lambda x: x[0][0] != "_" and x[0][0].upper() == x[0][0] and callable(x[1]),
|
||||
it.__dict__.items())),
|
||||
**dict(itertools.chain.from_iterable([self.get_sub(y[1], _depth + 1).items() for y in
|
||||
filter(lambda x: x[0][0] != "_"
|
||||
and isinstance(x[1], types.ModuleType)
|
||||
and x[1] != it
|
||||
and x[1].__package__.rsplit(".", _depth)[0]
|
||||
== "telethon.tl",
|
||||
it.__dict__.items())]))}
|
||||
40
KeyZenD/modules/rysianskiy.py
Normal file
40
KeyZenD/modules/rysianskiy.py
Normal file
@@ -0,0 +1,40 @@
|
||||
import logging
|
||||
from .. import loader, utils
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@loader.tds
|
||||
class RysianskiyMod(loader.Module):
|
||||
"""Perevodit rysskiy na rysianskiy yazyk"""
|
||||
strings = {"name": "Rysianskiy yazyk",
|
||||
"nety_teksta": "<b>Nety teksta dlya izmeneniya!</b>"}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
|
||||
@loader.owner
|
||||
async def rysianskiycmd(self, soobshenie):
|
||||
""".rysianskiy <tekst ili replay na tekst>"""
|
||||
|
||||
otvet = await soobshenie.get_reply_message()
|
||||
vvod = utils.get_args_raw(soobshenie)
|
||||
if not vvod:
|
||||
if not otvet or not otvet.text:
|
||||
await utils.answer(soobshenie, self.strings("nety_teksta", soobshenie))
|
||||
return
|
||||
else:
|
||||
tekst = otvet.raw_text
|
||||
else:
|
||||
tekst = vvod
|
||||
vyvod = ""
|
||||
for simvol in tekst:
|
||||
if simvol.lower() in bykvy:
|
||||
bykva = bykvy[simvol.lower()]
|
||||
if simvol.isupper():
|
||||
bykva = bykva.upper()
|
||||
else:
|
||||
bykva = simvol
|
||||
vyvod += bykva
|
||||
await utils.answer(soobshenie, vyvod)
|
||||
bykvy = {"а": "a", "б": "b", "в": "v", "г": "g", "д": "d", "е": "e", "ё": "yo", "ж": "j", "з": "z", "и": "i", "й": "y", "к": "k", "л": "l", "м": "m", "н": "n", "о": "o", "п": "p", "р": "r", "с": "s", "т": "t", "у": "y", "ф": "f", "х": "h", "ц": "ts", "ч": "ch", "ш": "sh", "щ": "sh'", "ъ": '"', "ы": "y", "ь": "'", "э": "e", "ю": "yu", "я": "ya"}
|
||||
24
KeyZenD/modules/saved.py
Normal file
24
KeyZenD/modules/saved.py
Normal file
@@ -0,0 +1,24 @@
|
||||
import io
|
||||
from .. import loader, utils
|
||||
|
||||
@loader.tds
|
||||
class SavedMod(loader.Module):
|
||||
"""Соxранятель в избранное"""
|
||||
strings = {"name": "SavedMessages", "to":"me"}
|
||||
@loader.unrestricted
|
||||
async def savedcmd(self, message):
|
||||
""".saved реплай на медиа"""
|
||||
await message.delete()
|
||||
reply = await message.get_reply_message()
|
||||
name = utils.get_args_raw(message)
|
||||
if not reply or not reply.file:
|
||||
return
|
||||
media = reply.media
|
||||
if media.ttl_seconds or name:
|
||||
file = await reply.download_media(bytes)
|
||||
file = io.BytesIO(file)
|
||||
file.name = name or str(reply.sender_id) + reply.file.ext
|
||||
file.seek(0)
|
||||
await message.client.send_file(self.strings["to"], file)
|
||||
else:
|
||||
await reply.forward_to(self.strings["to"])
|
||||
34
KeyZenD/modules/scrs.py
Normal file
34
KeyZenD/modules/scrs.py
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
from .. import loader, utils
|
||||
from telethon import events, errors, functions, types
|
||||
|
||||
def register(cb):
|
||||
cb(ScrSpamMod())
|
||||
|
||||
|
||||
class ScrSpamMod(loader.Module):
|
||||
"""Screenshot Spammer by @KeyZenD"""
|
||||
|
||||
strings = {'name': 'ScrSpam'}
|
||||
|
||||
def __init__(self):
|
||||
self.name = self.strings['name']
|
||||
self._me = None
|
||||
self._ratelimit = []
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self._db = db
|
||||
self._client = client
|
||||
self.me = await client.get_me()
|
||||
|
||||
async def scrscmd(self, message):
|
||||
""".scrs <amount>"""
|
||||
a = 1
|
||||
r = utils.get_args(message)
|
||||
if r and r[0].isdigit():
|
||||
a = int(r[0])
|
||||
await message.edit("Screenshoting...")
|
||||
for _ in range(a):
|
||||
await message.client(functions.messages.SendScreenshotNotificationRequest(peer=message.to_id, reply_to_msg_id=message.id))
|
||||
await message.delete()
|
||||
|
||||
106
KeyZenD/modules/soaper.py
Normal file
106
KeyZenD/modules/soaper.py
Normal file
@@ -0,0 +1,106 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Friendly Telegram (telegram userbot)
|
||||
# Copyright (C) 2018-2020 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.
|
||||
# если не подписан на t.me/keyzend
|
||||
# твоя мама шлюха
|
||||
# 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 # pylint: disable=relative-beyond-top-level
|
||||
import io
|
||||
from PIL import Image, ImageOps
|
||||
from telethon.tl.types import DocumentAttributeFilename
|
||||
import logging
|
||||
import random
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def register(cb):
|
||||
cb(SoaperMod())
|
||||
|
||||
|
||||
@loader.tds
|
||||
class SoaperMod(loader.Module):
|
||||
"""Гавно залупное"""
|
||||
strings = {
|
||||
"name": "Soaping"
|
||||
}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
|
||||
|
||||
@loader.sudo
|
||||
async def soapcmd(self, message):
|
||||
""".soap <reply to photo>"""
|
||||
soap = 3
|
||||
a = utils.get_args(message)
|
||||
if a:
|
||||
if a[0].isdigit():
|
||||
soap = int(a[0])
|
||||
if soap <= 0:
|
||||
soap = 3
|
||||
|
||||
if message.is_reply:
|
||||
reply_message = await message.get_reply_message()
|
||||
data = await check_media(reply_message)
|
||||
if isinstance(data, bool):
|
||||
await utils.answer(message, "<code>Reply to pic or stick!</code>")
|
||||
return
|
||||
else:
|
||||
await utils.answer(message, "<code>Reply to pic or stick!</code>")
|
||||
return
|
||||
|
||||
await message.edit("Soaping...")
|
||||
file = await self.client.download_media(data, bytes)
|
||||
media = await Soaping(file, soap)
|
||||
await message.delete()
|
||||
|
||||
await message.client.send_file(message.to_id, media)
|
||||
|
||||
|
||||
|
||||
|
||||
async def Soaping(file, soap):
|
||||
img = Image.open(io.BytesIO(file))
|
||||
(x, y) = img.size
|
||||
img = img.resize((x//soap, y//soap), Image.ANTIALIAS)
|
||||
img = img.resize((x, y))
|
||||
soap_io = io.BytesIO()
|
||||
soap_io.name = "image.jpeg"
|
||||
img = img.convert("RGB")
|
||||
img.save(soap_io, "JPEG", quality=100)
|
||||
soap_io.seek(0)
|
||||
return soap_io
|
||||
|
||||
|
||||
async def check_media(reply_message):
|
||||
if reply_message and reply_message.media:
|
||||
if reply_message.photo:
|
||||
data = reply_message.photo
|
||||
elif reply_message.document:
|
||||
if DocumentAttributeFilename(file_name='AnimatedSticker.tgs') in reply_message.media.document.attributes:
|
||||
return False
|
||||
if reply_message.gif or reply_message.video or reply_message.audio or reply_message.voice:
|
||||
return False
|
||||
data = reply_message.media.document
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
if not data or data is None:
|
||||
return False
|
||||
else:
|
||||
return data
|
||||
123
KeyZenD/modules/spinner.py
Normal file
123
KeyZenD/modules/spinner.py
Normal file
@@ -0,0 +1,123 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Friendly Telegram (telegram userbot)
|
||||
# Copyright (C) 2018-2020 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/>.
|
||||
|
||||
from .. import loader, utils # pylint: disable=relative-beyond-top-level
|
||||
import io
|
||||
from PIL import Image, ImageOps
|
||||
from telethon.tl.types import DocumentAttributeFilename
|
||||
import logging
|
||||
import random
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def register(cb):
|
||||
cb(SpinnerMod())
|
||||
|
||||
|
||||
@loader.tds
|
||||
class SpinnerMod(loader.Module):
|
||||
"""Гавно залупное"""
|
||||
strings = {
|
||||
"name": "Spinner"
|
||||
}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
|
||||
@loader.sudo
|
||||
async def spincmd(self, message):
|
||||
"""you spin me round..."""
|
||||
args = utils.get_args(message)
|
||||
|
||||
if message.is_reply:
|
||||
reply_message = await message.get_reply_message()
|
||||
data = await check_media(reply_message)
|
||||
if isinstance(data, bool):
|
||||
await utils.answer(message, "<code>Реплай на пикчу или стикер блять!</code>")
|
||||
return
|
||||
else:
|
||||
await utils.answer(message, "`Реплай на пикчу или стикер блять`")
|
||||
return
|
||||
|
||||
image = io.BytesIO()
|
||||
await self.client.download_media(data, image)
|
||||
image = Image.open(image)
|
||||
image.thumbnail((512, 512), Image.ANTIALIAS)
|
||||
img = Image.new("RGB", (512, 512), "black")
|
||||
img.paste(image, ((512-image.width)//2, (512-image.height)//2))
|
||||
image = img
|
||||
way = random.choice([1, -1])
|
||||
frames = []
|
||||
for i in range(1, 60):
|
||||
im = image.rotate(i*6*way)
|
||||
frames.append(im)
|
||||
frames.remove(im)
|
||||
|
||||
image_stream = io.BytesIO()
|
||||
image_stream.name = "spin.gif"
|
||||
im.save(image_stream, "GIF", save_all=True, append_images=frames, duration = 10)
|
||||
image_stream.seek(0)
|
||||
await utils.answer(message, image_stream)
|
||||
|
||||
@loader.sudo
|
||||
async def epilepsycmd(self, message):
|
||||
"""ПРИВЕТ ЭПИЛЕТИКИ АХАХАХХА"""
|
||||
args = utils.get_args(message)
|
||||
|
||||
if message.is_reply:
|
||||
reply_message = await message.get_reply_message()
|
||||
data = await check_media(reply_message)
|
||||
if isinstance(data, bool):
|
||||
await utils.answer(message, "<code>Реплай на пикчу или стикер блять!</code>")
|
||||
return
|
||||
else:
|
||||
await utils.answer(message, "`Реплай на пикчу или стикер блять`")
|
||||
return
|
||||
|
||||
image = io.BytesIO()
|
||||
await self.client.download_media(data, image)
|
||||
image = Image.open(image).convert("RGB")
|
||||
invert = ImageOps.invert(image)
|
||||
|
||||
image_stream = io.BytesIO()
|
||||
image_stream.name = "epilepsy.gif"
|
||||
image.save(image_stream, "GIF", save_all=True, append_images=[invert], duration = 1)
|
||||
image_stream.seek(0)
|
||||
await utils.answer(message, image_stream)
|
||||
|
||||
|
||||
|
||||
async def check_media(reply_message):
|
||||
if reply_message and reply_message.media:
|
||||
if reply_message.photo:
|
||||
data = reply_message.photo
|
||||
elif reply_message.document:
|
||||
if DocumentAttributeFilename(file_name='AnimatedSticker.tgs') in reply_message.media.document.attributes:
|
||||
return False
|
||||
if reply_message.gif or reply_message.video or reply_message.audio or reply_message.voice:
|
||||
return False
|
||||
data = reply_message.media.document
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
if not data or data is None:
|
||||
return False
|
||||
else:
|
||||
return data
|
||||
63
KeyZenD/modules/stext.py
Normal file
63
KeyZenD/modules/stext.py
Normal file
@@ -0,0 +1,63 @@
|
||||
from .. import loader, utils
|
||||
import io
|
||||
import logging
|
||||
import requests
|
||||
from textwrap import wrap
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
bytes_font = requests.get("https://github.com/KeyZenD/l/blob/master/bold.ttf?raw=true").content
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def register(cb):
|
||||
cb(Text2stickMod())
|
||||
|
||||
@loader.tds
|
||||
class Text2stickMod(loader.Module):
|
||||
"""Text to sticker"""
|
||||
strings = {"name": "StickText"}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
|
||||
@loader.owner
|
||||
async def stextcmd(self, message):
|
||||
""".stext <reply to photo>"""
|
||||
await message.delete()
|
||||
text = utils.get_args_raw(message)
|
||||
reply = await message.get_reply_message()
|
||||
if not text:
|
||||
if not reply:
|
||||
text = "#ffffff .stext <text or reply>"
|
||||
elif not reply.message:
|
||||
text = "#ffffff .stext <text or reply>"
|
||||
else:
|
||||
text = reply.raw_text
|
||||
color = text.split(" ", 1)[0]
|
||||
if color.startswith("#") and len(color) == 7:
|
||||
for ch in color.lower()[1:]:
|
||||
if ch not in "0123456789abcdef":
|
||||
break
|
||||
if len(text.split(" ", 1)) > 1:
|
||||
text = text.split(" ", 1)[1]
|
||||
else:
|
||||
if reply:
|
||||
if reply.message:
|
||||
text = reply.raw_text
|
||||
else:
|
||||
color = "#FFFFFF"
|
||||
txt = []
|
||||
for line in text.split("\n"):
|
||||
txt.append("\n".join(wrap(line, 30)))
|
||||
text = "\n".join(txt)
|
||||
font = io.BytesIO(bytes_font)
|
||||
font = ImageFont.truetype(font, 100)
|
||||
image = Image.new("RGBA", (1, 1), (0,0,0,0))
|
||||
draw = ImageDraw.Draw(image)
|
||||
w, h = draw.multiline_textsize(text=text, font=font)
|
||||
image = Image.new("RGBA", (w+100, h+100), (0,0,0,0))
|
||||
draw = ImageDraw.Draw(image)
|
||||
draw.multiline_text((50,50), text=text, font=font, fill=color, align="center")
|
||||
output = io.BytesIO()
|
||||
output.name = color+".webp"
|
||||
image.save(output, "WEBP")
|
||||
output.seek(0)
|
||||
await self.client.send_file(message.to_id, output, reply_to=reply)
|
||||
52
KeyZenD/modules/tagall.py
Normal file
52
KeyZenD/modules/tagall.py
Normal file
@@ -0,0 +1,52 @@
|
||||
from .. import loader, utils
|
||||
import logging
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def register(cb):
|
||||
cb(TagallMod())
|
||||
|
||||
|
||||
@loader.tds
|
||||
class TagallMod(loader.Module):
|
||||
"""Tagall"""
|
||||
strings = {
|
||||
"name": "TagAll", "subscribe to": "https://t.me/KeyZenD"
|
||||
}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
|
||||
def __init__(self):
|
||||
self.name = self.strings['name']
|
||||
|
||||
|
||||
|
||||
@loader.sudo
|
||||
async def tagallcmd(self, message):
|
||||
args = utils.get_args(message)
|
||||
tag_ = 5
|
||||
notext = False
|
||||
if args:
|
||||
if args[0].isdigit():
|
||||
tag_ = int(args[0])
|
||||
if len(args) > 1:
|
||||
notext = True
|
||||
text = " ".join(args[1:])
|
||||
|
||||
await message.delete()
|
||||
all = message.client.iter_participants(message.to_id)
|
||||
chunk = []
|
||||
async for user in all:
|
||||
if not user.deleted:
|
||||
name = f"{user.first_name} {user.last_name}" if user.last_name else user.first_name
|
||||
name = name.replace("<","<").replace(">",">")
|
||||
name = name[:30]+"..." if len(name) > 33 else name
|
||||
tag = f'<a href="tg://user?id={user.id}">{name}</a>' if not notext else f'<a href="tg://user?id={user.id}">{text}</a>'
|
||||
chunk.append(tag)
|
||||
if len(chunk) == tag_:
|
||||
await message.client.send_message(message.to_id, "\n".join(chunk))
|
||||
chunk = []
|
||||
if len(chunk) != 0:
|
||||
await message.client.send_message(message.to_id, "\n".join(chunk))
|
||||
132
KeyZenD/modules/test.py
Normal file
132
KeyZenD/modules/test.py
Normal file
@@ -0,0 +1,132 @@
|
||||
# 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 time
|
||||
from datetime import datetime
|
||||
|
||||
from io import BytesIO
|
||||
|
||||
from .. import loader, utils
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@loader.test(args=None)
|
||||
async def dumptest(conv):
|
||||
m = await conv.send_message("test")
|
||||
await conv.send_message(".dump", reply_to=m)
|
||||
r = await conv.get_response()
|
||||
assert r.message.startswith("Message(") and "test" in r.message, r
|
||||
|
||||
|
||||
@loader.test(args="0")
|
||||
async def logstest(conv):
|
||||
r = await conv.get_response()
|
||||
assert r.message == "Loading media...", r
|
||||
r2 = await conv.get_response()
|
||||
assert r2.document, r2
|
||||
|
||||
|
||||
@loader.tds
|
||||
class TestMod(loader.Module):
|
||||
"""Self-tests"""
|
||||
strings = {"name": "Tester",
|
||||
"pong": ".pong",
|
||||
"bad_loglevel": "<b>Не верный уровень логов.</b>",
|
||||
"uploading_logs": "<b>Собираю логи...</b>",
|
||||
"no_logs": "<b>Логов с уровнем {} нет.</b>",
|
||||
"logs_filename": "FTG-Logs[{}].txt",
|
||||
"logs_unsafe": ("<b>Если ты точно хочешь показать логи с уровнем {lvl}, то напиши </b><code>.logs {lvl} {force}</code>"),
|
||||
"logs_force": "FORCE_INSECURE",
|
||||
"suspend_invalid_time": "<b>Invalid time to suspend</b>"}
|
||||
|
||||
@loader.test(resp="Pong")
|
||||
@loader.unrestricted
|
||||
async def pingcmd(self, message):
|
||||
"""Does nothing"""
|
||||
await utils.answer(message, self.strings("pong", message))
|
||||
|
||||
@loader.owner
|
||||
async def pungcmd(self, message):
|
||||
"""Useless pinger"""
|
||||
a = 5
|
||||
r = utils.get_args(message)
|
||||
if r and r[0].isdigit():
|
||||
a = int(r[0])
|
||||
ping_msg = []
|
||||
ping_data = []
|
||||
for _ in range(a):
|
||||
start = datetime.now()
|
||||
msg = await message.client.send_message("me", "ping")
|
||||
end = datetime.now()
|
||||
duration = (end - start).microseconds / 1000
|
||||
ping_data.append(duration)
|
||||
ping_msg.append(msg)
|
||||
ping = sum(ping_data) / len(ping_data)
|
||||
await message.edit(f"<code>[ ping {str(ping)[0:5]}ms ]</code>")
|
||||
for i in ping_msg:
|
||||
await i.delete()
|
||||
|
||||
@loader.test(func=dumptest)
|
||||
async def dumpcmd(self, message):
|
||||
"""Use in reply to get a dump of a message"""
|
||||
if not message.is_reply:
|
||||
return
|
||||
await utils.answer(message, "<code>"
|
||||
+ utils.escape_html((await message.get_reply_message()).stringify()) + "</code>")
|
||||
|
||||
@loader.test(func=logstest)
|
||||
async def logscmd(self, message):
|
||||
""".logs <level>
|
||||
Dumps logs. Loglevels below WARNING may contain personal info."""
|
||||
args = utils.get_args(message)
|
||||
if not len(args) == 1 and not len(args) == 2:
|
||||
args = ["40"]
|
||||
try:
|
||||
lvl = int(args[0])
|
||||
except ValueError:
|
||||
# It's not an int. Maybe it's a loglevel
|
||||
lvl = getattr(logging, args[0].upper(), None)
|
||||
if not isinstance(lvl, int):
|
||||
await utils.answer(message, self.strings("bad_loglevel", message))
|
||||
return
|
||||
if not (lvl >= logging.WARNING or (len(args) == 2 and args[1] == self.strings("logs_force", message))):
|
||||
await utils.answer(message,
|
||||
self.strings("logs_unsafe", message).format(lvl=lvl, force=self.strings("logs_force", message)))
|
||||
return
|
||||
[handler] = logging.getLogger().handlers
|
||||
logs = ("\n".join(handler.dumps(lvl))).encode("utf-8")
|
||||
if not len(logs) > 0:
|
||||
await utils.answer(message, self.strings("no_logs", message).format(lvl))
|
||||
return
|
||||
logs = BytesIO(logs)
|
||||
logs.name = self.strings("logs_filename", message).format(lvl)
|
||||
await utils.answer(message, logs)
|
||||
|
||||
@loader.owner
|
||||
async def suspendcmd(self, message):
|
||||
""".suspend <time>
|
||||
Suspends the bot for N seconds"""
|
||||
# Blocks asyncio event loop, preventing ANYTHING happening (except multithread ops,
|
||||
# but they will be blocked on return).
|
||||
try:
|
||||
time.sleep(int(utils.get_args_raw(message)))
|
||||
except ValueError:
|
||||
await utils.answer(message, self.strings("suspend_invalid_time", message))
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
45
KeyZenD/modules/ticker.py
Normal file
45
KeyZenD/modules/ticker.py
Normal file
@@ -0,0 +1,45 @@
|
||||
# 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.
|
||||
# SUBSCRIBE TO t.me/keyzend pls
|
||||
# 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 asyncio
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@loader.tds
|
||||
class TickerMod(loader.Module):
|
||||
"""Makes your messages type slower"""
|
||||
strings = {"name": "Ticker",
|
||||
"no_message": "<b>.ticker [any text?]</b>",
|
||||
"delay_typer_cfg_doc": "How long to delay showing?"}
|
||||
|
||||
def __init__(self):
|
||||
self.config = loader.ModuleConfig("DELAY_TICKER", 0.04, lambda m: self.strings("delay_tikcer_cfg_doc", m))
|
||||
|
||||
@loader.ratelimit
|
||||
async def tickercmd(self, message):
|
||||
""".ticker <message>"""
|
||||
a = utils.get_args_raw(message)
|
||||
if not a:
|
||||
await utils.answer(message, self.strings("no_message", message))
|
||||
return
|
||||
for c in a:
|
||||
a = a[-1]+a[0:-1]
|
||||
message = await utils.answer(message, f" {a} ")
|
||||
await asyncio.sleep(0.3)
|
||||
31
KeyZenD/modules/ttdl.py
Normal file
31
KeyZenD/modules/ttdl.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from requests import head,get
|
||||
from urllib.parse import urlsplit as E,parse_qs as H
|
||||
import json,io,re
|
||||
from .. import loader as A,utils
|
||||
class TikTokDlMod(A.Module):
|
||||
strings={'name':'TikTokDl'}
|
||||
async def ttcmd(J,message):
|
||||
A=message;B=await A.get_reply_message();F=utils.get_args_raw(A);C=lambda x:f"<b>{x}</b>"
|
||||
if F:D=F
|
||||
elif B and B.raw_text:D=B.raw_text
|
||||
else:return await A.edit(C('No url.'))
|
||||
if'.tiktok.com'not in D:return await A.edit(C('Bad url.'))
|
||||
await A.edit(C('Loading...'));G,K=await I(D)
|
||||
try:await A.client.send_file(A.to_id,file=G,reply_to=B);await A.delete()
|
||||
except:
|
||||
try:await A.edit(C('DownLoading...'));H=get(G).content;E=io.BytesIO(H);E.name='video.mp4';E.seek(0);await A.client.send_file(A.to_id,file=E,reply_to=B);await A.delete()
|
||||
except:await A.edit(C('я чёт нихуя не могу загрузить...'))
|
||||
async def I(url):
|
||||
A=url
|
||||
async def F(video_id,_):
|
||||
A=f"https://api-va.tiktokv.com/aweme/v1/multi/aweme/detail/?aweme_ids=%5B{video_id}%5D";A=get(A);B=A.json().get('aweme_details')
|
||||
if not B:return 0,0,A
|
||||
return B,True,A
|
||||
A=head(A).headers;A=A.get('Location')
|
||||
try:
|
||||
I=H(E(A).query);B=I.get('share_item_id')[0];G,C,D=await F(B,1)
|
||||
if not C:raise
|
||||
except:
|
||||
B=''.join(re.findall('[0-9]',E(A).path.split('/')[-1]));G,C,D=await F(B,2)
|
||||
if not C:return False,D
|
||||
return G[0]['video']['bit_rate'][0]['play_addr']['url_list'][-1],D
|
||||
72
KeyZenD/modules/urldl.py
Normal file
72
KeyZenD/modules/urldl.py
Normal file
@@ -0,0 +1,72 @@
|
||||
from .. import loader, utils
|
||||
import io
|
||||
from telethon.tl.types import MessageEntityUrl, MessageEntityTextUrl
|
||||
import os
|
||||
import aiohttp
|
||||
|
||||
class aMod(loader.Module):
|
||||
strings = {"name": "UrlDl"}
|
||||
|
||||
async def urldlcmd(self, event):
|
||||
await downloading(event)
|
||||
|
||||
async def urldlbigcmd(self, event):
|
||||
await downloading(event, True)
|
||||
|
||||
async def downloading(event, big=False):
|
||||
args = utils.get_args_raw(event)
|
||||
reply = await event.get_reply_message()
|
||||
if not args:
|
||||
if not reply:
|
||||
await event.edit("<b>Ссылки нету!</b>")
|
||||
return
|
||||
message = reply
|
||||
else:
|
||||
message = event
|
||||
|
||||
if not message.entities:
|
||||
await event.edit("<b>Ссылки нету!</b>")
|
||||
return
|
||||
|
||||
urls = []
|
||||
for ent in message.entities:
|
||||
if type(ent) in [MessageEntityUrl, MessageEntityTextUrl]:
|
||||
url_ = True
|
||||
if type(ent) == MessageEntityUrl:
|
||||
offset = ent.offset
|
||||
length = ent.length
|
||||
url = message.raw_text[offset:offset+length]
|
||||
else:
|
||||
url = ent.url
|
||||
if not url.startswith("http"):
|
||||
url = "http://"+url
|
||||
urls.append(url)
|
||||
|
||||
if not urls:
|
||||
await event.edit("<b>Ссылки нету!</b>")
|
||||
return
|
||||
async with aiohttp.ClientSession() as session:
|
||||
for url in urls:
|
||||
try:
|
||||
await event.edit("<b>Загрузка...</b>\n"+url)
|
||||
fname = url.split("/")[-1]
|
||||
async with session.get(url) as response:
|
||||
if big:
|
||||
f = open(fname, "wb")
|
||||
async for chunk in response.content.iter_chunked(1024):
|
||||
f.write(chunk)
|
||||
f.close()
|
||||
await event.edit("<b>Отправка...</b>\n"+url)
|
||||
await event.client.send_file(event.to_id, open(fname, "rb"), reply_to=reply)
|
||||
os.remove(fname)
|
||||
else:
|
||||
file = io.BytesIO(await response.read())
|
||||
file.name = fname
|
||||
file.seek(0)
|
||||
await event.edit("<b>Отправка...</b>\n"+url)
|
||||
await event.client.send_file(event.to_id, file, reply_to=reply)
|
||||
|
||||
except Exception as e:
|
||||
await event.reply("<b>Ошибка при загрузке!</b>\n"+url+"\n<code>"+str(e)+"</code>")
|
||||
|
||||
await event.delete()
|
||||
41
KeyZenD/modules/valute.py
Normal file
41
KeyZenD/modules/valute.py
Normal file
@@ -0,0 +1,41 @@
|
||||
import asyncio
|
||||
import logging
|
||||
from requests import get
|
||||
from .. import loader, utils
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@loader.tds
|
||||
class ValitesMod(loader.Module):
|
||||
"""Valute converter"""
|
||||
strings = {"name": "Valutes"}
|
||||
|
||||
@loader.unrestricted
|
||||
async def valutecmd(self, message):
|
||||
""".valute <Valute char code (optional)>"""
|
||||
valutes = get("https://www.cbr-xml-daily.ru/daily_json.js").json()
|
||||
names = valutes["Valute"].keys()
|
||||
args = utils.get_args(message)
|
||||
req = []
|
||||
|
||||
if args:
|
||||
for val in args:
|
||||
val = val.upper()
|
||||
if val in names:
|
||||
req.append(val)
|
||||
valutes["Valute"] = {val: valutes["Valute"][val] for val in req}
|
||||
|
||||
text = []
|
||||
temp = "<b>{}</b>\n{} <code>{}</code>: {}₽ ({}{}₽)"
|
||||
for val in valutes["Valute"].values():
|
||||
name = val["Name"]
|
||||
code = val["CharCode"]
|
||||
nom = int(val["Nominal"])
|
||||
now = round(float(val["Value"]), 3)
|
||||
pre = round(float(val["Previous"]), 3)
|
||||
way = "🔹" if now == pre else "🔻" if now < pre else "🔺"
|
||||
text.append(temp.format(name, nom, code, now, way, pre))
|
||||
if not text:
|
||||
return await utils.answer(message, "<b>Запрос неверен - ответ пуст!</b>")
|
||||
await utils.answer(message, "\n".join(text))
|
||||
48
KeyZenD/modules/webshot.py
Normal file
48
KeyZenD/modules/webshot.py
Normal file
@@ -0,0 +1,48 @@
|
||||
from .. import loader, utils
|
||||
import logging
|
||||
from requests import get
|
||||
import io
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def register(cb):
|
||||
cb(WebShotMod())
|
||||
|
||||
|
||||
@loader.tds
|
||||
class WebShotMod(loader.Module):
|
||||
"""link to screen"""
|
||||
strings = {
|
||||
"name": "WebShot"
|
||||
}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
|
||||
def __init__(self):
|
||||
self.name = self.strings['name']
|
||||
|
||||
|
||||
|
||||
@loader.sudo
|
||||
async def webshotcmd(self, message):
|
||||
reply = None
|
||||
link = utils.get_args_raw(message)
|
||||
if not link:
|
||||
reply = await message.get_reply_message()
|
||||
if not reply:
|
||||
await message.delete()
|
||||
return
|
||||
link = reply.raw_text
|
||||
await message.edit("<b>S c r e e n s h o t i n g . . .</b>")
|
||||
url = "https://webshot.deam.io/{}/?width=1920&height=1080?type=png"
|
||||
file = get(url.format(link))
|
||||
if not file.ok:
|
||||
await message.edit("<b>Something went wrong...</b>")
|
||||
return
|
||||
file = io.BytesIO(file.content)
|
||||
file.name = "webshot.png"
|
||||
file.seek(0)
|
||||
await message.client.send_file(message.to_id, file, reply_to=reply)
|
||||
await message.delete()
|
||||
37
KeyZenD/modules/what.py
Normal file
37
KeyZenD/modules/what.py
Normal file
@@ -0,0 +1,37 @@
|
||||
from .. import loader, utils
|
||||
from PIL import Image, ImageDraw
|
||||
from random import randint
|
||||
from io import BytesIO
|
||||
|
||||
|
||||
@loader.tds
|
||||
class WhatMod(loader.Module):
|
||||
"""wow, what is it there?"""
|
||||
strings = {"name": "What?"}
|
||||
|
||||
async def whatcmd(self, message):
|
||||
"""Draw circle in random place"""
|
||||
args = utils.get_args_raw(message)
|
||||
scale = int(args) if args and args.isdigit() else 50
|
||||
scale = 10 if scale < 0 else scale
|
||||
scale = 100 if scale > 100 else scale
|
||||
reply = await message.get_reply_message()
|
||||
if not reply or not reply.file.mime_type.split("/")[0].lower() == "image":
|
||||
await message.edit("<b>Reply to img!</b>")
|
||||
return
|
||||
await message.edit("<b>What is it?</b>")
|
||||
im = BytesIO()
|
||||
await reply.download_media(im)
|
||||
im = Image.open(im)
|
||||
w, h = im.size
|
||||
f = (min(w,h)//100)*scale
|
||||
draw = ImageDraw.Draw(im)
|
||||
x, y = randint(0, w-f), randint(0, h-f)
|
||||
draw.ellipse((x, y, x+randint(f//2, f), y+randint(f//2, f)), fill=None, outline="red", width=randint(3, 10))
|
||||
out = BytesIO()
|
||||
out.name = "what.png"
|
||||
im.save(out)
|
||||
out.seek(0)
|
||||
await message.delete()
|
||||
return await reply.reply(file=out)
|
||||
|
||||
30
KeyZenD/modules/words.py
Normal file
30
KeyZenD/modules/words.py
Normal file
@@ -0,0 +1,30 @@
|
||||
from .. import loader
|
||||
import io
|
||||
|
||||
class WordsMod(loader.Module):
|
||||
strings = {"name": "Words Counter"}
|
||||
|
||||
async def wordscmd(self, message):
|
||||
reply = await message.get_reply_message()
|
||||
object = reply.sender_id if reply else message.sender_id
|
||||
chat = message.to_id
|
||||
|
||||
await message.edit("<b>Сбор статистики...</b>")
|
||||
|
||||
_words = {}
|
||||
|
||||
async for msg in message.client.iter_messages(chat, from_user=object):
|
||||
if msg and msg.raw_text:
|
||||
words = set("".join(map(lambda x: x if (x in [" "] or x.isalpha()) else " ", msg.raw_text)).lower().split())
|
||||
for word in words:
|
||||
count = msg.raw_text.lower().count(word)
|
||||
_words[word] = _words.get(word, 0) + count
|
||||
all = list(_words.items())
|
||||
all.sort(key=lambda i: i[1])
|
||||
response = ""
|
||||
for word in all[::-1]:
|
||||
response += f"{word[0]}: {word[1]}\n"
|
||||
file = io.BytesIO(bytes(response, "utf-8"))
|
||||
file.name = f"ID:{object}.txt"
|
||||
await message.reply(file=file)
|
||||
await message.delete()
|
||||
111
KeyZenD/modules/zip.py
Normal file
111
KeyZenD/modules/zip.py
Normal file
@@ -0,0 +1,111 @@
|
||||
from .. import loader, utils
|
||||
import os
|
||||
import urllib.parse
|
||||
from uuid import uuid4
|
||||
|
||||
ztd = 'zip-temp-dir'
|
||||
|
||||
@loader.tds
|
||||
class ZipMod(loader.Module):
|
||||
'''Запаковывает/распаковывает файлы'''
|
||||
strings = {'name': 'ZIP'}
|
||||
|
||||
@loader.unrestricted
|
||||
async def zipaddcmd(self, message):
|
||||
""".zipadd <file/reply to file> - сохраняет файл во временную папку"""
|
||||
reply = await message.get_reply_message()
|
||||
event = reply or message
|
||||
|
||||
if not event.file:
|
||||
await message.edit('<b>[ZIP]Добавить что?<b>')
|
||||
return
|
||||
|
||||
if not os.path.exists(ztd):
|
||||
os.mkdir(ztd)
|
||||
|
||||
fn = _fn = event.file.name
|
||||
if not fn:
|
||||
date = event.date
|
||||
kind = event.file.mime_type.split('/')[0]
|
||||
ext = event.file.ext
|
||||
fn = _fn = '{}_{}-{:02}-{:02}_{:02}-{:02}-{:02}{}'.format(kind, date.year, date.month, date.day, date.hour, date.minute, date.second, ext)
|
||||
|
||||
files = os.listdir(ztd)
|
||||
copy = 1
|
||||
while fn in files:
|
||||
fn = f"({copy}).{_fn}"
|
||||
copy += 1
|
||||
await message.edit(f'<b>[ZIP]Загружаю файл \'</b><code>{fn}</code>\'...')
|
||||
await event.download_media(f'{ztd}/{fn}')
|
||||
await message.edit(f"<b>[ZIP]Файл \"</b><code>{fn}</code><b>\" загружен!</b>")
|
||||
|
||||
@loader.unrestricted
|
||||
async def ziplistcmd(self, message):
|
||||
"""список сохраненных файлов"""
|
||||
if not os.path.exists(ztd):
|
||||
await message.edit('<b>[ZIP]В папке пусто!</b>')
|
||||
return
|
||||
files = os.listdir(ztd)
|
||||
files = '\n'.join([f'<a href="tg://msg?text=.zipshow+{urllib.parse.quote(fn)}">{num+1})</a> <code>{fn}</code>' for num, fn in enumerate(files)])
|
||||
await message.edit('<b>[ZIP]Список файлов:</b>\n'+files)
|
||||
|
||||
@loader.unrestricted
|
||||
async def zipshowcmd(self, message):
|
||||
""".zipshow <name> - показывает сохранённый файл"""
|
||||
if not os.path.exists(ztd):
|
||||
await message.edit('<b>[ZIP]В папке пусто!</b>')
|
||||
return
|
||||
files = os.listdir(ztd)
|
||||
file = utils.get_args_raw(message)
|
||||
if not file:
|
||||
await message.edit('<b>[ZIP]Пустой запрос!</b>')
|
||||
return
|
||||
if file not in files:
|
||||
await message.edit('<b>[ZIP]Такого файла нет!</b>')
|
||||
return
|
||||
await message.edit(f"<b>[ZIP]Отправляю \"</b><code>{file}</code><b>\"...")
|
||||
await message.respond(file=ztd+"/"+file)
|
||||
await message.delete()
|
||||
|
||||
@loader.unrestricted
|
||||
async def zipdelcmd(self, message):
|
||||
""".zipdel <name> - удаляет сохранённый файл"""
|
||||
file = utils.get_args_raw(message)
|
||||
try:
|
||||
os.remove(ztd+"/"+file)
|
||||
except FileNotFoundError:
|
||||
await message.edit("<b>[ZIP]Такого файла нет!</b>")
|
||||
return
|
||||
await message.edit(f"<b>[ZIP]Файл \"</b><code>{file}</code><b>\" удалён!</b>")
|
||||
|
||||
|
||||
@loader.unrestricted
|
||||
async def zipcmd(self, message):
|
||||
""".zip <name> (-s) - пакует в архив name. если есть флаг -s то сохраняет папку с фацлами"""
|
||||
if not os.path.exists(ztd):
|
||||
await message.edit("<b>[ZIP]Файлов для запаковки не найдено!</b>")
|
||||
return
|
||||
name = utils.get_args_raw(message)
|
||||
save = False
|
||||
if "-s" in name:
|
||||
save = True
|
||||
name = name.replace("-s","").strip()
|
||||
if not name:
|
||||
name = str(uuid4()).split("-")[-1]+".zip"
|
||||
|
||||
name = name + (".zip" if ".zip" not in name else "")
|
||||
await message.edit(f'<b>[ZIP]Запаковываю {len(os.listdir(ztd))} файл(ов) в </b>"<code>{name}</code>"')
|
||||
os.system(f"zip {name} {ztd}/*")
|
||||
await message.edit(f'<b>[ZIP]Отправляю </b>"<code>{name}</code>"')
|
||||
await message.respond(file=open(name, "rb"))
|
||||
await message.delete()
|
||||
os.system("rm -rf {name}")
|
||||
if not save:
|
||||
os.system("rm -rf zip-temp-dir")
|
||||
|
||||
@loader.unrestricted
|
||||
async def zipcleancmd(self, message):
|
||||
""".zipclear - очищает папку с файлами"""
|
||||
os.system("rm -rf zip-temp-dir")
|
||||
await message.edit('<b>[ZIP]Очищено!</b>')
|
||||
os.mkdir(ztd)
|
||||
32
KeyZenD/modules/заёбушка.py
Normal file
32
KeyZenD/modules/заёбушка.py
Normal file
@@ -0,0 +1,32 @@
|
||||
from asyncio import sleep
|
||||
from .. import loader, utils
|
||||
|
||||
def register(cb):
|
||||
cb(ЗаёбушкаMod())
|
||||
|
||||
class ЗаёбушкаMod(loader.Module):
|
||||
"""Заебет любого"""
|
||||
strings = {'name': 'Заёбушка'}
|
||||
|
||||
async def заебуcmd(self, message):
|
||||
""".заебу <колличество> <реплай на того, кого заебать>"""
|
||||
reply = await message.get_reply_message()
|
||||
if not reply:
|
||||
await message.edit("<b>А кого заёбывать-то?</b>")
|
||||
return
|
||||
id = reply.sender_id
|
||||
args = utils.get_args(message)
|
||||
count = 50
|
||||
if args:
|
||||
if args[0].isdigit():
|
||||
if int(args[0]) < 0:
|
||||
count = 50
|
||||
else:
|
||||
count = int(args[0])
|
||||
txt = '<a href="tg://user?id={}">Заёбушка :3</a>'.format(id)
|
||||
await message.delete()
|
||||
for _ in range(count):
|
||||
await sleep(0.3)
|
||||
msg = await message.client.send_message(message.to_id, txt)
|
||||
await sleep(0.3)
|
||||
await msg.delete()
|
||||
41
KeyZenD/modules/заёбушка2.0.py
Normal file
41
KeyZenD/modules/заёбушка2.0.py
Normal file
@@ -0,0 +1,41 @@
|
||||
from asyncio import sleep
|
||||
from .. import loader, utils
|
||||
|
||||
def register(cb):
|
||||
cb(ЗаёбушкаMod())
|
||||
|
||||
class ЗаёбушкаMod(loader.Module):
|
||||
"""Заебет любого"""
|
||||
strings = {'name': 'Заёбушка'}
|
||||
def __init__(self):
|
||||
self.name = self.strings['name']
|
||||
self._me = None
|
||||
self._ratelimit = []
|
||||
|
||||
async def заебуcmd(self, message):
|
||||
""".заебу <колличество> <реплай на того, кого заебать>"""
|
||||
reply = await message.get_reply_message()
|
||||
if not reply:
|
||||
await message.edit("<b>А кого заёбывать-то?</b>")
|
||||
return
|
||||
id = reply.sender_id
|
||||
args = utils.get_args(message)
|
||||
count = 50
|
||||
if args:
|
||||
if args[0].isdigit():
|
||||
if int(args[0]) < 0:
|
||||
count = 50
|
||||
else:
|
||||
count = int(args[0])
|
||||
txt = '<a href="tg://user?id={}">{}</a>'
|
||||
await message.edit(txt.format(id, "Я тебя заебу!"))
|
||||
for _ in range(count):
|
||||
await sleep(0.3)
|
||||
msg = await message.client.send_message(message.to_id, txt.format(id, "Заёбушка:3"), reply_to=message)
|
||||
if not msg.is_reply:
|
||||
await msg.edit("<b>Остановлено!</b>")
|
||||
break
|
||||
await sleep(0.3)
|
||||
await msg.delete()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user