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.
@@ -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.
@@ -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,4 @@
1
+ from .client import ChessHomeClient
2
+ from .models import User, Tournament, ForumThread, BlogPost, Conversation, Message, Club
3
+
4
+ __version__ = "0.1.0"
@@ -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,2 @@
1
+ httpx>=0.24.0
2
+ pydantic>=2.0.0
@@ -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"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+