Metadata-Version: 2.4
Name: cristalixapi
Version: 2.2.2
Summary: Python client for https://api.cristalix.gg
Project-URL: Homepage, https://github.com/LisoMandiy/cristalixtopclaude
Author: LisoMandiy
License: MIT
License-File: LICENSE
Requires-Python: >=3.10
Requires-Dist: httpx[http2]>=0.27.0
Description-Content-Type: text/markdown

# CristalixAPI

Python-библиотека для работы с [Cristalix Public API](https://top.cristalix.gg/api-docs).

Есть синхронный и асинхронный клиент, типизированные ответы и автоматические повторы при rate limit.

## Установка

```bash
pip install cristalixapi
```

## Авторизация

1. Войди на [top.cristalix.gg/api-docs](https://top.cristalix.gg/api-docs) через аккаунт Cristalix.
2. Создай проект — получишь `project_key` и `project_token`.
3. Токен показывается один раз. Если потерял — пересоздай через «Пересоздать токен».

## Быстрый старт

```python
from cristalixapi import CristalixClient

with CristalixClient(project_key="YOUR_PROJECT_KEY", token="YOUR_TOKEN") as client:
    profile = client.get_profile_by_name("LisoMandiy")
    print(profile["name"], profile["groups"])
```

## Асинхронный вариант

```python
import asyncio
import httpx
from cristalixapi import AsyncCristalixClient

async def main():
    limits = httpx.Limits(max_connections=50, max_keepalive_connections=10)
    async with AsyncCristalixClient(project_key="YOUR_PROJECT_KEY", token="YOUR_TOKEN", limits=limits) as client:
        profile = await client.get_profile_by_name("LisoMandiy")
        print(profile)

asyncio.run(main())
```

## Что умеет клиент

### Игры

```python
# Список активных игр с режимами и полями статистики
games = client.get_games()
game_id = games[0]["gameId"]
```

### Лидерборды

```python
# Топ-10 по победам
top = client.get_leaderboard(game_id, field="wins", limit=10)

# Топ с динамикой (немного медленнее)
top = client.get_leaderboard(game_id, field="wins", trends=True)

# Топ с данными по всем периодам сразу
rich = client.get_leaderboard_rich(game_id, field="wins", period="WEEK")
```

Периоды: `HOUR`, `DAY`, `WEEK`, `MONTH`, `QUARTER`, `YEAR`, `ALL`.

### Статистика игрока

```python
# Статистика за конкретный период
stats = client.get_player_stats(game_id, player_id, period="WEEK")
print(stats["fields"])  # {"wins": 5, "kills": 15, ...}

# Сразу все периоды
periods = client.get_player_periods(game_id, player_id)
print(periods["periods"]["ALL"])

# Позиция в топе
pos = client.get_player_position(game_id, player_id, field="wins")
print(pos["position"])  # -1 если игрок не в рейтинге

# Вся статистика по всем играм одним запросом
all_stats = client.get_player_aggregated_stats(player_id)
```

### Профили

```python
# По UUID
profile = client.get_profile_by_id("5b23daba-9b07-11ed-a328-1cb72cb014ae")

# По нику
profile = client.get_profile_by_name("LisoMandiy")

# Много игроков сразу (до 200)
batch = client.get_profiles_batch(["5b23daba-9b07-11ed-a328-1cb72cb014ae", "31e609bc-169b-11ea-ba20-1cb72caa35fd"])
print(batch["found"], batch["notFound"])

# То же самое по никам
batch = client.get_profiles_batch_names(["LisoMandiy", "kkp_"])

# Поиск по префиксу ника (автокомплит)
results = client.search_players("Ko", limit=5)
```

Лёгкий режим `lite=True` возвращает только `playerId`, `name`, `status`, `groups` — удобно для списков.

### Социальные данные

```python
# Друзья
friends = client.get_friends(player_id, limit=50)

# Подписчики (INCOMING) или подписки (OUTGOING)
subs = client.get_subscribers(player_id, type="OUTGOING")

# История смены ников
history = client.get_name_history(player_id)

# Текущий онлайн и реалм
location = client.get_location(player_id)

# Кто поставил лайк / дизлайк
reactions = client.get_reactions(player_id, type="LIKE")
```

### Рейтинги

```python
top_karma = client.get_ratings_karma(limit=10)
top_likes = client.get_ratings_likes(limit=10)
top_views = client.get_ratings_views(limit=10)
```

### Справочники

```python
# Все группы с цветами и префиксами — кэшируй на ~5 минут
roles = client.get_roles()

# Сколько стафф сейчас онлайн по группам
counts = client.get_staff_counts()
# {"HELPER": 158, "MODERATOR": 27, "TESTER": 28}
```

## Настройка клиента

```python
client = CristalixClient(
    project_key="YOUR_PROJECT_KEY",
    token="YOUR_TOKEN",
    timeout=15.0,        # таймаут запроса в секундах
    max_retries=3,       # повторов при 429
    enforce_http2=True,  # упасть если сервер не HTTP/2
)
```

## Обработка ошибок

```python
from cristalixapi import (
    CristalixClient,
    CristalixHTTPError,
    CristalixRateLimitError,
    CristalixValidationError,
)

try:
    with CristalixClient(project_key="YOUR_PROJECT_KEY", token="YOUR_TOKEN") as client:
        profile = client.get_profile_by_name("LisoMandiy")
except CristalixValidationError as e:
    print("Неверный параметр:", e)
except CristalixRateLimitError as e:
    print("Rate limit:", e.status_code)
except CristalixHTTPError as e:
    print(f"HTTP {e.status_code}:", e.payload)
```

| Исключение | Когда |
|---|---|
| `CristalixValidationError` | Неверные параметры на стороне клиента |
| `CristalixRateLimitError` | 429 после всех повторов |
| `CristalixHTTPError` | Любой другой 4xx/5xx |
| `CristalixProtocolError` | Сервер ответил не по HTTP/2 |

## Лимиты API

- **320 запросов/мин** на проект (общий лимит).
- **60 запросов/мин** для `search_players` — отдельный лимит, не расходует общий.
- При 429 клиент автоматически делает повтор с экспоненциальной задержкой.

## Приватность

Если игрок скрыл данные, в ответе будет `privacyHidden: true`, а сами поля заменятся на `null`, `-1` или `[]`. Это нормальное поведение API — просто проверяй этот флаг перед отображением данных.