Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
699d48bbd4
|
|||
f4ce13a2c7
|
|||
35c2a3e578
|
|||
1b61667705
|
|||
bd4dd1feda
|
|||
df95910e42
|
|||
0eb0685115
|
10
CHANGELOG.md
10
CHANGELOG.md
@ -1,4 +1,12 @@
|
||||
### 1.1.0
|
||||
## 2.1.0
|
||||
|
||||
- В БД сохраняется UTF-8 строки, вместо `\u`
|
||||
|
||||
## 2.0.0
|
||||
|
||||
- переход с SQLite3 на PostgreSQL
|
||||
|
||||
## 1.1.0
|
||||
|
||||
- Добавлен выхлом ошибок `try...catch` в логи
|
||||
- У игроков с премиумом теперь отрезается символ 💎 из имени
|
||||
|
13
HISTORY.md
Normal file
13
HISTORY.md
Normal file
@ -0,0 +1,13 @@
|
||||
---
|
||||
gitea: none
|
||||
include_toc: true
|
||||
---
|
||||
|
||||
# 📄 История изменений
|
||||
|
||||
|
||||
## 🪧 Легенда
|
||||
|
||||
* 🟢 – Добавлено
|
||||
* 🔴 – Удалёно
|
||||
* ♻️ – Исправлено
|
16
README.md
16
README.md
@ -3,14 +3,14 @@ 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] Сохранение статистики пожертвований в сокровищницу членов клана
|
||||
|
||||
|
||||
## 💽 Установка и использование
|
||||
@ -30,10 +30,14 @@ cp env.example .env
|
||||
- `APP_HASH` — Хэш приложения Telegram.
|
||||
- `ACCOUNT` — Имя аккаунта пользователя Telegram (_например `db_o_qp`_).
|
||||
- `LOG_PATH` — Путь в файлу логов (_например `/tmp/test.log`_).
|
||||
- `DB_PATH` — Путь к файлу базы данных SQLite3 (_например `./db.sqlite`_).
|
||||
- `DB_HOST` — Хост базы данных PostgreSQL
|
||||
- `DB_PORT` — Порт сервера базы данных
|
||||
- `DB_NAME` — Имя базы данных
|
||||
- `DB_USER` — Имя пользователя
|
||||
- `DB_PASSWORD` — Пароль пользователя
|
||||
|
||||
|
||||
### 🐦🔥 Настройка виртуального окружения и загрузка бибилотек
|
||||
### 🐦🔥 Настройка виртуального окружения и загрузка библиотек
|
||||
|
||||
Создание и активация виртуального окружения.
|
||||
|
||||
@ -80,4 +84,6 @@ Enter confirmation code: 14628
|
||||
- **Pyrogram** — Telegram клиент
|
||||
- **python-dotenv** — Работа с `.env` файлами
|
||||
- **loguru** — Логирование
|
||||
- **psycopg2** — Работа с PostgreSQL
|
||||
- **black** — Форматирование кода
|
||||
- **pdoc** — Генератор документации Python кода
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Информация о программе
|
||||
__author__ = 'Alexander Popov'
|
||||
__version__ = (1, 1, 0)
|
||||
__version__ = (2, 2, 0)
|
||||
|
||||
# Импорт модулей стандартной библиотеки
|
||||
from os import getenv
|
||||
@ -16,10 +16,16 @@ 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_PATH'))
|
||||
"""База данных"""
|
||||
db = DataBase(
|
||||
getenv('DB_HOST'),
|
||||
int(getenv('DB_PORT')),
|
||||
getenv('DB_NAME'),
|
||||
getenv('DB_USER'),
|
||||
getenv('DB_PASSWORD'),
|
||||
)
|
||||
"""🗃️ База данных"""
|
||||
|
||||
logger.add(getenv('LOG_PATH'), compression='zip')
|
||||
"""Логгер"""
|
||||
@ -28,4 +34,4 @@ DELAY_TIME = 12 * 60 * 60 # 12 часов
|
||||
"""Время приостановки выполнения цикла сбора статистики"""
|
||||
|
||||
BOT_NAME = '@anicardplaybot'
|
||||
"""Имя бота"""
|
||||
"""🏷️ Имя бота"""
|
||||
|
@ -35,7 +35,7 @@ async def get_top_wins() -> None:
|
||||
time.sleep(1)
|
||||
|
||||
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)
|
||||
|
||||
@ -71,7 +71,7 @@ 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)
|
||||
|
||||
|
@ -3,50 +3,53 @@ import re
|
||||
|
||||
# Импорт сторонних модулей
|
||||
from pyrogram.types import Message
|
||||
from pyrogram.enums import MessageEntityType
|
||||
|
||||
# Импорт модулей приложения
|
||||
from . import db
|
||||
from .utils import get_telegram_id, get_player_data
|
||||
|
||||
|
||||
def parse_wins_top(message: Message) -> None:
|
||||
async def parse_wins_top(message: Message) -> None:
|
||||
"""Выполняет парсинг данных топа побед членов клана"""
|
||||
if message.text.startswith('🏆 Топ по победам'):
|
||||
gamers = message.text.split('\n')
|
||||
gamers.pop(0)
|
||||
gamers.pop(0)
|
||||
players = message.text.split('\n')
|
||||
players.pop(0)
|
||||
players.pop(0)
|
||||
|
||||
WINS = list()
|
||||
|
||||
for idx, gamer in enumerate(gamers):
|
||||
gamer = re.sub(r'^\d+. ', '', gamer) # удаляет нумерацию
|
||||
gamer, battle_count = gamer.split(' - ') # разделяет ник и количество побед в клановых сражениях
|
||||
for idx, player in enumerate(players):
|
||||
player = re.sub(r'^\d+. ', '', player) # удаляет нумерацию
|
||||
player, battle_count = player.split(' - ') # разделяет ник и количество побед в клановых сражениях
|
||||
|
||||
# оставляет ники игроков, Python не может в эмодзи в RegExp, по этому пришлось делать через str.replace()
|
||||
# gamer = re.sub(r'\s[⚡⚜]$', '', gamer)
|
||||
gamer = gamer.replace(' ⚡', '')
|
||||
gamer = gamer.replace(' ⚜', '').replace('\ufe0f', '')
|
||||
gamer = gamer.replace(' 💎', '')
|
||||
# player = re.sub(r'\s[⚡⚜]$', '', player)
|
||||
player = player.replace(' ⚡', '')
|
||||
player = player.replace(' ⚜', '').replace('\ufe0f', '')
|
||||
player = player.replace(' 💎', '')
|
||||
|
||||
battle_count = battle_count.replace(' ⚔', '') # удаляем эмодзи мечей
|
||||
battle_count = int(re.sub(r'[^\x00-\x7F]', '', battle_count)) # преобразовывает строку в число
|
||||
|
||||
player_url, player_telegram_id = await get_player_data(message, idx)
|
||||
|
||||
WINS.append(
|
||||
{
|
||||
# 'telegram_id': message.entities[idx].url.strip('http://t.me/'),
|
||||
'username': gamer,
|
||||
'telegram_id': player_telegram_id,
|
||||
'username': player,
|
||||
'count': battle_count,
|
||||
'url': player_url,
|
||||
}
|
||||
)
|
||||
|
||||
# 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:
|
||||
async def parse_donates_top(message: Message) -> None:
|
||||
"""Выполняет парсинг данных топа пожертвований членов клана"""
|
||||
if message.text.startswith('🏆 Топ по пожертвованиям'):
|
||||
players = message.text.split('\n')
|
||||
@ -71,16 +74,17 @@ def parse_donates_top(message: Message) -> None:
|
||||
donates_count = donates_count.replace(' 💠', '') # удаляем эмодзи пожертвований
|
||||
donates_count = int(re.sub(r'[^\x00-\x7F]', '', donates_count)) # преобразовывает строку в число
|
||||
|
||||
player_url, player_telegram_id = await get_player_data(message, idx)
|
||||
|
||||
DONATES.append(
|
||||
{
|
||||
# 'telegram_id': message.entities[idx].url.strip('http://t.me/'),
|
||||
'telegram_id': player_telegram_id,
|
||||
'username': player,
|
||||
'count': donates_count,
|
||||
'url': player_url,
|
||||
}
|
||||
)
|
||||
|
||||
# print('{0} - {1} (@{2})'.format(player, donates_count, message.entities[idx].url.strip('http://t.me/')))
|
||||
|
||||
print(DONATES)
|
||||
db.add_data(DONATES, False)
|
||||
else:
|
||||
|
36
app/db.py
36
app/db.py
@ -1,19 +1,35 @@
|
||||
# Импорт модулей стандартной библиотеки
|
||||
import sqlite3
|
||||
import json
|
||||
|
||||
# Импорт сторонних модулей
|
||||
import psycopg2
|
||||
|
||||
|
||||
class DataBase(object):
|
||||
"""Класс для работы с базой данных"""
|
||||
|
||||
def __init__(self, path):
|
||||
def __init__(self, host: str, port: int, name: str, user: str, password: str):
|
||||
super(DataBase, self).__init__()
|
||||
self.path = path
|
||||
"""Путь к файлу базы данных SQLite3"""
|
||||
self.host = host
|
||||
"""Хост PostgreSQL базы данных"""
|
||||
self.port = port
|
||||
"""Порт сервера базы данных"""
|
||||
self.name = name
|
||||
"""Имя базы данных"""
|
||||
self.user = user
|
||||
"""Имя пользователя"""
|
||||
self.password = password
|
||||
"""Пароль пользователя"""
|
||||
|
||||
def connect(self) -> bool:
|
||||
"""Выполняет подключение к базе данных"""
|
||||
self.conn = sqlite3.connect(self.path)
|
||||
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:
|
||||
@ -34,7 +50,15 @@ class DataBase(object):
|
||||
table = 'donates'
|
||||
|
||||
cur = self.conn.cursor()
|
||||
cur.execute('INSERT INTO {table} (\'data\') VALUES (\'{data}\')'.format(table=table, data=json.dumps(data)))
|
||||
cur.execute(
|
||||
'INSERT INTO {table} ("data") VALUES (\'{data}\')'.format(
|
||||
table=table,
|
||||
data=json.dumps(
|
||||
data,
|
||||
ensure_ascii=False,
|
||||
),
|
||||
)
|
||||
)
|
||||
self.commit()
|
||||
cur.close()
|
||||
|
||||
|
21
app/utils.py
21
app/utils.py
@ -1,8 +1,27 @@
|
||||
# Импорт сторонних модулей
|
||||
from pyrogram.types import Message
|
||||
from pyrogram.enums import MessageEntityType
|
||||
|
||||
from . import client
|
||||
|
||||
|
||||
async def get_telegram_id(username: str) -> int:
|
||||
"""Возвращает Telegram ID по имени пользователя"""
|
||||
"""Возвращает Telegram ID"""
|
||||
telegram_user = await client.get_users(username)
|
||||
|
||||
return telegram_user.id
|
||||
|
||||
|
||||
async def get_player_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)
|
||||
|
@ -2,4 +2,8 @@ APP_ID=""
|
||||
APP_HASH=""
|
||||
ACCOUNT=""
|
||||
LOG_PATH="/tmp/test.log"
|
||||
DB_PATH="./db.sqlite"
|
||||
DB_HOST=""
|
||||
DB_PORT=""
|
||||
DB_NAME=""
|
||||
DB_USER=""
|
||||
DB_PASSWORD=""
|
||||
|
@ -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
|
||||
|
3
scripts/mkdocs.sh
Executable file
3
scripts/mkdocs.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
pdoc -o docs/ app
|
@ -1,12 +1,8 @@
|
||||
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');
|
||||
CREATE TABLE "public"."wins" (
|
||||
"data" JSON NOT NULL,
|
||||
"timestamp" Timestamp Without Time Zone DEFAULT CURRENT_TIMESTAMP );
|
||||
;
|
||||
|
||||
COMMIT;
|
||||
|
Reference in New Issue
Block a user