Compare commits
17 Commits
Author | SHA1 | Date | |
---|---|---|---|
2c8656c296
|
|||
501ba5d4a7
|
|||
cf46592915
|
|||
1686c99600
|
|||
16179148b5
|
|||
e8edb62ac7
|
|||
780782f369
|
|||
a7821361cb
|
|||
77b8e13619
|
|||
d48280ec7b
|
|||
22866616eb
|
|||
699d48bbd4
|
|||
f4ce13a2c7
|
|||
35c2a3e578
|
|||
1b61667705
|
|||
bd4dd1feda
|
|||
df95910e42
|
8
.gitignore
vendored
8
.gitignore
vendored
@ -8,3 +8,11 @@ db.sqlite
|
||||
|
||||
# Docs
|
||||
docs/
|
||||
|
||||
# AppImage
|
||||
AppDir/.DirIcon
|
||||
AppDir/usr/
|
||||
dist/python*
|
||||
dist/packages/
|
||||
dist/appimagetool*.AppImage
|
||||
dist/ClanStat-*.AppImage
|
||||
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "3rdparty/colors.sh"]
|
||||
path = 3rdparty/colors.sh
|
||||
url = https://git.a2s.su/iiiypuk/colors.sh.git
|
1
3rdparty/colors.sh
vendored
Submodule
1
3rdparty/colors.sh
vendored
Submodule
Submodule 3rdparty/colors.sh added at b4c1b5e3ee
5
AppDir/AppRun
Executable file
5
AppDir/AppRun
Executable file
@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
export PYTHONPATH="${PYTHONPATH}:${APPDIR}/usr/lib/python3.13/site-packages"
|
||||
|
||||
${APPDIR}/usr/bin/python3.13 -m ClanStat $1
|
6
AppDir/app.desktop
Normal file
6
AppDir/app.desktop
Normal file
@ -0,0 +1,6 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=ClanStat
|
||||
Icon=shield
|
||||
Terminal=false
|
||||
Categories=Utility;
|
BIN
AppDir/shield.png
Normal file
BIN
AppDir/shield.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
@ -1,8 +1,12 @@
|
||||
### 2.0.0
|
||||
## 2.1.0
|
||||
|
||||
- В БД сохраняется UTF-8 строки, вместо `\u`
|
||||
|
||||
## 2.0.0
|
||||
|
||||
- переход с SQLite3 на PostgreSQL
|
||||
|
||||
### 1.1.0
|
||||
## 1.1.0
|
||||
|
||||
- Добавлен выхлом ошибок `try...catch` в логи
|
||||
- У игроков с премиумом теперь отрезается символ 💎 из имени
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Информация о программе
|
||||
__author__ = 'Alexander Popov'
|
||||
__version__ = (2, 0, 0)
|
||||
__version__ = (2, 2, 4)
|
||||
|
||||
# Импорт модулей стандартной библиотеки
|
||||
from os import getenv
|
||||
@ -16,7 +16,7 @@ from .db import DataBase
|
||||
load_dotenv() # Выполняет чтение .env
|
||||
|
||||
client = Client(getenv('ACCOUNT'), api_id=getenv('APP_ID'), api_hash=getenv('APP_HASH'))
|
||||
"""Клиент Telegram"""
|
||||
"""🤖 Клиент Telegram"""
|
||||
|
||||
db = DataBase(
|
||||
getenv('DB_HOST'),
|
||||
@ -25,7 +25,7 @@ db = DataBase(
|
||||
getenv('DB_USER'),
|
||||
getenv('DB_PASSWORD'),
|
||||
)
|
||||
"""База данных"""
|
||||
"""🗃️ База данных"""
|
||||
|
||||
logger.add(getenv('LOG_PATH'), compression='zip')
|
||||
"""Логгер"""
|
||||
@ -34,4 +34,4 @@ DELAY_TIME = 12 * 60 * 60 # 12 часов
|
||||
"""Время приостановки выполнения цикла сбора статистики"""
|
||||
|
||||
BOT_NAME = '@anicardplaybot'
|
||||
"""Имя бота"""
|
||||
"""🏷️ Имя бота"""
|
@ -1,13 +1,17 @@
|
||||
# Импорт модулей стандартной библиотеки
|
||||
import time
|
||||
|
||||
# Импорт сторонних модулей
|
||||
from pyrogram.errors import exceptions
|
||||
from rich import print as rich_print
|
||||
|
||||
# Импорт модулей приложения
|
||||
from . import client, db, logger, DELAY_TIME
|
||||
from . import __version__, client, db, logger, DELAY_TIME
|
||||
from .actions import get_top_wins, get_top_donates
|
||||
|
||||
|
||||
async def main():
|
||||
"""Запускак клиента Telegram"""
|
||||
"""Запуск клиента Telegram"""
|
||||
await client.start()
|
||||
logger.info('Клиент Telegram запущен')
|
||||
|
||||
@ -33,6 +37,8 @@ async def main():
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logger.warning('🎴 ClanStat 🆔 {}', '.'.join(map(str, __version__)))
|
||||
logger.warning('🌐 URL: {}', 'https://git.a2s.su/AniCard/ClanStat/')
|
||||
logger.info('Выполняется запуск приложения')
|
||||
|
||||
logger.info('Выполняется подключение к базе данных')
|
||||
@ -40,6 +46,12 @@ if __name__ == '__main__':
|
||||
|
||||
try:
|
||||
client.run(main())
|
||||
except exceptions.unauthorized_401.AuthKeyUnregistered:
|
||||
rich_print('Ошибка Telegram: [bold red][401 AUTH_KEY_UNREGISTERED][/bold red]')
|
||||
rich_print(
|
||||
'Удалите файлы авторизации [bold green]Pyrogram[/bold green]:'
|
||||
' [italic yellow]*.session, *.session-journal[/italic yellow]'
|
||||
)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
@ -1,3 +1,7 @@
|
||||
"""
|
||||
🩻 ...
|
||||
"""
|
||||
|
||||
# Импорт модулей стандартной библиотеки
|
||||
import time
|
||||
|
||||
@ -7,8 +11,8 @@ from .collect import parse_wins_top, parse_donates_top
|
||||
|
||||
|
||||
async def get_top_wins() -> None:
|
||||
"""Получает топ клана по победам"""
|
||||
logger.info('Выполняется получения списка побед клана')
|
||||
"""⚔️ Получает топ клана по победам"""
|
||||
logger.info('⚔️ Выполняется получения списка побед клана')
|
||||
|
||||
await client.send_message(BOT_NAME, '🛡 Мой клан')
|
||||
time.sleep(1)
|
||||
@ -22,7 +26,7 @@ async def get_top_wins() -> None:
|
||||
message_id=message_id,
|
||||
callback_data='my_clan:tops:91:0:0:0:0:1',
|
||||
)
|
||||
time.sleep(1)
|
||||
time.sleep(2)
|
||||
|
||||
async for message in client.get_chat_history(BOT_NAME, limit=1):
|
||||
message_id = message.id
|
||||
@ -32,22 +36,22 @@ async def get_top_wins() -> None:
|
||||
message_id=message_id,
|
||||
callback_data='my_clan:top-wins:91:0:0:0:0:1',
|
||||
)
|
||||
time.sleep(1)
|
||||
time.sleep(2)
|
||||
|
||||
async for message in client.get_chat_history(BOT_NAME, limit=1):
|
||||
parse_wins_top(message)
|
||||
await parse_wins_top(message)
|
||||
|
||||
await client.read_chat_history(BOT_NAME)
|
||||
await client.read_chat_history(BOT_NAME) # Помечает сообщения в чате прочитанными
|
||||
|
||||
logger.info('Получение списка побед клана завершено')
|
||||
|
||||
|
||||
async def get_top_donates() -> None:
|
||||
"""Получает топ клана по пожертвованиям"""
|
||||
logger.info('Выполняется получения списка пожертвований клана')
|
||||
"""💠 Получает топ клана по пожертвованиям"""
|
||||
logger.info('💠 Выполняется получения списка пожертвований клана')
|
||||
|
||||
await client.send_message(BOT_NAME, '🛡 Мой клан')
|
||||
time.sleep(1)
|
||||
time.sleep(2)
|
||||
|
||||
message_id = 0
|
||||
async for message in client.get_chat_history(BOT_NAME, limit=1):
|
||||
@ -58,7 +62,7 @@ async def get_top_donates() -> None:
|
||||
message_id=message_id,
|
||||
callback_data='my_clan:tops:91:0:0:0:0:1',
|
||||
)
|
||||
time.sleep(1)
|
||||
time.sleep(2)
|
||||
|
||||
async for message in client.get_chat_history(BOT_NAME, limit=1):
|
||||
message_id = message.id
|
||||
@ -71,8 +75,8 @@ async def get_top_donates() -> None:
|
||||
time.sleep(1)
|
||||
|
||||
async for message in client.get_chat_history(BOT_NAME, limit=1):
|
||||
parse_donates_top(message)
|
||||
await parse_donates_top(message)
|
||||
|
||||
await client.read_chat_history(BOT_NAME)
|
||||
await client.read_chat_history(BOT_NAME) # Помечает сообщения в чате прочитанными
|
||||
|
||||
logger.info('Получение списка пожертвований клана завершено')
|
93
ClanStat/collect.py
Normal file
93
ClanStat/collect.py
Normal file
@ -0,0 +1,93 @@
|
||||
"""
|
||||
🩻 ...
|
||||
"""
|
||||
|
||||
# Импорт модулей стандартной библиотеки
|
||||
import re
|
||||
import io
|
||||
|
||||
# Импорт сторонних модулей
|
||||
from rich import print as rich_print
|
||||
from rich.table import Table
|
||||
from pyrogram.types import Message
|
||||
from pyrogram.enums import MessageEntityType
|
||||
|
||||
# Импорт модулей приложения
|
||||
from . import db
|
||||
from .utils import get_telegram_id, get_telegram_data, clean_icons
|
||||
|
||||
|
||||
async def parse_wins_top(message: Message) -> None:
|
||||
"""⚔️ Выполняет парсинг данных топа побед членов клана"""
|
||||
|
||||
if not message.text.startswith('🏆 Топ по победам'):
|
||||
return
|
||||
|
||||
WINS = await parse_tops(message, '⚔')
|
||||
|
||||
# 📟 Отрисовывает таблицу побед
|
||||
table = Table(show_header=True)
|
||||
table.add_column('ID', style='dim', justify='right', width=12)
|
||||
table.add_column('Username', style='magenta')
|
||||
table.add_column('Count', style='green', width=7)
|
||||
table.add_column('URL', style='yellow')
|
||||
for i in WINS:
|
||||
table.add_row(str(i['telegram_id']), i['username'], str(i['count']), i['url'])
|
||||
rich_print(table)
|
||||
|
||||
db.add_data(WINS, True) # Добавляет данные в базу данных
|
||||
|
||||
|
||||
async def parse_donates_top(message: Message) -> None:
|
||||
"""💠 Выполняет парсинг данных топа пожертвований членов клана"""
|
||||
|
||||
if not message.text.startswith('🏆 Топ по пожертвованиям'):
|
||||
return
|
||||
|
||||
DONATES = await parse_tops(message, '💠')
|
||||
|
||||
# 📟 Отрисовывает таблицу побед
|
||||
table = Table(show_header=True)
|
||||
table.add_column('ID', style='dim', justify='right', width=12)
|
||||
table.add_column('Username', style='magenta')
|
||||
table.add_column('Count', style='green', width=7)
|
||||
table.add_column('URL', style='yellow')
|
||||
for i in DONATES:
|
||||
table.add_row(str(i['telegram_id']), i['username'], str(i['count']), i['url'])
|
||||
rich_print(table)
|
||||
|
||||
db.add_data(DONATES, False) # Добавляет данные в базу данных
|
||||
|
||||
|
||||
async def parse_tops(message: Message, emoji_replace: str) -> list:
|
||||
"""..."""
|
||||
|
||||
top_data = list()
|
||||
|
||||
msg_buffer = io.StringIO(message.text)
|
||||
msg_buffer.readline()
|
||||
msg_buffer.readline()
|
||||
|
||||
for e in message.entities:
|
||||
player_line = msg_buffer.readline()
|
||||
player_name, battle_count = player_line.split(' - ')
|
||||
player = clean_icons(message.text[e.offset : e.offset + e.length])
|
||||
player_name = clean_icons(re.sub(r'^\d+. ', '', player_name))
|
||||
battle_count = battle_count.replace(f' {emoji_replace}', '') # Удаляет эмодзи
|
||||
battle_count = int(re.sub(r'[^\x00-\x7F]', '', battle_count))
|
||||
|
||||
if player not in player_name:
|
||||
top_data.append({'telegram_id': None, 'username': player_name, 'count': battle_count, 'url': None})
|
||||
msg_buffer.readline()
|
||||
continue
|
||||
|
||||
if e.type is MessageEntityType.TEXT_LINK:
|
||||
player_url = e.url
|
||||
player_telegram_id = await get_telegram_id(player_url.replace('http://t.me/', ''))
|
||||
elif e.type is MessageEntityType.TEXT_MENTION:
|
||||
player_url = e.url
|
||||
player_telegram_id = e.user.id
|
||||
|
||||
top_data.append({'telegram_id': player_telegram_id, 'username': player, 'count': battle_count, 'url': player_url})
|
||||
|
||||
return top_data
|
94
ClanStat/db.py
Normal file
94
ClanStat/db.py
Normal file
@ -0,0 +1,94 @@
|
||||
"""
|
||||
🗃️ Работа с базой данных
|
||||
"""
|
||||
|
||||
# Импорт модулей стандартной библиотеки
|
||||
import json
|
||||
|
||||
# Импорт сторонних модулей
|
||||
import psycopg2
|
||||
|
||||
|
||||
class DataBase(object):
|
||||
"""Класс для работы с базой данных"""
|
||||
|
||||
def __init__(self, host: str, port: int, name: str, user: str, password: str):
|
||||
super(DataBase, self).__init__()
|
||||
self.host = host
|
||||
"""🖥️ Хост PostgreSQL базы данных"""
|
||||
self.port = port
|
||||
"""🔟 Порт сервера базы данных"""
|
||||
self.name = name
|
||||
"""🏷️ Имя базы данных"""
|
||||
self.user = user
|
||||
"""🥸 Имя пользователя"""
|
||||
self.password = password
|
||||
"""🔐 Пароль пользователя"""
|
||||
|
||||
def connect(self) -> bool:
|
||||
"""Выполняет подключение к базе данных"""
|
||||
|
||||
connection_kwargs = {
|
||||
"host": self.host,
|
||||
"port": self.port,
|
||||
"user": self.user,
|
||||
"password": self.password,
|
||||
"database": self.name,
|
||||
}
|
||||
"""Настройки соединения"""
|
||||
|
||||
keepalive_kwargs = {
|
||||
"keepalives": 1,
|
||||
"keepalives_idle": 5,
|
||||
"keepalives_interval": 5,
|
||||
"keepalives_count": 2,
|
||||
"tcp_user_timeout": 1000,
|
||||
}
|
||||
"""Настройки TCP"""
|
||||
|
||||
self.conn = psycopg2.connect(**connection_kwargs, **keepalive_kwargs) # Выполняет подключение к базе данных
|
||||
self.conn.autocommit = True # Активирует автоматический коммит транзакций
|
||||
|
||||
return True
|
||||
|
||||
def close(self) -> bool:
|
||||
"""Закрывает подключение к базе данных"""
|
||||
self.conn.close()
|
||||
return True
|
||||
|
||||
def check_connect(self) -> None:
|
||||
"""Проверяет статус подключения"""
|
||||
try:
|
||||
cur = self.conn.cursor()
|
||||
cur.execute('SELECT 1')
|
||||
cur.close()
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
return False
|
||||
|
||||
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,
|
||||
ensure_ascii=False,
|
||||
),
|
||||
)
|
||||
)
|
||||
cur.close()
|
||||
|
||||
return True
|
49
ClanStat/utils.py
Normal file
49
ClanStat/utils.py
Normal file
@ -0,0 +1,49 @@
|
||||
"""
|
||||
🧰 Утилиты
|
||||
"""
|
||||
|
||||
# Импорт сторонних модулей
|
||||
from pyrogram.types import Message
|
||||
from pyrogram.enums import MessageEntityType
|
||||
|
||||
from . import client
|
||||
|
||||
|
||||
async def get_telegram_id(username: str) -> int:
|
||||
"""🆔 Возвращает Telegram ID"""
|
||||
|
||||
try:
|
||||
telegram_user = await client.get_users(username)
|
||||
return telegram_user.id
|
||||
except Exception as e:
|
||||
return None
|
||||
|
||||
|
||||
async def get_telegram_data(message: Message, idx: int) -> tuple():
|
||||
"""..."""
|
||||
|
||||
if message.entities[idx].type == MessageEntityType.TEXT_LINK:
|
||||
player_url = message.entities[idx].url
|
||||
player_telegram_id = await get_telegram_id(player_url.replace('http://t.me/', ''))
|
||||
elif message.entities[idx].type == MessageEntityType.TEXT_MENTION:
|
||||
player_url = None
|
||||
player_telegram_id = message.entities[idx].user.id
|
||||
else:
|
||||
player_url = None
|
||||
player_telegram_id = None
|
||||
|
||||
return (player_url, player_telegram_id)
|
||||
|
||||
|
||||
def clean_icons(text: str) -> str:
|
||||
"""💎 Удаляет иконки подписок из ников"""
|
||||
|
||||
# оставляет ники игроков, Python не может в эмодзи в RegExp, по этому пришлось делать через str.replace()
|
||||
# player = re.sub(r'\s[⚡⚜]$', '', player)
|
||||
|
||||
output = text
|
||||
|
||||
for icon in ['⚡', '⚜', '💎']:
|
||||
output = output.replace(f' {icon}', '')
|
||||
|
||||
return output
|
20
HISTORY.md
Normal file
20
HISTORY.md
Normal file
@ -0,0 +1,20 @@
|
||||
---
|
||||
gitea: none
|
||||
include_toc: true
|
||||
---
|
||||
|
||||
# 📄 История изменений
|
||||
|
||||
|
||||
## 🪧 Легенда
|
||||
|
||||
* 🟢 – Добавлено
|
||||
* 🔴 – Удалёно
|
||||
* ♻️ – Исправлено
|
||||
|
||||
## 2.2.4
|
||||
|
||||
* 🟢 Добавлено сообщение об ошибке **401** `AUTH_KEY_UNREGISTERED`
|
||||
* 🟢 Добавлены emoji в приветственное сообщение
|
||||
* 🟢 Результаты в терминале отображаются в таблице
|
||||
* 🟢 Изменён алгоритм получения значений побед и пожертвований
|
22
README.md
22
README.md
@ -3,24 +3,36 @@ gitea: none
|
||||
include_toc: true
|
||||
---
|
||||
|
||||
# 🎴 Бот для ведения статистики клана в AniCard
|
||||
# 🎴 Клиент для ведения статистики клана в AniCard
|
||||
|
||||
<img src="https://git.a2s.su/AniCard/ClanStat/raw/branch/master/assets/icon.png" alt="Иконка" height="512">
|
||||
|
||||
## 📦 Возможности
|
||||
|
||||
- [ ] Сохранение статистики побед в КВ членов клана
|
||||
- [ ] Сохранение статистики пожертвований в сокровищницу членов клана
|
||||
- [x] Сохранение статистики побед в КВ членов клана
|
||||
- [x] Сохранение статистики пожертвований в сокровищницу членов клана
|
||||
|
||||
|
||||
## 💽 Установка и использование
|
||||
|
||||
### ⬇️ Загрузка проекта
|
||||
|
||||
Первым делом необходимо скачать приложение.
|
||||
|
||||
```sh
|
||||
# Скачиваем приложение и переходим в скачанную директорию
|
||||
git clone https://git.a2s.su/AniCard/ClanStat.git
|
||||
cd ClanStat
|
||||
```
|
||||
|
||||
|
||||
### 📄 Подготовка файла конфигурации
|
||||
|
||||
Настройки приложения хранится в файле `.env`.
|
||||
Пример файла с настройками называется `env.example`.
|
||||
|
||||
```sh
|
||||
# Копируем файл с примером конфигурации
|
||||
cp env.example .env
|
||||
```
|
||||
|
||||
@ -37,7 +49,7 @@ cp env.example .env
|
||||
- `DB_PASSWORD` — Пароль пользователя
|
||||
|
||||
|
||||
### 🐦🔥 Настройка виртуального окружения и загрузка бибилотек
|
||||
### 🐦🔥 Настройка виртуального окружения и загрузка библиотек
|
||||
|
||||
Создание и активация виртуального окружения.
|
||||
|
||||
@ -84,4 +96,6 @@ Enter confirmation code: 14628
|
||||
- **Pyrogram** — Telegram клиент
|
||||
- **python-dotenv** — Работа с `.env` файлами
|
||||
- **loguru** — Логирование
|
||||
- **psycopg2** — Работа с PostgreSQL
|
||||
- **black** — Форматирование кода
|
||||
- **pdoc** — Генератор документации Python кода
|
||||
|
@ -1,87 +0,0 @@
|
||||
# Импорт модулей стандартной библиотеки
|
||||
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(' ⚜', '').replace('\ufe0f', '')
|
||||
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/')))
|
||||
|
||||
print(WINS)
|
||||
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(' ⚜', '').replace('\ufe0f', '')
|
||||
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/')))
|
||||
|
||||
print(DONATES)
|
||||
db.add_data(DONATES, False)
|
||||
else:
|
||||
pass
|
57
app/db.py
57
app/db.py
@ -1,57 +0,0 @@
|
||||
# Импорт модулей стандартной библиотеки
|
||||
import json
|
||||
|
||||
# Импорт сторонних модулей
|
||||
import psycopg2
|
||||
|
||||
|
||||
class DataBase(object):
|
||||
"""Класс для работы с базой данных"""
|
||||
|
||||
def __init__(self, host: str, port: int, name: str, user: str, password: str):
|
||||
super(DataBase, self).__init__()
|
||||
self.host = host
|
||||
"""Хост PostgreSQL базы данных"""
|
||||
self.port = port
|
||||
"""Порт сервера базы данных"""
|
||||
self.name = name
|
||||
"""Имя базы данных"""
|
||||
self.user = user
|
||||
"""Имя пользователя"""
|
||||
self.password = password
|
||||
"""Пароль пользователя"""
|
||||
|
||||
def connect(self) -> bool:
|
||||
"""Выполняет подключение к базе данных"""
|
||||
self.conn = psycopg2.connect(
|
||||
dbname=self.name,
|
||||
host=self.host,
|
||||
user=self.user,
|
||||
password=self.password,
|
||||
port=self.port,
|
||||
)
|
||||
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
|
@ -1,8 +0,0 @@
|
||||
from . import client
|
||||
|
||||
|
||||
async def get_telegram_id(username: str) -> int:
|
||||
"""Возвращает Telegram ID по имени пользователя"""
|
||||
telegram_user = await client.get_users(username)
|
||||
|
||||
return telegram_user.id
|
0
dist/.gitkeep
vendored
Normal file
0
dist/.gitkeep
vendored
Normal file
@ -1,7 +1,7 @@
|
||||
[project]
|
||||
dynamic = [ "version" ]
|
||||
name = "..."
|
||||
description = "..."
|
||||
name = "ClanStat"
|
||||
description = "AniCard Clan Statistics"
|
||||
authors = [ {name = "Alexander Popov", email = "iiiypuk@fastmail.fm"}, ]
|
||||
readme = "README.md"
|
||||
license = { text = "MIT-0 License" }
|
||||
|
@ -1 +1,2 @@
|
||||
black==24.10.0
|
||||
pdoc==15.0.1
|
||||
|
@ -1,5 +1,7 @@
|
||||
loguru==0.7.2
|
||||
pdoc==15.0.1
|
||||
psycopg2==2.9.10
|
||||
Pyrogram==2.0.106
|
||||
python-dotenv==1.0.1
|
||||
rich==14.0.0
|
||||
TgCrypto==1.2.5
|
||||
zstandard==0.23.0
|
||||
|
82
scripts/make-appimage.sh
Executable file
82
scripts/make-appimage.sh
Executable file
@ -0,0 +1,82 @@
|
||||
#!/bin/sh
|
||||
|
||||
# author: Alexander Popov
|
||||
# mail: iiiypuk {at} fastmail.fm
|
||||
# license: Public Domain
|
||||
# desc: Собирает AppImage
|
||||
|
||||
# Импортирует скрипт с определениями цветов
|
||||
source ./3rdparty/colors.sh/colors.sh
|
||||
|
||||
APPDIR="../AppDir"
|
||||
GIT_HASH=$(git rev-parse --short HEAD)
|
||||
|
||||
# Скачивает x86_64 AppImageTool
|
||||
download_appimage_tool() {
|
||||
echo -e "${CYAN}Загрузка AppImageTool...${NC}"
|
||||
|
||||
wget -q --show-progress https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage
|
||||
chmod +x appimagetool-x86_64.AppImage
|
||||
}
|
||||
|
||||
# Скачивает March Any Linux Python
|
||||
download_python() {
|
||||
wget -q --show-progress https://github.com/niess/python-appimage/releases/download/python3.13/python3.13.3-cp313-cp313-manylinux2014_x86_64.AppImage
|
||||
chmod +x python3.13.3-cp313-cp313-manylinux2014_x86_64.AppImage
|
||||
mv python3.13.3-cp313-cp313-manylinux2014_x86_64.AppImage python3.13
|
||||
|
||||
mkdir -p ${APPDIR}/usr/bin/
|
||||
cp ./python3.13 ${APPDIR}/usr/bin/python3.13
|
||||
}
|
||||
|
||||
# Загружает Python зависимости проекта
|
||||
get_requirements() {
|
||||
./python3.13 -m pip install --target=$(pwd)/packages -r ../requirements.txt > /dev/null 2>&1
|
||||
}
|
||||
|
||||
# Копирует записимости в AppDir
|
||||
copy_requirements() {
|
||||
mkdir -p ${APPDIR}/usr/lib/python3.13/site-packages/
|
||||
|
||||
cp -r packages/* ${APPDIR}/usr/lib/python3.13/site-packages/
|
||||
}
|
||||
|
||||
# Копирует приложение в AppDir
|
||||
copy_app_files() {
|
||||
echo -e "${GREEN}Копирование файлов ...${NC}"
|
||||
rm -rf ${APPDIR}/usr/lib/python3.13/site-packages/ClanStat
|
||||
|
||||
cp -r ../ClanStat ${APPDIR}/usr/lib/python3.13/site-packages/ClanStat
|
||||
rm -rf ${APPDIR}/usr/lib/python3.13/site-packages/ClanStat/__pycache__
|
||||
}
|
||||
|
||||
# Выполянет сборку AppImage
|
||||
make_appimage() {
|
||||
echo -e "${GREEN}Сборка AppImage...${NC}"
|
||||
./appimagetool-x86_64.AppImage ${APPDIR} > /dev/null 2>&1
|
||||
mv ./ClanStat-x86_64.AppImage ./ClanStat-${GIT_HASH}-x86_64.AppImage
|
||||
|
||||
echo -e "${RED}Сборка AppImage заверщена${NC}"
|
||||
}
|
||||
|
||||
# Основная функция
|
||||
main() {
|
||||
clear
|
||||
|
||||
echo -e "${YELLOW}Подготовка к сборке AppImage...${NC}"
|
||||
if [ ! -f "appimagetool-x86_64.AppImage" ]; then
|
||||
download_appimage_tool
|
||||
fi
|
||||
|
||||
if [ ! -f "python3.13" ]; then
|
||||
download_python
|
||||
get_requirements
|
||||
copy_requirements
|
||||
fi
|
||||
|
||||
copy_app_files
|
||||
make_appimage
|
||||
}
|
||||
|
||||
# Запускает основную функцию
|
||||
main
|
15
scripts/mkdocs.sh
Executable file
15
scripts/mkdocs.sh
Executable file
@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
|
||||
# author: Alexander Popov
|
||||
# mail: iiiypuk {at} fastmail.fm
|
||||
# license: Public Domain
|
||||
# desc: Генерирует документацию Python кода
|
||||
|
||||
# Импортирует скрипт с определениями цветов
|
||||
source ./3rdparty/colors.sh/colors.sh
|
||||
|
||||
echo -e "${CYAN}Генерация документации...${NC}"
|
||||
|
||||
pdoc -o docs/ ClanStat
|
||||
|
||||
echo -e "${GREEN}Генерация завершена. Смотрите директорию 'docs'.${NC}"
|
Reference in New Issue
Block a user