second init
This commit is contained in:
commit
10aa70702c
16
.editorconfig
Normal file
16
.editorconfig
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.py]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Pyrogram files
|
||||||
|
*.session
|
||||||
|
*.session-journal
|
||||||
|
|
||||||
|
# App
|
||||||
|
.env
|
||||||
|
db.sqlite
|
16
LICENSE
Normal file
16
LICENSE
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
MIT No Attribution
|
||||||
|
|
||||||
|
Copyright 2024 Alexander Popov
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||||
|
software and associated documentation files (the "Software"), to deal in the Software
|
||||||
|
without restriction, including without limitation the rights to use, copy, modify,
|
||||||
|
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
3
README.md
Normal file
3
README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# TODO
|
||||||
|
|
||||||
|
- [ ] Добавить уведомления, если что-то пошло не так
|
27
app/__init__.py
Normal file
27
app/__init__.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Информация о программе
|
||||||
|
__author__ = 'Alexander Popov'
|
||||||
|
__version__ = (0, 0, 1)
|
||||||
|
|
||||||
|
# Импорт модулей стандартной библиотеки
|
||||||
|
from os import getenv
|
||||||
|
|
||||||
|
# Импорт сторонних модулей
|
||||||
|
from loguru import logger
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from pyrogram import Client
|
||||||
|
|
||||||
|
# Импорт модулей приложения
|
||||||
|
from .db import DataBase
|
||||||
|
|
||||||
|
load_dotenv() # Выполняет чтение .env
|
||||||
|
|
||||||
|
# Приложение
|
||||||
|
app = Client(getenv('ACCOUNT'), api_id=getenv('APP_ID'), api_hash=getenv('APP_HASH'))
|
||||||
|
|
||||||
|
# База данных
|
||||||
|
db = DataBase(getenv('DB_PATH'))
|
||||||
|
|
||||||
|
# Логгер
|
||||||
|
logger.add(getenv('LOG_PATH'), compression='zip')
|
||||||
|
|
||||||
|
BOT_NAME = '@anicardplaybot'
|
32
app/__main__.py
Normal file
32
app/__main__.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# Импорт модулей стандартной библиотеки
|
||||||
|
import time
|
||||||
|
|
||||||
|
# Импорт модулей приложения
|
||||||
|
from . import app, db, logger
|
||||||
|
from .actions import get_top_wins, get_top_donates
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
await app.start()
|
||||||
|
logger.info('Клиент Telegram запущен')
|
||||||
|
|
||||||
|
# Основной цикл программы
|
||||||
|
while True:
|
||||||
|
await get_top_wins() # Получает топ клана по победам
|
||||||
|
await get_top_donates() # Получает топ клана по пожертвованиям
|
||||||
|
|
||||||
|
time.sleep(12 * 60 * 60) # 12 часов
|
||||||
|
|
||||||
|
await app.stop()
|
||||||
|
logger.info('Клиент Telegram остановлен')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
logger.info('Выполняется запуск приложения')
|
||||||
|
|
||||||
|
logger.info('Выполняется подключение к базе данных')
|
||||||
|
db.connect()
|
||||||
|
|
||||||
|
app.run(main())
|
||||||
|
db.close()
|
||||||
|
logger.info('Приложение завершило работу')
|
76
app/actions.py
Normal file
76
app/actions.py
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
# Импорт модулей стандартной библиотеки
|
||||||
|
import time
|
||||||
|
|
||||||
|
# Импорт модулей приложения
|
||||||
|
from . import app, logger, BOT_NAME
|
||||||
|
from .collect import parse_wins_top, parse_donates_top
|
||||||
|
|
||||||
|
|
||||||
|
async def get_top_wins() -> None:
|
||||||
|
logger.info('Выполняется получения списка побед клана')
|
||||||
|
|
||||||
|
await app.send_message(BOT_NAME, '🛡 Мой клан')
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
message_id = 0
|
||||||
|
async for message in app.get_chat_history(BOT_NAME, limit=1):
|
||||||
|
message_id = message.id
|
||||||
|
|
||||||
|
await app.request_callback_answer(
|
||||||
|
chat_id=BOT_NAME,
|
||||||
|
message_id=message_id,
|
||||||
|
callback_data='my_clan:tops:91:0:0:0:0:1',
|
||||||
|
)
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
async for message in app.get_chat_history(BOT_NAME, limit=1):
|
||||||
|
message_id = message.id
|
||||||
|
|
||||||
|
await app.request_callback_answer(
|
||||||
|
chat_id=BOT_NAME,
|
||||||
|
message_id=message_id,
|
||||||
|
callback_data='my_clan:top-wins:91:0:0:0:0:1',
|
||||||
|
)
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
async for message in app.get_chat_history(BOT_NAME, limit=1):
|
||||||
|
parse_wins_top(message)
|
||||||
|
|
||||||
|
await app.read_chat_history(BOT_NAME)
|
||||||
|
|
||||||
|
logger.info('Получение списка побед клана завершено')
|
||||||
|
|
||||||
|
|
||||||
|
async def get_top_donates() -> None:
|
||||||
|
logger.info('Выполняется получения списка пожертвований клана')
|
||||||
|
|
||||||
|
await app.send_message(BOT_NAME, '🛡 Мой клан')
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
message_id = 0
|
||||||
|
async for message in app.get_chat_history(BOT_NAME, limit=1):
|
||||||
|
message_id = message.id
|
||||||
|
|
||||||
|
await app.request_callback_answer(
|
||||||
|
chat_id=BOT_NAME,
|
||||||
|
message_id=message_id,
|
||||||
|
callback_data='my_clan:tops:91:0:0:0:0:1',
|
||||||
|
)
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
async for message in app.get_chat_history(BOT_NAME, limit=1):
|
||||||
|
message_id = message.id
|
||||||
|
|
||||||
|
await app.request_callback_answer(
|
||||||
|
chat_id=BOT_NAME,
|
||||||
|
message_id=message_id,
|
||||||
|
callback_data='my_clan:top-donates:91:0:0:0:0:1',
|
||||||
|
)
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
async for message in app.get_chat_history(BOT_NAME, limit=1):
|
||||||
|
parse_donates_top(message)
|
||||||
|
|
||||||
|
await app.read_chat_history(BOT_NAME)
|
||||||
|
|
||||||
|
logger.info('Получение списка пожертвований клана завершено')
|
81
app/collect.py
Normal file
81
app/collect.py
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
# Импорт модулей стандартной библиотеки
|
||||||
|
import re
|
||||||
|
|
||||||
|
# Импорт сторонних модулей
|
||||||
|
from pyrogram.types import Message
|
||||||
|
|
||||||
|
# Импорт модулей приложения
|
||||||
|
from . import db
|
||||||
|
|
||||||
|
|
||||||
|
def parse_wins_top(message: Message) -> None:
|
||||||
|
if message.text.startswith('🏆 Топ по победам'):
|
||||||
|
gamers = message.text.split('\n')
|
||||||
|
gamers.pop(0)
|
||||||
|
gamers.pop(0)
|
||||||
|
|
||||||
|
WINS = list()
|
||||||
|
|
||||||
|
for idx, gamer in enumerate(gamers):
|
||||||
|
gamer = re.sub(r'^\d+. ', '', gamer) # удаляет нумерацию
|
||||||
|
gamer, battle_count = gamer.split(' - ') # разделяет ник и количество побед в клановых сражениях
|
||||||
|
|
||||||
|
# оставляет ники игроков, Python не может в эмодзи в RegExp, по этому пришлось делать через str.replace()
|
||||||
|
# gamer = re.sub(r'\s[⚡⚜]$', '', gamer)
|
||||||
|
gamer = gamer.replace(' ⚡', '')
|
||||||
|
gamer = gamer.replace(' ⚜', '')
|
||||||
|
|
||||||
|
battle_count = battle_count.replace(' ⚔', '') # удаляем эмодзи мечей
|
||||||
|
battle_count = int(re.sub(r'[^\x00-\x7F]', '', battle_count)) # преобразовывает строку в число
|
||||||
|
|
||||||
|
WINS.append(
|
||||||
|
{
|
||||||
|
'telegram_id': message.entities[idx].url.strip('http://t.me/'),
|
||||||
|
'username': gamer,
|
||||||
|
'count': battle_count,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# print('{0} - {1} (@{2})'.format(gamer, battle_count, message.entities[idx].url.strip('http://t.me/')))
|
||||||
|
|
||||||
|
db.add_data(WINS, True)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def parse_donates_top(message: Message) -> None:
|
||||||
|
if message.text.startswith('🏆 Топ по пожертвованиям'):
|
||||||
|
players = message.text.split('\n')
|
||||||
|
|
||||||
|
# Удаляет из массива строку с заголовком и последующую пустую строку
|
||||||
|
players.pop(0)
|
||||||
|
players.pop(0)
|
||||||
|
|
||||||
|
DONATES = list()
|
||||||
|
|
||||||
|
for idx, player in enumerate(players):
|
||||||
|
player = re.sub(r'^\d+. ', '', player) # удаляет нумерацию
|
||||||
|
player, donates_count = player.split(' - ') # разделяет ник и количество пожертвований в клановую сокровищницу
|
||||||
|
|
||||||
|
# Оставляет только ники игроков.
|
||||||
|
# Python не может парсить эмодзи в RegExp, по этому пришлось делать через str.replace()
|
||||||
|
# player = re.sub(r'\s[⚡⚜]$', '', player)
|
||||||
|
player = player.replace(' ⚡', '')
|
||||||
|
player = player.replace(' ⚜', '')
|
||||||
|
|
||||||
|
donates_count = donates_count.replace(' 💠', '') # удаляем эмодзи пожертвований
|
||||||
|
donates_count = int(re.sub(r'[^\x00-\x7F]', '', donates_count)) # преобразовывает строку в число
|
||||||
|
|
||||||
|
DONATES.append(
|
||||||
|
{
|
||||||
|
'telegram_id': message.entities[idx].url.strip('http://t.me/'),
|
||||||
|
'username': player,
|
||||||
|
'count': donates_count,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# print('{0} - {1} (@{2})'.format(player, donates_count, message.entities[idx].url.strip('http://t.me/')))
|
||||||
|
|
||||||
|
db.add_data(DONATES, False)
|
||||||
|
else:
|
||||||
|
pass
|
36
app/db.py
Normal file
36
app/db.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# Импорт модулей стандартной библиотеки
|
||||||
|
import sqlite3
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
class DataBase(object):
|
||||||
|
"""..."""
|
||||||
|
|
||||||
|
def __init__(self, path):
|
||||||
|
super(DataBase, self).__init__()
|
||||||
|
self.path = path
|
||||||
|
|
||||||
|
def connect(self) -> bool:
|
||||||
|
self.conn = sqlite3.connect(self.path)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def close(self) -> bool:
|
||||||
|
self.conn.close()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def commit(self) -> None:
|
||||||
|
self.conn.commit()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def add_data(self, data, wins: bool) -> bool: # wins изменит на Enum
|
||||||
|
if wins:
|
||||||
|
table = 'wins'
|
||||||
|
else:
|
||||||
|
table = 'donates'
|
||||||
|
|
||||||
|
cur = self.conn.cursor()
|
||||||
|
cur.execute('INSERT INTO {table} (\'data\') VALUES (\'{data}\')'.format(table=table, data=json.dumps(data)))
|
||||||
|
self.commit()
|
||||||
|
cur.close()
|
||||||
|
|
||||||
|
return True
|
8
app/utils.py
Normal file
8
app/utils.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
from . import app
|
||||||
|
|
||||||
|
|
||||||
|
async def get_telegram_id(username: str) -> int:
|
||||||
|
"""Возвращает Telegram ID по имени пользователя"""
|
||||||
|
telegram_user = await app.get_users(username)
|
||||||
|
|
||||||
|
return telegram_user.id
|
5
env.example
Normal file
5
env.example
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
APP_ID=""
|
||||||
|
APP_HASH=""
|
||||||
|
ACCOUNT=""
|
||||||
|
LOG_PATH="/tmp/test.log"
|
||||||
|
DB_PATH="./db.sqlite"
|
3
pyproject.toml
Normal file
3
pyproject.toml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[tool.black]
|
||||||
|
line-length = 123
|
||||||
|
skip-string-normalization = 1
|
1
requirements-dev.txt
Normal file
1
requirements-dev.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
black==24.10.0
|
3
requirements.txt
Normal file
3
requirements.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Pyrogram==2.0.106
|
||||||
|
TgCrypto==1.2.5
|
||||||
|
python_dotenv==1.0.1
|
1
sql/README.md
Normal file
1
sql/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
`wins` заменить на `donates` для создания второй таблицы.
|
12
sql/table.sql
Normal file
12
sql/table.sql
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS 'wins'
|
||||||
|
(
|
||||||
|
'id' Integer PRIMARY KEY AUTOINCREMENT,
|
||||||
|
'timestamp' DateTime NOT NULL DEFAULT (datetime(CURRENT_TIMESTAMP, 'localtime')),
|
||||||
|
'data' Text NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS 'index_timestamp' ON 'wins' ('timestamp');
|
||||||
|
|
||||||
|
COMMIT;
|
14
systemd/user/anicardclanstats.service
Normal file
14
systemd/user/anicardclanstats.service
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=AniCard Clan Stats
|
||||||
|
After=network.target network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=exec
|
||||||
|
Environment=APP_DIR=/home/bot/AniCardClan
|
||||||
|
Environment=VIRTUAL_ENV=${APP_DIR}/venv
|
||||||
|
Environment=PYTHONPATH=${APP_DIR}
|
||||||
|
Environment=PATH=${VIRTUAL_ENV}/bin:$PATH
|
||||||
|
ExecStart=/bin/bash -c '${VIRTUAL_ENV}/bin/python3 -m norify'
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
267
tests/donates-top.json
Normal file
267
tests/donates-top.json
Normal file
@ -0,0 +1,267 @@
|
|||||||
|
{
|
||||||
|
"_": "Message",
|
||||||
|
"id": 72311,
|
||||||
|
"from_user": {
|
||||||
|
"_": "User",
|
||||||
|
"id": 6018105307,
|
||||||
|
"is_self": false,
|
||||||
|
"is_contact": false,
|
||||||
|
"is_mutual_contact": false,
|
||||||
|
"is_deleted": false,
|
||||||
|
"is_bot": true,
|
||||||
|
"is_verified": false,
|
||||||
|
"is_restricted": false,
|
||||||
|
"is_scam": false,
|
||||||
|
"is_fake": false,
|
||||||
|
"is_support": false,
|
||||||
|
"is_premium": false,
|
||||||
|
"first_name": "AniCard",
|
||||||
|
"username": "anicardplaybot",
|
||||||
|
"dc_id": 2,
|
||||||
|
"photo": {
|
||||||
|
"_": "ChatPhoto",
|
||||||
|
"small_file_id": "AQADAgADiN0xG9osoEgAEAIAA9v_tGYBAAOnb8uWDDJj8AAEHgQ",
|
||||||
|
"small_photo_unique_id": "AgADiN0xG9osoEg",
|
||||||
|
"big_file_id": "AQADAgADiN0xG9osoEgAEAMAA9v_tGYBAAOnb8uWDDJj8AAEHgQ",
|
||||||
|
"big_photo_unique_id": "AgADiN0xG9osoEg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"date": "2024-11-15 21:37:15",
|
||||||
|
"chat": {
|
||||||
|
"_": "Chat",
|
||||||
|
"id": 6018105307,
|
||||||
|
"type": "ChatType.BOT",
|
||||||
|
"is_verified": false,
|
||||||
|
"is_restricted": false,
|
||||||
|
"is_scam": false,
|
||||||
|
"is_fake": false,
|
||||||
|
"is_support": false,
|
||||||
|
"username": "anicardplaybot",
|
||||||
|
"first_name": "AniCard",
|
||||||
|
"photo": {
|
||||||
|
"_": "ChatPhoto",
|
||||||
|
"small_file_id": "AQADAgADiN0xG9osoEgAEAIAA9v_tGYBAAOnb8uWDDJj8AAEHgQ",
|
||||||
|
"small_photo_unique_id": "AgADiN0xG9osoEg",
|
||||||
|
"big_file_id": "AQADAgADiN0xG9osoEgAEAMAA9v_tGYBAAOnb8uWDDJj8AAEHgQ",
|
||||||
|
"big_photo_unique_id": "AgADiN0xG9osoEg"
|
||||||
|
},
|
||||||
|
"dc_id": 2
|
||||||
|
},
|
||||||
|
"mentioned": false,
|
||||||
|
"scheduled": false,
|
||||||
|
"from_scheduled": false,
|
||||||
|
"edit_date": "2024-11-15 21:37:17",
|
||||||
|
"has_protected_content": false,
|
||||||
|
"text": "🏆 Топ по пожертвованиям 💠\n\n1. Seraph ⚜ - 2825 💠\n2. Timur ⚡ - 2220 💠\n3. Valerix 02 ⚡ - 1666 💠\n4. Thomas ⚡ - 1623 💠\n5. Nota ⚡ - 1548 💠\n6. Marpol ⚡ - 1231 💠\n7. Юсти ⚡ - 1199 💠\n8. K_L_E_Y--- ⚡ - 1144 💠\n9. Abror ⚡ - 1062 💠\n10. Миша ⚡ - 1048 💠\n11. Easy ⚜ - 1000 💠\n12. Ssoh ⚡ - 823 💠\n13. Glad_loz ⚡ - 795 💠\n14. You are my sunshine ⚡ - 775 💠\n15. Po ⚡ - 774 💠\n16. Vladimir ⚡ - 715 💠\n17. Влад ⚡ - 671 💠\n18. Name ⚡ - 658 💠\n19. Мизик ⚡ - 611 💠\n20. Ksw ⚡ - 599 💠\n21. Тимофей ⚡ - 562 💠\n22. W1zard ⚡ - 550 💠\n23. Андрей ⚡ - 498 💠\n24. Данила ⚡ - 364 💠\n25. ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ Lqidatorᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ⚡ - 293 💠\n26. Александр ⚡ - 213 💠\n27. Ch0my_ ⚡ - 0 💠\n28. Musso ⚡ - 0 💠",
|
||||||
|
"entities": [
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 32,
|
||||||
|
"length": 9,
|
||||||
|
"url": "http://t.me/owariserph"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 55,
|
||||||
|
"length": 8,
|
||||||
|
"url": "http://t.me/timurgatiatullin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 77,
|
||||||
|
"length": 13,
|
||||||
|
"url": "http://t.me/valerix02"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 104,
|
||||||
|
"length": 9,
|
||||||
|
"url": "http://t.me/thomas_02"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 127,
|
||||||
|
"length": 7,
|
||||||
|
"url": "http://t.me/NoTa145"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 148,
|
||||||
|
"length": 9,
|
||||||
|
"url": "http://t.me/marpol_l"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 171,
|
||||||
|
"length": 7,
|
||||||
|
"url": "http://t.me/Yustes_GuardianOfTheWorlds"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 192,
|
||||||
|
"length": 13,
|
||||||
|
"url": "http://t.me/KLEY_MOMENTS"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 219,
|
||||||
|
"length": 8,
|
||||||
|
"url": "http://t.me/Abroryy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 242,
|
||||||
|
"length": 7,
|
||||||
|
"url": "http://t.me/alien1life"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 264,
|
||||||
|
"length": 7,
|
||||||
|
"url": "http://t.me/db_o_qp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 286,
|
||||||
|
"length": 7,
|
||||||
|
"url": "http://t.me/Gnu_Linuks"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 307,
|
||||||
|
"length": 11,
|
||||||
|
"url": "http://t.me/Glad_loz1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 332,
|
||||||
|
"length": 22,
|
||||||
|
"url": "http://t.me/Tailer_Jirden"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 368,
|
||||||
|
"length": 5,
|
||||||
|
"url": "http://t.me/Poooooooooooopp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 387,
|
||||||
|
"length": 11,
|
||||||
|
"url": "http://t.me/h1ssoka"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 412,
|
||||||
|
"length": 7,
|
||||||
|
"url": "http://t.me/vlad_n5q"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 433,
|
||||||
|
"length": 7,
|
||||||
|
"url": "http://t.me/MrGhoul279"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 454,
|
||||||
|
"length": 8,
|
||||||
|
"url": "http://t.me/mizlony"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 476,
|
||||||
|
"length": 6,
|
||||||
|
"url": "http://t.me/Aassbube"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 496,
|
||||||
|
"length": 10,
|
||||||
|
"url": "http://t.me/halzov10"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 520,
|
||||||
|
"length": 9,
|
||||||
|
"url": "http://t.me/W1zard00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 543,
|
||||||
|
"length": 9,
|
||||||
|
"url": "http://t.me/Allastar123"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 566,
|
||||||
|
"length": 9,
|
||||||
|
"url": "http://t.me/Staldent"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 589,
|
||||||
|
"length": 59,
|
||||||
|
"url": "http://t.me/qaak01"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 662,
|
||||||
|
"length": 12,
|
||||||
|
"url": "http://t.me/yneznauchto"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 688,
|
||||||
|
"length": 9,
|
||||||
|
"url": "http://t.me/to4no_ch0my"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 709,
|
||||||
|
"length": 8,
|
||||||
|
"url": "http://t.me/mus_wf"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outgoing": false,
|
||||||
|
"reply_markup": {
|
||||||
|
"_": "InlineKeyboardMarkup",
|
||||||
|
"inline_keyboard": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"_": "InlineKeyboardButton",
|
||||||
|
"text": "Назад 🔙",
|
||||||
|
"callback_data": "my_clan:tops:91:0:0:0:0:1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
267
tests/win-top.json
Normal file
267
tests/win-top.json
Normal file
@ -0,0 +1,267 @@
|
|||||||
|
{
|
||||||
|
"_": "Message",
|
||||||
|
"id": 71945,
|
||||||
|
"from_user": {
|
||||||
|
"_": "User",
|
||||||
|
"id": 6018105307,
|
||||||
|
"is_self": false,
|
||||||
|
"is_contact": false,
|
||||||
|
"is_mutual_contact": false,
|
||||||
|
"is_deleted": false,
|
||||||
|
"is_bot": true,
|
||||||
|
"is_verified": false,
|
||||||
|
"is_restricted": false,
|
||||||
|
"is_scam": false,
|
||||||
|
"is_fake": false,
|
||||||
|
"is_support": false,
|
||||||
|
"is_premium": false,
|
||||||
|
"first_name": "AniCard",
|
||||||
|
"username": "anicardplaybot",
|
||||||
|
"dc_id": 2,
|
||||||
|
"photo": {
|
||||||
|
"_": "ChatPhoto",
|
||||||
|
"small_file_id": "AQADAgADiN0xG9osoEgAEAIAA9v_tGYBAAOnb8uWDDJj8AAEHgQ",
|
||||||
|
"small_photo_unique_id": "AgADiN0xG9osoEg",
|
||||||
|
"big_file_id": "AQADAgADiN0xG9osoEgAEAMAA9v_tGYBAAOnb8uWDDJj8AAEHgQ",
|
||||||
|
"big_photo_unique_id": "AgADiN0xG9osoEg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"date": "2024-11-15 19:23:05",
|
||||||
|
"chat": {
|
||||||
|
"_": "Chat",
|
||||||
|
"id": 6018105307,
|
||||||
|
"type": "ChatType.BOT",
|
||||||
|
"is_verified": false,
|
||||||
|
"is_restricted": false,
|
||||||
|
"is_scam": false,
|
||||||
|
"is_fake": false,
|
||||||
|
"is_support": false,
|
||||||
|
"username": "anicardplaybot",
|
||||||
|
"first_name": "AniCard",
|
||||||
|
"photo": {
|
||||||
|
"_": "ChatPhoto",
|
||||||
|
"small_file_id": "AQADAgADiN0xG9osoEgAEAIAA9v_tGYBAAOnb8uWDDJj8AAEHgQ",
|
||||||
|
"small_photo_unique_id": "AgADiN0xG9osoEg",
|
||||||
|
"big_file_id": "AQADAgADiN0xG9osoEgAEAMAA9v_tGYBAAOnb8uWDDJj8AAEHgQ",
|
||||||
|
"big_photo_unique_id": "AgADiN0xG9osoEg"
|
||||||
|
},
|
||||||
|
"dc_id": 2
|
||||||
|
},
|
||||||
|
"mentioned": false,
|
||||||
|
"scheduled": false,
|
||||||
|
"from_scheduled": false,
|
||||||
|
"edit_date": "2024-11-15 19:23:07",
|
||||||
|
"has_protected_content": false,
|
||||||
|
"text": "🏆 Топ по победам ⚔\n\n1. Valerix 02 ⚡ - 110 ⚔\n2. Thomas ⚡ - 94 ⚔\n3. Nota ⚡ - 93 ⚔\n4. Timur ⚡ - 86 ⚔\n5. Marpol ⚡ - 65 ⚔\n6. Easy ⚜ - 60 ⚔\n7. Vladimir ⚡ - 58 ⚔\n8. Abror ⚡ - 57 ⚔\n9. Миша ⚡ - 52 ⚔\n10. Юсти ⚡ - 52 ⚔\n11. Ssoh ⚡ - 49 ⚔\n12. K_L_E_Y--- ⚡ - 41 ⚔\n13. Влад ⚡ - 40 ⚔\n14. Name ⚡ - 39 ⚔\n15. Seraph ⚜ - 39 ⚔\n16. Po ⚡ - 32 ⚔\n17. You are my sunshine ⚡ - 31 ⚔\n18. W1zard ⚡ - 30 ⚔\n19. Ksw ⚡ - 22 ⚔\n20. Тимофей ⚡ - 17 ⚔\n21. Мизик ⚡ - 16 ⚔\n22. Glad_loz ⚡ - 15 ⚔\n23. Андрей ⚡ - 15 ⚔\n24. Данила ⚡ - 9 ⚔\n25. ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ Lqidatorᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ⚡ - 6 ⚔\n26. Ch0my_ ⚡ - 6 ⚔\n27. Musso ⚡ - 6 ⚔\n28. Александр ⚡ - 5 ⚔",
|
||||||
|
"entities": [
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 25,
|
||||||
|
"length": 13,
|
||||||
|
"url": "http://t.me/valerix02"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 51,
|
||||||
|
"length": 9,
|
||||||
|
"url": "http://t.me/thomas_02"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 72,
|
||||||
|
"length": 7,
|
||||||
|
"url": "http://t.me/NoTa145"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 91,
|
||||||
|
"length": 8,
|
||||||
|
"url": "http://t.me/timurgatiatullin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 111,
|
||||||
|
"length": 9,
|
||||||
|
"url": "http://t.me/marpol_l"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 132,
|
||||||
|
"length": 7,
|
||||||
|
"url": "http://t.me/db_o_qp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 151,
|
||||||
|
"length": 11,
|
||||||
|
"url": "http://t.me/h1ssoka"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 174,
|
||||||
|
"length": 8,
|
||||||
|
"url": "http://t.me/Abroryy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 194,
|
||||||
|
"length": 7,
|
||||||
|
"url": "http://t.me/alien1life"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 214,
|
||||||
|
"length": 7,
|
||||||
|
"url": "http://t.me/Yustes_GuardianOfTheWorlds"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 234,
|
||||||
|
"length": 7,
|
||||||
|
"url": "http://t.me/Gnu_Linuks"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 254,
|
||||||
|
"length": 13,
|
||||||
|
"url": "http://t.me/KLEY_MOMENTS"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 280,
|
||||||
|
"length": 7,
|
||||||
|
"url": "http://t.me/vlad_n5q"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 300,
|
||||||
|
"length": 7,
|
||||||
|
"url": "http://t.me/MrGhoul279"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 320,
|
||||||
|
"length": 9,
|
||||||
|
"url": "http://t.me/owariserph"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 342,
|
||||||
|
"length": 5,
|
||||||
|
"url": "http://t.me/Poooooooooooopp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 360,
|
||||||
|
"length": 22,
|
||||||
|
"url": "http://t.me/Tailer_Jirden"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 395,
|
||||||
|
"length": 9,
|
||||||
|
"url": "http://t.me/W1zard00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 417,
|
||||||
|
"length": 6,
|
||||||
|
"url": "http://t.me/Aassbube"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 436,
|
||||||
|
"length": 10,
|
||||||
|
"url": "http://t.me/halzov10"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 459,
|
||||||
|
"length": 8,
|
||||||
|
"url": "http://t.me/mizlony"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 480,
|
||||||
|
"length": 11,
|
||||||
|
"url": "http://t.me/Glad_loz1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 504,
|
||||||
|
"length": 9,
|
||||||
|
"url": "http://t.me/Allastar123"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 526,
|
||||||
|
"length": 9,
|
||||||
|
"url": "http://t.me/Staldent"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 547,
|
||||||
|
"length": 59,
|
||||||
|
"url": "http://t.me/qaak01"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 618,
|
||||||
|
"length": 9,
|
||||||
|
"url": "http://t.me/to4no_ch0my"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 639,
|
||||||
|
"length": 8,
|
||||||
|
"url": "http://t.me/mus_wf"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_": "MessageEntity",
|
||||||
|
"type": "MessageEntityType.TEXT_LINK",
|
||||||
|
"offset": 659,
|
||||||
|
"length": 12,
|
||||||
|
"url": "http://t.me/yneznauchto"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outgoing": false,
|
||||||
|
"reply_markup": {
|
||||||
|
"_": "InlineKeyboardMarkup",
|
||||||
|
"inline_keyboard": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"_": "InlineKeyboardButton",
|
||||||
|
"text": "Назад 🔙",
|
||||||
|
"callback_data": "my_clan:tops:91:0:0:0:0:1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user