chesshome 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- chesshome-0.1.0/LICENSE +21 -0
- chesshome-0.1.0/PKG-INFO +234 -0
- chesshome-0.1.0/README.md +218 -0
- chesshome-0.1.0/chesshome/__init__.py +4 -0
- chesshome-0.1.0/chesshome/client.py +176 -0
- chesshome-0.1.0/chesshome/models.py +115 -0
- chesshome-0.1.0/chesshome.egg-info/PKG-INFO +234 -0
- chesshome-0.1.0/chesshome.egg-info/SOURCES.txt +11 -0
- chesshome-0.1.0/chesshome.egg-info/dependency_links.txt +1 -0
- chesshome-0.1.0/chesshome.egg-info/requires.txt +2 -0
- chesshome-0.1.0/chesshome.egg-info/top_level.txt +1 -0
- chesshome-0.1.0/pyproject.toml +25 -0
- chesshome-0.1.0/setup.cfg +4 -0
chesshome-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Chess Home
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
chesshome-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: chesshome
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python client for ChessHome platform API
|
|
5
|
+
Author-email: ChessHome <noreply@chesshome.pro>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://chesshome.pro
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Requires-Python: >=3.8
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Requires-Dist: httpx>=0.24.0
|
|
14
|
+
Requires-Dist: pydantic>=2.0.0
|
|
15
|
+
Dynamic: license-file
|
|
16
|
+
|
|
17
|
+
# ♟️ ChessHome Python Client
|
|
18
|
+
|
|
19
|
+
Официальный Python-клиент для платформы [Chess Home](https://chesshome.pro).
|
|
20
|
+
Позволяет взаимодействовать с API: управлять турнирами, форумом, клубами, решать задачи, отправлять личные сообщения и многое другое.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 🚀 Установка
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install chesshome
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Или установка из исходников:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
git clone https://github.com/your_username/chesshome-py.git
|
|
34
|
+
cd chesshome-py
|
|
35
|
+
pip install -e .
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 📖 Быстрый старт
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from chesshome import ChessHomeClient
|
|
44
|
+
|
|
45
|
+
# Создаём клиент и авторизуемся
|
|
46
|
+
client = ChessHomeClient()
|
|
47
|
+
client.login("ваш_логин", "ваш_пароль")
|
|
48
|
+
|
|
49
|
+
# Получаем свой профиль
|
|
50
|
+
me = client.get_me()
|
|
51
|
+
print(f"Привет, {me.username}! Рейтинг: {me.rating}")
|
|
52
|
+
|
|
53
|
+
# Список активных турниров
|
|
54
|
+
tours = client.get_tournaments(status="active")
|
|
55
|
+
for t in tours:
|
|
56
|
+
print(f"{t.name} — {t.participantsCount} участников")
|
|
57
|
+
|
|
58
|
+
# Создаём тему на форуме
|
|
59
|
+
result = client.create_forum_thread(
|
|
60
|
+
title="Моя первая тема",
|
|
61
|
+
body="Привет! Это тест через Python-клиент."
|
|
62
|
+
)
|
|
63
|
+
print(f"Тема создана: {result['thread']['slug']}")
|
|
64
|
+
|
|
65
|
+
# Отправляем личное сообщение
|
|
66
|
+
client.send_dm("friend", "Привет! Как дела?")
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 📚 Документация по методам
|
|
72
|
+
|
|
73
|
+
### 🔑 Авторизация
|
|
74
|
+
|
|
75
|
+
| Метод | Описание |
|
|
76
|
+
|-------|----------|
|
|
77
|
+
| `login(username, password)` | Вход в аккаунт, возвращает клиент с токеном |
|
|
78
|
+
|
|
79
|
+
### 👤 Пользователи
|
|
80
|
+
|
|
81
|
+
| Метод | Описание |
|
|
82
|
+
|-------|----------|
|
|
83
|
+
| `get_me()` | Получить свой профиль (`User`) |
|
|
84
|
+
| `get_user(username)` | Получить профиль другого пользователя |
|
|
85
|
+
| `search_users(query)` | Поиск пользователей по нику |
|
|
86
|
+
| `follow(username)` | Подписаться на пользователя |
|
|
87
|
+
| `unfollow(username)` | Отписаться |
|
|
88
|
+
| `check_follow(username)` | Проверить, подписан ли ты на пользователя |
|
|
89
|
+
| `get_followers(username)` | Список подписчиков пользователя |
|
|
90
|
+
| `get_following(username)` | Список подписок пользователя |
|
|
91
|
+
| `get_online_friends()` | Друзья онлайн (на кого подписан и онлайн) |
|
|
92
|
+
|
|
93
|
+
### 🏆 Турниры
|
|
94
|
+
|
|
95
|
+
| Метод | Описание |
|
|
96
|
+
|-------|----------|
|
|
97
|
+
| `get_tournaments(status)` | Список турниров (`active`, `upcoming`, `finished`) |
|
|
98
|
+
| `get_tournament(id)` | Детали турнира |
|
|
99
|
+
| `join_tournament(id)` | Вступить в турнир |
|
|
100
|
+
| `leave_tournament(id)` | Покинуть турнир |
|
|
101
|
+
|
|
102
|
+
### 💬 Форум
|
|
103
|
+
|
|
104
|
+
| Метод | Описание |
|
|
105
|
+
|-------|----------|
|
|
106
|
+
| `get_forum_threads(page, limit)` | Список тем |
|
|
107
|
+
| `get_forum_thread(slug)` | Получить тему с ответами |
|
|
108
|
+
| `create_forum_thread(title, body)` | Создать тему |
|
|
109
|
+
| `reply_to_thread(thread_id, body)` | Ответить в тему |
|
|
110
|
+
|
|
111
|
+
### 📰 Блог
|
|
112
|
+
|
|
113
|
+
| Метод | Описание |
|
|
114
|
+
|-------|----------|
|
|
115
|
+
| `get_blog_posts(page, limit)` | Список постов |
|
|
116
|
+
| `get_blog_post(post_id)` | Получить пост |
|
|
117
|
+
| `like_blog_post(post_id, unlike)` | Поставить/снять лайк |
|
|
118
|
+
|
|
119
|
+
### 🧩 Задачи (Puzzles)
|
|
120
|
+
|
|
121
|
+
| Метод | Описание |
|
|
122
|
+
|-------|----------|
|
|
123
|
+
| `get_puzzles(topic, difficulty, limit, offset)` | Список задач |
|
|
124
|
+
| `get_puzzle(puzzle_id)` | Детали задачи |
|
|
125
|
+
| `attempt_puzzle(puzzle_id, correct, moves)` | Отправить результат решения |
|
|
126
|
+
|
|
127
|
+
### ⚡ Storm
|
|
128
|
+
|
|
129
|
+
| Метод | Описание |
|
|
130
|
+
|-------|----------|
|
|
131
|
+
| `get_storm_puzzles(topics)` | Получить набор задач для шторма |
|
|
132
|
+
| `finish_storm(score, total_attempted, correct, wrong, time_bonus)` | Завершить забег |
|
|
133
|
+
|
|
134
|
+
### 🏛️ Клубы
|
|
135
|
+
|
|
136
|
+
| Метод | Описание |
|
|
137
|
+
|-------|----------|
|
|
138
|
+
| `get_clubs()` | Список всех клубов |
|
|
139
|
+
| `get_club(club_id)` | Информация о клубе |
|
|
140
|
+
| `create_club(name, description)` | Создать клуб (макс. 5 на пользователя) |
|
|
141
|
+
| `join_club(club_id)` | Вступить в клуб |
|
|
142
|
+
| `leave_club(club_id)` | Покинуть клуб |
|
|
143
|
+
| `update_club(club_id, name, description)` | Обновить клуб (только админ) |
|
|
144
|
+
| `get_club_chat(club_id)` | Чат клуба (только для участников) |
|
|
145
|
+
|
|
146
|
+
### ✉️ Личные сообщения (DM)
|
|
147
|
+
|
|
148
|
+
| Метод | Описание |
|
|
149
|
+
|-------|----------|
|
|
150
|
+
| `get_conversations()` | Список диалогов |
|
|
151
|
+
| `get_messages(partner, since)` | История сообщений с пользователем |
|
|
152
|
+
| `send_dm(to, text)` | Отправить сообщение |
|
|
153
|
+
| `mark_dm_read(partner)` | Отметить все сообщения как прочитанные |
|
|
154
|
+
| `block_user(username)` | Заблокировать пользователя |
|
|
155
|
+
| `unblock_user(username)` | Разблокировать |
|
|
156
|
+
|
|
157
|
+
### 🌐 Глобальный чат
|
|
158
|
+
|
|
159
|
+
| Метод | Описание |
|
|
160
|
+
|-------|----------|
|
|
161
|
+
| `get_global_chat(limit)` | Последние сообщения глобального чата (только чтение) |
|
|
162
|
+
|
|
163
|
+
### 📊 Статистика
|
|
164
|
+
|
|
165
|
+
| Метод | Описание |
|
|
166
|
+
|-------|----------|
|
|
167
|
+
| `get_stats()` | Общая статистика платформы |
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## 🧪 Примеры использования
|
|
172
|
+
|
|
173
|
+
### Получение статистики
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
stats = client.get_stats()
|
|
177
|
+
print(f"Всего пользователей: {stats['totals']['users']}")
|
|
178
|
+
print(f"Сыграно партий: {stats['totals']['games']}")
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Работа с клубами
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
# Создать клуб
|
|
185
|
+
new_club = client.create_club("Мой клуб", "Описание клуба")
|
|
186
|
+
print(f"Клуб создан: {new_club.id}")
|
|
187
|
+
|
|
188
|
+
# Вступить в клуб
|
|
189
|
+
client.join_club(new_club.id)
|
|
190
|
+
|
|
191
|
+
# Получить чат клуба
|
|
192
|
+
chat = client.get_club_chat(new_club.id)
|
|
193
|
+
for msg in chat.get('messages', []):
|
|
194
|
+
print(f"{msg['username']}: {msg['message']}")
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Задачи (Puzzles)
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
# Получить задачи по теме "Мат в 1 ход"
|
|
201
|
+
puzzles = client.get_puzzles(topic="mate1", limit=5)
|
|
202
|
+
for p in puzzles:
|
|
203
|
+
print(p['title'], p['difficulty'])
|
|
204
|
+
|
|
205
|
+
# Отправить результат решения (пример)
|
|
206
|
+
# client.attempt_puzzle(puzzles[0]['id'], correct=True, moves=[...])
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Подписки
|
|
210
|
+
|
|
211
|
+
```python
|
|
212
|
+
# Подписаться на пользователя
|
|
213
|
+
client.follow("username")
|
|
214
|
+
|
|
215
|
+
# Проверить подписку
|
|
216
|
+
is_following = client.check_follow("username")
|
|
217
|
+
print(is_following)
|
|
218
|
+
|
|
219
|
+
# Получить список подписчиков
|
|
220
|
+
followers = client.get_followers("username")
|
|
221
|
+
for f in followers:
|
|
222
|
+
print(f['username'])
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
## 📄 Лицензия
|
|
229
|
+
|
|
230
|
+
MIT License. См. файл [LICENSE](LICENSE).
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
**Разработано с ❤️ для сообщества Chess Home**
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# ♟️ ChessHome Python Client
|
|
2
|
+
|
|
3
|
+
Официальный Python-клиент для платформы [Chess Home](https://chesshome.pro).
|
|
4
|
+
Позволяет взаимодействовать с API: управлять турнирами, форумом, клубами, решать задачи, отправлять личные сообщения и многое другое.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 🚀 Установка
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pip install chesshome
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Или установка из исходников:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
git clone https://github.com/your_username/chesshome-py.git
|
|
18
|
+
cd chesshome-py
|
|
19
|
+
pip install -e .
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 📖 Быстрый старт
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
from chesshome import ChessHomeClient
|
|
28
|
+
|
|
29
|
+
# Создаём клиент и авторизуемся
|
|
30
|
+
client = ChessHomeClient()
|
|
31
|
+
client.login("ваш_логин", "ваш_пароль")
|
|
32
|
+
|
|
33
|
+
# Получаем свой профиль
|
|
34
|
+
me = client.get_me()
|
|
35
|
+
print(f"Привет, {me.username}! Рейтинг: {me.rating}")
|
|
36
|
+
|
|
37
|
+
# Список активных турниров
|
|
38
|
+
tours = client.get_tournaments(status="active")
|
|
39
|
+
for t in tours:
|
|
40
|
+
print(f"{t.name} — {t.participantsCount} участников")
|
|
41
|
+
|
|
42
|
+
# Создаём тему на форуме
|
|
43
|
+
result = client.create_forum_thread(
|
|
44
|
+
title="Моя первая тема",
|
|
45
|
+
body="Привет! Это тест через Python-клиент."
|
|
46
|
+
)
|
|
47
|
+
print(f"Тема создана: {result['thread']['slug']}")
|
|
48
|
+
|
|
49
|
+
# Отправляем личное сообщение
|
|
50
|
+
client.send_dm("friend", "Привет! Как дела?")
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 📚 Документация по методам
|
|
56
|
+
|
|
57
|
+
### 🔑 Авторизация
|
|
58
|
+
|
|
59
|
+
| Метод | Описание |
|
|
60
|
+
|-------|----------|
|
|
61
|
+
| `login(username, password)` | Вход в аккаунт, возвращает клиент с токеном |
|
|
62
|
+
|
|
63
|
+
### 👤 Пользователи
|
|
64
|
+
|
|
65
|
+
| Метод | Описание |
|
|
66
|
+
|-------|----------|
|
|
67
|
+
| `get_me()` | Получить свой профиль (`User`) |
|
|
68
|
+
| `get_user(username)` | Получить профиль другого пользователя |
|
|
69
|
+
| `search_users(query)` | Поиск пользователей по нику |
|
|
70
|
+
| `follow(username)` | Подписаться на пользователя |
|
|
71
|
+
| `unfollow(username)` | Отписаться |
|
|
72
|
+
| `check_follow(username)` | Проверить, подписан ли ты на пользователя |
|
|
73
|
+
| `get_followers(username)` | Список подписчиков пользователя |
|
|
74
|
+
| `get_following(username)` | Список подписок пользователя |
|
|
75
|
+
| `get_online_friends()` | Друзья онлайн (на кого подписан и онлайн) |
|
|
76
|
+
|
|
77
|
+
### 🏆 Турниры
|
|
78
|
+
|
|
79
|
+
| Метод | Описание |
|
|
80
|
+
|-------|----------|
|
|
81
|
+
| `get_tournaments(status)` | Список турниров (`active`, `upcoming`, `finished`) |
|
|
82
|
+
| `get_tournament(id)` | Детали турнира |
|
|
83
|
+
| `join_tournament(id)` | Вступить в турнир |
|
|
84
|
+
| `leave_tournament(id)` | Покинуть турнир |
|
|
85
|
+
|
|
86
|
+
### 💬 Форум
|
|
87
|
+
|
|
88
|
+
| Метод | Описание |
|
|
89
|
+
|-------|----------|
|
|
90
|
+
| `get_forum_threads(page, limit)` | Список тем |
|
|
91
|
+
| `get_forum_thread(slug)` | Получить тему с ответами |
|
|
92
|
+
| `create_forum_thread(title, body)` | Создать тему |
|
|
93
|
+
| `reply_to_thread(thread_id, body)` | Ответить в тему |
|
|
94
|
+
|
|
95
|
+
### 📰 Блог
|
|
96
|
+
|
|
97
|
+
| Метод | Описание |
|
|
98
|
+
|-------|----------|
|
|
99
|
+
| `get_blog_posts(page, limit)` | Список постов |
|
|
100
|
+
| `get_blog_post(post_id)` | Получить пост |
|
|
101
|
+
| `like_blog_post(post_id, unlike)` | Поставить/снять лайк |
|
|
102
|
+
|
|
103
|
+
### 🧩 Задачи (Puzzles)
|
|
104
|
+
|
|
105
|
+
| Метод | Описание |
|
|
106
|
+
|-------|----------|
|
|
107
|
+
| `get_puzzles(topic, difficulty, limit, offset)` | Список задач |
|
|
108
|
+
| `get_puzzle(puzzle_id)` | Детали задачи |
|
|
109
|
+
| `attempt_puzzle(puzzle_id, correct, moves)` | Отправить результат решения |
|
|
110
|
+
|
|
111
|
+
### ⚡ Storm
|
|
112
|
+
|
|
113
|
+
| Метод | Описание |
|
|
114
|
+
|-------|----------|
|
|
115
|
+
| `get_storm_puzzles(topics)` | Получить набор задач для шторма |
|
|
116
|
+
| `finish_storm(score, total_attempted, correct, wrong, time_bonus)` | Завершить забег |
|
|
117
|
+
|
|
118
|
+
### 🏛️ Клубы
|
|
119
|
+
|
|
120
|
+
| Метод | Описание |
|
|
121
|
+
|-------|----------|
|
|
122
|
+
| `get_clubs()` | Список всех клубов |
|
|
123
|
+
| `get_club(club_id)` | Информация о клубе |
|
|
124
|
+
| `create_club(name, description)` | Создать клуб (макс. 5 на пользователя) |
|
|
125
|
+
| `join_club(club_id)` | Вступить в клуб |
|
|
126
|
+
| `leave_club(club_id)` | Покинуть клуб |
|
|
127
|
+
| `update_club(club_id, name, description)` | Обновить клуб (только админ) |
|
|
128
|
+
| `get_club_chat(club_id)` | Чат клуба (только для участников) |
|
|
129
|
+
|
|
130
|
+
### ✉️ Личные сообщения (DM)
|
|
131
|
+
|
|
132
|
+
| Метод | Описание |
|
|
133
|
+
|-------|----------|
|
|
134
|
+
| `get_conversations()` | Список диалогов |
|
|
135
|
+
| `get_messages(partner, since)` | История сообщений с пользователем |
|
|
136
|
+
| `send_dm(to, text)` | Отправить сообщение |
|
|
137
|
+
| `mark_dm_read(partner)` | Отметить все сообщения как прочитанные |
|
|
138
|
+
| `block_user(username)` | Заблокировать пользователя |
|
|
139
|
+
| `unblock_user(username)` | Разблокировать |
|
|
140
|
+
|
|
141
|
+
### 🌐 Глобальный чат
|
|
142
|
+
|
|
143
|
+
| Метод | Описание |
|
|
144
|
+
|-------|----------|
|
|
145
|
+
| `get_global_chat(limit)` | Последние сообщения глобального чата (только чтение) |
|
|
146
|
+
|
|
147
|
+
### 📊 Статистика
|
|
148
|
+
|
|
149
|
+
| Метод | Описание |
|
|
150
|
+
|-------|----------|
|
|
151
|
+
| `get_stats()` | Общая статистика платформы |
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## 🧪 Примеры использования
|
|
156
|
+
|
|
157
|
+
### Получение статистики
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
stats = client.get_stats()
|
|
161
|
+
print(f"Всего пользователей: {stats['totals']['users']}")
|
|
162
|
+
print(f"Сыграно партий: {stats['totals']['games']}")
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Работа с клубами
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
# Создать клуб
|
|
169
|
+
new_club = client.create_club("Мой клуб", "Описание клуба")
|
|
170
|
+
print(f"Клуб создан: {new_club.id}")
|
|
171
|
+
|
|
172
|
+
# Вступить в клуб
|
|
173
|
+
client.join_club(new_club.id)
|
|
174
|
+
|
|
175
|
+
# Получить чат клуба
|
|
176
|
+
chat = client.get_club_chat(new_club.id)
|
|
177
|
+
for msg in chat.get('messages', []):
|
|
178
|
+
print(f"{msg['username']}: {msg['message']}")
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Задачи (Puzzles)
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
# Получить задачи по теме "Мат в 1 ход"
|
|
185
|
+
puzzles = client.get_puzzles(topic="mate1", limit=5)
|
|
186
|
+
for p in puzzles:
|
|
187
|
+
print(p['title'], p['difficulty'])
|
|
188
|
+
|
|
189
|
+
# Отправить результат решения (пример)
|
|
190
|
+
# client.attempt_puzzle(puzzles[0]['id'], correct=True, moves=[...])
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Подписки
|
|
194
|
+
|
|
195
|
+
```python
|
|
196
|
+
# Подписаться на пользователя
|
|
197
|
+
client.follow("username")
|
|
198
|
+
|
|
199
|
+
# Проверить подписку
|
|
200
|
+
is_following = client.check_follow("username")
|
|
201
|
+
print(is_following)
|
|
202
|
+
|
|
203
|
+
# Получить список подписчиков
|
|
204
|
+
followers = client.get_followers("username")
|
|
205
|
+
for f in followers:
|
|
206
|
+
print(f['username'])
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
## 📄 Лицензия
|
|
213
|
+
|
|
214
|
+
MIT License. См. файл [LICENSE](LICENSE).
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
**Разработано с ❤️ для сообщества Chess Home**
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import httpx
|
|
2
|
+
from typing import Optional, Dict, Any, List
|
|
3
|
+
from .models import User, Tournament, ForumThread, BlogPost, Conversation, Message, Club
|
|
4
|
+
|
|
5
|
+
class ChessHomeClient:
|
|
6
|
+
BASE_URL = "https://chesshome.pro/api"
|
|
7
|
+
|
|
8
|
+
def __init__(self, token: Optional[str] = None, device_id: Optional[str] = None, verify_ssl: bool = True):
|
|
9
|
+
self.token = token
|
|
10
|
+
self.device_id = device_id or self._generate_device_id()
|
|
11
|
+
self._session = httpx.Client(
|
|
12
|
+
base_url=self.BASE_URL,
|
|
13
|
+
headers=self._default_headers(),
|
|
14
|
+
timeout=30.0,
|
|
15
|
+
verify=verify_ssl
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
def _default_headers(self) -> Dict[str, str]:
|
|
19
|
+
headers = {"X-Device-Id": self.device_id}
|
|
20
|
+
if self.token:
|
|
21
|
+
headers["Authorization"] = f"Bearer {self.token}"
|
|
22
|
+
return headers
|
|
23
|
+
|
|
24
|
+
def _generate_device_id(self) -> str:
|
|
25
|
+
import uuid
|
|
26
|
+
return f"py_{uuid.uuid4().hex[:12]}"
|
|
27
|
+
|
|
28
|
+
def _request(self, method: str, path: str, **kwargs) -> Any:
|
|
29
|
+
response = self._session.request(method, path, **kwargs)
|
|
30
|
+
response.raise_for_status()
|
|
31
|
+
return response.json()
|
|
32
|
+
|
|
33
|
+
# ========== AUTH ==========
|
|
34
|
+
def login(self, username: str, password: str) -> "ChessHomeClient":
|
|
35
|
+
data = {"username": username, "password": password}
|
|
36
|
+
resp = self._request("POST", "/login", json=data)
|
|
37
|
+
self.token = resp["token"]
|
|
38
|
+
self._session.headers.update({"Authorization": f"Bearer {self.token}"})
|
|
39
|
+
return self
|
|
40
|
+
|
|
41
|
+
# ========== USERS ==========
|
|
42
|
+
def get_me(self) -> User:
|
|
43
|
+
return User(**self._request("GET", "/me"))
|
|
44
|
+
|
|
45
|
+
def get_user(self, username: str) -> User:
|
|
46
|
+
return User(**self._request("GET", f"/users/{username}"))
|
|
47
|
+
|
|
48
|
+
def search_users(self, query: str) -> List[User]:
|
|
49
|
+
resp = self._request("GET", "/users/search", params={"q": query})
|
|
50
|
+
return [User(**u) for u in resp]
|
|
51
|
+
|
|
52
|
+
# ========== TOURNAMENTS ==========
|
|
53
|
+
def get_tournaments(self, status: Optional[str] = None) -> List[Tournament]:
|
|
54
|
+
params = {"status": status} if status else {}
|
|
55
|
+
resp = self._request("GET", "/tournaments", params=params)
|
|
56
|
+
return [Tournament(**t) for t in resp]
|
|
57
|
+
|
|
58
|
+
def get_tournament(self, tournament_id: str) -> Tournament:
|
|
59
|
+
return Tournament(**self._request("GET", f"/tournaments/{tournament_id}"))
|
|
60
|
+
|
|
61
|
+
def join_tournament(self, tournament_id: str) -> dict:
|
|
62
|
+
return self._request("POST", f"/tournaments/{tournament_id}/join")
|
|
63
|
+
|
|
64
|
+
def leave_tournament(self, tournament_id: str) -> dict:
|
|
65
|
+
return self._request("POST", f"/tournaments/{tournament_id}/leave")
|
|
66
|
+
|
|
67
|
+
# ========== FORUM ==========
|
|
68
|
+
def get_forum_threads(self, page: int = 0, limit: int = 20) -> List[ForumThread]:
|
|
69
|
+
resp = self._request("GET", "/forum/threads", params={"page": page, "limit": limit})
|
|
70
|
+
return [ForumThread(**t) for t in resp["threads"]]
|
|
71
|
+
|
|
72
|
+
def get_forum_thread(self, slug: str) -> dict:
|
|
73
|
+
return self._request("GET", f"/forum/threads/{slug}")
|
|
74
|
+
|
|
75
|
+
def create_forum_thread(self, title: str, body: str) -> dict:
|
|
76
|
+
return self._request("POST", "/forum/threads", json={"title": title, "body": body})
|
|
77
|
+
|
|
78
|
+
def reply_to_thread(self, thread_id: str, body: str) -> dict:
|
|
79
|
+
return self._request("POST", f"/forum/threads/{thread_id}/replies", json={"body": body})
|
|
80
|
+
|
|
81
|
+
# ========== BLOG ==========
|
|
82
|
+
def get_blog_posts(self, page: int = 0, limit: int = 20) -> List[BlogPost]:
|
|
83
|
+
resp = self._request("GET", "/blog", params={"page": page, "limit": limit})
|
|
84
|
+
return [BlogPost(**p) for p in resp["posts"]]
|
|
85
|
+
|
|
86
|
+
def get_blog_post(self, post_id: str) -> BlogPost:
|
|
87
|
+
return BlogPost(**self._request("GET", f"/blog/{post_id}"))
|
|
88
|
+
|
|
89
|
+
def like_blog_post(self, post_id: str, unlike: bool = False) -> dict:
|
|
90
|
+
return self._request("POST", f"/blog/{post_id}/like", json={"unlike": unlike})
|
|
91
|
+
|
|
92
|
+
# ========== PUZZLES ==========
|
|
93
|
+
def get_puzzles(self, topic: Optional[str] = None, difficulty: Optional[str] = None,
|
|
94
|
+
limit: int = 20, offset: int = 0) -> List[dict]:
|
|
95
|
+
params = {"topic": topic, "difficulty": difficulty, "limit": limit, "offset": offset}
|
|
96
|
+
params = {k: v for k, v in params.items() if v is not None}
|
|
97
|
+
return self._request("GET", "/puzzles", params=params)
|
|
98
|
+
|
|
99
|
+
def get_puzzle(self, puzzle_id: str) -> dict:
|
|
100
|
+
return self._request("GET", f"/puzzles/{puzzle_id}")
|
|
101
|
+
|
|
102
|
+
def attempt_puzzle(self, puzzle_id: str, correct: bool, moves: Optional[list] = None) -> dict:
|
|
103
|
+
return self._request("POST", f"/puzzles/{puzzle_id}/attempt",
|
|
104
|
+
json={"correct": correct, "moves": moves})
|
|
105
|
+
|
|
106
|
+
# ========== STORM ==========
|
|
107
|
+
def get_storm_puzzles(self, topics: str = "mate1,mate2") -> List[dict]:
|
|
108
|
+
return self._request("GET", "/storm/puzzles", params={"topics": topics})
|
|
109
|
+
|
|
110
|
+
def finish_storm(self, score: int, total_attempted: int, correct: int,
|
|
111
|
+
wrong: int, time_bonus: int = 0) -> dict:
|
|
112
|
+
return self._request("POST", "/storm/finish", json={
|
|
113
|
+
"score": score,
|
|
114
|
+
"total_attempted": total_attempted,
|
|
115
|
+
"correct": correct,
|
|
116
|
+
"wrong": wrong,
|
|
117
|
+
"time_bonus": time_bonus
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
# ========== DM (ЛИЧНЫЕ СООБЩЕНИЯ) ==========
|
|
121
|
+
def get_conversations(self) -> List[Conversation]:
|
|
122
|
+
resp = self._request("GET", "/dm/conversations")
|
|
123
|
+
return [Conversation(**c) for c in resp]
|
|
124
|
+
|
|
125
|
+
def get_messages(self, partner: str, since: Optional[str] = None) -> List[Message]:
|
|
126
|
+
params = {"since": since} if since else {}
|
|
127
|
+
resp = self._request("GET", f"/dm/messages/{partner}", params=params)
|
|
128
|
+
return [Message(**m) for m in resp.get("messages", [])]
|
|
129
|
+
|
|
130
|
+
def send_dm(self, to: str, text: str) -> Message:
|
|
131
|
+
resp = self._request("POST", "/dm/send", json={"to": to, "text": text})
|
|
132
|
+
return Message(**resp)
|
|
133
|
+
|
|
134
|
+
def mark_dm_read(self, partner: str) -> dict:
|
|
135
|
+
return self._request("POST", "/dm/read", json={"partner": partner})
|
|
136
|
+
|
|
137
|
+
def block_user(self, username: str) -> dict:
|
|
138
|
+
return self._request("POST", "/dm/block", json={"username": username})
|
|
139
|
+
|
|
140
|
+
def unblock_user(self, username: str) -> dict:
|
|
141
|
+
return self._request("POST", "/dm/unblock", json={"username": username})
|
|
142
|
+
|
|
143
|
+
# ========== ГЛОБАЛЬНЫЙ ЧАТ (ТОЛЬКО ЧТЕНИЕ) ==========
|
|
144
|
+
def get_global_chat(self, limit: int = 50) -> List[dict]:
|
|
145
|
+
return self._request("GET", "/chat", params={"limit": limit})
|
|
146
|
+
|
|
147
|
+
# ========== КЛУБЫ ==========
|
|
148
|
+
def get_clubs(self) -> List[Club]:
|
|
149
|
+
resp = self._request("GET", "/clubs")
|
|
150
|
+
return [Club(**c) for c in resp]
|
|
151
|
+
|
|
152
|
+
def get_club(self, club_id: str) -> Club:
|
|
153
|
+
return Club(**self._request("GET", f"/clubs/{club_id}"))
|
|
154
|
+
|
|
155
|
+
def create_club(self, name: str, description: str = "") -> Club:
|
|
156
|
+
resp = self._request("POST", "/clubs", json={"name": name, "description": description})
|
|
157
|
+
return Club(**resp)
|
|
158
|
+
|
|
159
|
+
def join_club(self, club_id: str) -> dict:
|
|
160
|
+
return self._request("POST", f"/clubs/{club_id}/join")
|
|
161
|
+
|
|
162
|
+
def leave_club(self, club_id: str) -> dict:
|
|
163
|
+
return self._request("POST", f"/clubs/{club_id}/leave")
|
|
164
|
+
|
|
165
|
+
def update_club(self, club_id: str, name: Optional[str] = None, description: Optional[str] = None) -> Club:
|
|
166
|
+
payload = {}
|
|
167
|
+
if name is not None:
|
|
168
|
+
payload["name"] = name
|
|
169
|
+
if description is not None:
|
|
170
|
+
payload["description"] = description
|
|
171
|
+
resp = self._request("PATCH", f"/clubs/{club_id}", json=payload)
|
|
172
|
+
return Club(**resp)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def get_club_chat(self, club_id: str) -> dict:
|
|
176
|
+
return self._request("GET", f"/clubs/{club_id}/chat")
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
from pydantic import BaseModel, Field
|
|
2
|
+
from typing import Optional, List
|
|
3
|
+
|
|
4
|
+
class User(BaseModel):
|
|
5
|
+
id: str
|
|
6
|
+
username: str
|
|
7
|
+
rating: int = 1200
|
|
8
|
+
games_played: Optional[int] = 0
|
|
9
|
+
wins: Optional[int] = 0
|
|
10
|
+
losses: Optional[int] = 0
|
|
11
|
+
draws: Optional[int] = 0
|
|
12
|
+
avatar: Optional[str] = None
|
|
13
|
+
role: str = "user"
|
|
14
|
+
banned: bool = False
|
|
15
|
+
ban_reason: Optional[str] = None
|
|
16
|
+
puzzle_rating: Optional[int] = 1200
|
|
17
|
+
puzzle_solved: Optional[int] = 0
|
|
18
|
+
puzzle_attempted: Optional[int] = 0
|
|
19
|
+
storm_best: Optional[int] = 0
|
|
20
|
+
storm_runs: Optional[int] = 0
|
|
21
|
+
emoji: str = ""
|
|
22
|
+
created_at: Optional[int] = None
|
|
23
|
+
|
|
24
|
+
class Config:
|
|
25
|
+
extra = "ignore" # ← игнорируем любые дополнительные поля
|
|
26
|
+
|
|
27
|
+
class Tournament(BaseModel):
|
|
28
|
+
id: str
|
|
29
|
+
name: str
|
|
30
|
+
description: Optional[str] = None
|
|
31
|
+
timeControl: str
|
|
32
|
+
durationMinutes: int
|
|
33
|
+
startsAt: int
|
|
34
|
+
endsAt: int
|
|
35
|
+
maxParticipants: int = 0
|
|
36
|
+
minRating: int = 0
|
|
37
|
+
maxRating: int = 9999
|
|
38
|
+
participantsCount: int = 0
|
|
39
|
+
createdBy: str
|
|
40
|
+
status: str
|
|
41
|
+
winner: Optional[str] = None
|
|
42
|
+
participants: Optional[List] = None
|
|
43
|
+
games: Optional[List] = None
|
|
44
|
+
|
|
45
|
+
class Config:
|
|
46
|
+
extra = "ignore"
|
|
47
|
+
|
|
48
|
+
class ForumThread(BaseModel):
|
|
49
|
+
id: str
|
|
50
|
+
slug: str
|
|
51
|
+
author: str
|
|
52
|
+
title: str
|
|
53
|
+
body: str
|
|
54
|
+
createdAt: int
|
|
55
|
+
lastActivityAt: int
|
|
56
|
+
replyCount: int = 0
|
|
57
|
+
views: int = 0
|
|
58
|
+
|
|
59
|
+
class Config:
|
|
60
|
+
extra = "ignore"
|
|
61
|
+
|
|
62
|
+
class BlogPost(BaseModel):
|
|
63
|
+
id: str
|
|
64
|
+
title: str
|
|
65
|
+
body: Optional[str] = None
|
|
66
|
+
author: str
|
|
67
|
+
status: str
|
|
68
|
+
views: int = 0
|
|
69
|
+
likes: int = 0
|
|
70
|
+
createdAt: int
|
|
71
|
+
updatedAt: Optional[int] = None
|
|
72
|
+
community: bool = False
|
|
73
|
+
|
|
74
|
+
class Config:
|
|
75
|
+
extra = "ignore"
|
|
76
|
+
|
|
77
|
+
class Conversation(BaseModel):
|
|
78
|
+
partner: str
|
|
79
|
+
last_msg: str
|
|
80
|
+
last_ts: str
|
|
81
|
+
unread: int = 0
|
|
82
|
+
blocked: bool = False
|
|
83
|
+
|
|
84
|
+
class Config:
|
|
85
|
+
extra = "ignore"
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class Message(BaseModel):
|
|
89
|
+
id: str
|
|
90
|
+
text: str
|
|
91
|
+
ts: str
|
|
92
|
+
read: bool
|
|
93
|
+
from_: Optional[str] = Field(None, alias='from')
|
|
94
|
+
to: Optional[str] = None
|
|
95
|
+
from_user: Optional[str] = None
|
|
96
|
+
to_user: Optional[str] = None
|
|
97
|
+
|
|
98
|
+
class Config:
|
|
99
|
+
extra = "ignore"
|
|
100
|
+
populate_by_name = True
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class Club(BaseModel):
|
|
104
|
+
id: str
|
|
105
|
+
name: str
|
|
106
|
+
description: Optional[str] = None
|
|
107
|
+
memberCount: int = 0
|
|
108
|
+
admins: List[str] = []
|
|
109
|
+
members: List[str] = []
|
|
110
|
+
createdBy: str
|
|
111
|
+
createdAt: str
|
|
112
|
+
official: bool = False
|
|
113
|
+
|
|
114
|
+
class Config:
|
|
115
|
+
extra = "ignore"
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: chesshome
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python client for ChessHome platform API
|
|
5
|
+
Author-email: ChessHome <noreply@chesshome.pro>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://chesshome.pro
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Requires-Python: >=3.8
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Requires-Dist: httpx>=0.24.0
|
|
14
|
+
Requires-Dist: pydantic>=2.0.0
|
|
15
|
+
Dynamic: license-file
|
|
16
|
+
|
|
17
|
+
# ♟️ ChessHome Python Client
|
|
18
|
+
|
|
19
|
+
Официальный Python-клиент для платформы [Chess Home](https://chesshome.pro).
|
|
20
|
+
Позволяет взаимодействовать с API: управлять турнирами, форумом, клубами, решать задачи, отправлять личные сообщения и многое другое.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 🚀 Установка
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install chesshome
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Или установка из исходников:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
git clone https://github.com/your_username/chesshome-py.git
|
|
34
|
+
cd chesshome-py
|
|
35
|
+
pip install -e .
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 📖 Быстрый старт
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from chesshome import ChessHomeClient
|
|
44
|
+
|
|
45
|
+
# Создаём клиент и авторизуемся
|
|
46
|
+
client = ChessHomeClient()
|
|
47
|
+
client.login("ваш_логин", "ваш_пароль")
|
|
48
|
+
|
|
49
|
+
# Получаем свой профиль
|
|
50
|
+
me = client.get_me()
|
|
51
|
+
print(f"Привет, {me.username}! Рейтинг: {me.rating}")
|
|
52
|
+
|
|
53
|
+
# Список активных турниров
|
|
54
|
+
tours = client.get_tournaments(status="active")
|
|
55
|
+
for t in tours:
|
|
56
|
+
print(f"{t.name} — {t.participantsCount} участников")
|
|
57
|
+
|
|
58
|
+
# Создаём тему на форуме
|
|
59
|
+
result = client.create_forum_thread(
|
|
60
|
+
title="Моя первая тема",
|
|
61
|
+
body="Привет! Это тест через Python-клиент."
|
|
62
|
+
)
|
|
63
|
+
print(f"Тема создана: {result['thread']['slug']}")
|
|
64
|
+
|
|
65
|
+
# Отправляем личное сообщение
|
|
66
|
+
client.send_dm("friend", "Привет! Как дела?")
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 📚 Документация по методам
|
|
72
|
+
|
|
73
|
+
### 🔑 Авторизация
|
|
74
|
+
|
|
75
|
+
| Метод | Описание |
|
|
76
|
+
|-------|----------|
|
|
77
|
+
| `login(username, password)` | Вход в аккаунт, возвращает клиент с токеном |
|
|
78
|
+
|
|
79
|
+
### 👤 Пользователи
|
|
80
|
+
|
|
81
|
+
| Метод | Описание |
|
|
82
|
+
|-------|----------|
|
|
83
|
+
| `get_me()` | Получить свой профиль (`User`) |
|
|
84
|
+
| `get_user(username)` | Получить профиль другого пользователя |
|
|
85
|
+
| `search_users(query)` | Поиск пользователей по нику |
|
|
86
|
+
| `follow(username)` | Подписаться на пользователя |
|
|
87
|
+
| `unfollow(username)` | Отписаться |
|
|
88
|
+
| `check_follow(username)` | Проверить, подписан ли ты на пользователя |
|
|
89
|
+
| `get_followers(username)` | Список подписчиков пользователя |
|
|
90
|
+
| `get_following(username)` | Список подписок пользователя |
|
|
91
|
+
| `get_online_friends()` | Друзья онлайн (на кого подписан и онлайн) |
|
|
92
|
+
|
|
93
|
+
### 🏆 Турниры
|
|
94
|
+
|
|
95
|
+
| Метод | Описание |
|
|
96
|
+
|-------|----------|
|
|
97
|
+
| `get_tournaments(status)` | Список турниров (`active`, `upcoming`, `finished`) |
|
|
98
|
+
| `get_tournament(id)` | Детали турнира |
|
|
99
|
+
| `join_tournament(id)` | Вступить в турнир |
|
|
100
|
+
| `leave_tournament(id)` | Покинуть турнир |
|
|
101
|
+
|
|
102
|
+
### 💬 Форум
|
|
103
|
+
|
|
104
|
+
| Метод | Описание |
|
|
105
|
+
|-------|----------|
|
|
106
|
+
| `get_forum_threads(page, limit)` | Список тем |
|
|
107
|
+
| `get_forum_thread(slug)` | Получить тему с ответами |
|
|
108
|
+
| `create_forum_thread(title, body)` | Создать тему |
|
|
109
|
+
| `reply_to_thread(thread_id, body)` | Ответить в тему |
|
|
110
|
+
|
|
111
|
+
### 📰 Блог
|
|
112
|
+
|
|
113
|
+
| Метод | Описание |
|
|
114
|
+
|-------|----------|
|
|
115
|
+
| `get_blog_posts(page, limit)` | Список постов |
|
|
116
|
+
| `get_blog_post(post_id)` | Получить пост |
|
|
117
|
+
| `like_blog_post(post_id, unlike)` | Поставить/снять лайк |
|
|
118
|
+
|
|
119
|
+
### 🧩 Задачи (Puzzles)
|
|
120
|
+
|
|
121
|
+
| Метод | Описание |
|
|
122
|
+
|-------|----------|
|
|
123
|
+
| `get_puzzles(topic, difficulty, limit, offset)` | Список задач |
|
|
124
|
+
| `get_puzzle(puzzle_id)` | Детали задачи |
|
|
125
|
+
| `attempt_puzzle(puzzle_id, correct, moves)` | Отправить результат решения |
|
|
126
|
+
|
|
127
|
+
### ⚡ Storm
|
|
128
|
+
|
|
129
|
+
| Метод | Описание |
|
|
130
|
+
|-------|----------|
|
|
131
|
+
| `get_storm_puzzles(topics)` | Получить набор задач для шторма |
|
|
132
|
+
| `finish_storm(score, total_attempted, correct, wrong, time_bonus)` | Завершить забег |
|
|
133
|
+
|
|
134
|
+
### 🏛️ Клубы
|
|
135
|
+
|
|
136
|
+
| Метод | Описание |
|
|
137
|
+
|-------|----------|
|
|
138
|
+
| `get_clubs()` | Список всех клубов |
|
|
139
|
+
| `get_club(club_id)` | Информация о клубе |
|
|
140
|
+
| `create_club(name, description)` | Создать клуб (макс. 5 на пользователя) |
|
|
141
|
+
| `join_club(club_id)` | Вступить в клуб |
|
|
142
|
+
| `leave_club(club_id)` | Покинуть клуб |
|
|
143
|
+
| `update_club(club_id, name, description)` | Обновить клуб (только админ) |
|
|
144
|
+
| `get_club_chat(club_id)` | Чат клуба (только для участников) |
|
|
145
|
+
|
|
146
|
+
### ✉️ Личные сообщения (DM)
|
|
147
|
+
|
|
148
|
+
| Метод | Описание |
|
|
149
|
+
|-------|----------|
|
|
150
|
+
| `get_conversations()` | Список диалогов |
|
|
151
|
+
| `get_messages(partner, since)` | История сообщений с пользователем |
|
|
152
|
+
| `send_dm(to, text)` | Отправить сообщение |
|
|
153
|
+
| `mark_dm_read(partner)` | Отметить все сообщения как прочитанные |
|
|
154
|
+
| `block_user(username)` | Заблокировать пользователя |
|
|
155
|
+
| `unblock_user(username)` | Разблокировать |
|
|
156
|
+
|
|
157
|
+
### 🌐 Глобальный чат
|
|
158
|
+
|
|
159
|
+
| Метод | Описание |
|
|
160
|
+
|-------|----------|
|
|
161
|
+
| `get_global_chat(limit)` | Последние сообщения глобального чата (только чтение) |
|
|
162
|
+
|
|
163
|
+
### 📊 Статистика
|
|
164
|
+
|
|
165
|
+
| Метод | Описание |
|
|
166
|
+
|-------|----------|
|
|
167
|
+
| `get_stats()` | Общая статистика платформы |
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## 🧪 Примеры использования
|
|
172
|
+
|
|
173
|
+
### Получение статистики
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
stats = client.get_stats()
|
|
177
|
+
print(f"Всего пользователей: {stats['totals']['users']}")
|
|
178
|
+
print(f"Сыграно партий: {stats['totals']['games']}")
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Работа с клубами
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
# Создать клуб
|
|
185
|
+
new_club = client.create_club("Мой клуб", "Описание клуба")
|
|
186
|
+
print(f"Клуб создан: {new_club.id}")
|
|
187
|
+
|
|
188
|
+
# Вступить в клуб
|
|
189
|
+
client.join_club(new_club.id)
|
|
190
|
+
|
|
191
|
+
# Получить чат клуба
|
|
192
|
+
chat = client.get_club_chat(new_club.id)
|
|
193
|
+
for msg in chat.get('messages', []):
|
|
194
|
+
print(f"{msg['username']}: {msg['message']}")
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Задачи (Puzzles)
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
# Получить задачи по теме "Мат в 1 ход"
|
|
201
|
+
puzzles = client.get_puzzles(topic="mate1", limit=5)
|
|
202
|
+
for p in puzzles:
|
|
203
|
+
print(p['title'], p['difficulty'])
|
|
204
|
+
|
|
205
|
+
# Отправить результат решения (пример)
|
|
206
|
+
# client.attempt_puzzle(puzzles[0]['id'], correct=True, moves=[...])
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Подписки
|
|
210
|
+
|
|
211
|
+
```python
|
|
212
|
+
# Подписаться на пользователя
|
|
213
|
+
client.follow("username")
|
|
214
|
+
|
|
215
|
+
# Проверить подписку
|
|
216
|
+
is_following = client.check_follow("username")
|
|
217
|
+
print(is_following)
|
|
218
|
+
|
|
219
|
+
# Получить список подписчиков
|
|
220
|
+
followers = client.get_followers("username")
|
|
221
|
+
for f in followers:
|
|
222
|
+
print(f['username'])
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
## 📄 Лицензия
|
|
229
|
+
|
|
230
|
+
MIT License. См. файл [LICENSE](LICENSE).
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
**Разработано с ❤️ для сообщества Chess Home**
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
chesshome/__init__.py
|
|
5
|
+
chesshome/client.py
|
|
6
|
+
chesshome/models.py
|
|
7
|
+
chesshome.egg-info/PKG-INFO
|
|
8
|
+
chesshome.egg-info/SOURCES.txt
|
|
9
|
+
chesshome.egg-info/dependency_links.txt
|
|
10
|
+
chesshome.egg-info/requires.txt
|
|
11
|
+
chesshome.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
chesshome
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "chesshome"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Python client for ChessHome platform API"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "ChessHome", email = "noreply@chesshome.pro"}
|
|
14
|
+
]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
]
|
|
19
|
+
dependencies = [
|
|
20
|
+
"httpx>=0.24.0",
|
|
21
|
+
"pydantic>=2.0.0",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[project.urls]
|
|
25
|
+
Homepage = "https://chesshome.pro"
|