Metadata-Version: 2.4
Name: cloudtips
Version: 0.4.0
Summary: Неофициальная асинхронная Python-библиотека для CloudTips (получение донатов, поллинг, обновление токенов)
Project-URL: Repository, https://github.com/IRRatium/cloudtips-api
Project-URL: Issues, https://github.com/IRRatium/cloudtips-api/issues
License: MIT
License-File: LICENSE
Keywords: api,async,asyncio,cloudtips,donations,payments,tips
Classifier: Framework :: AsyncIO
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Internet :: WWW/HTTP
Requires-Python: >=3.9
Requires-Dist: aiohttp>=3.9
Description-Content-Type: text/markdown

# CloudtipsAPI

Неофициальная асинхронная Python-библиотека для [CloudTips](https://cloudtips.ru) — получение донатов, поллинг новых поступлений и автоматическое обновление токенов.

## Установка

```bash
pip install cloudtips
```

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

```python
import asyncio
import json
from cloudtips import CloudTipsAuth, CloudTipsClient, TokenData

# Загружаем токены из файла
with open("donate.json") as f:
    config = json.load(f)

# Колбэк вызывается каждый раз при обновлении токенов.
# Поддерживаются как async, так и обычные функции.
# Refresh-токен одноразовый — обязательно сохраняйте новые!
async def on_token_refresh(token_data: TokenData):
    config["cloudtips_token"] = token_data.access_token
    config["cloudtips_refresh_token"] = token_data.refresh_token
    config["cloudtips_expires_at"] = token_data.expires_at
    with open("donate.json", "w") as f:
        json.dump(config, f, ensure_ascii=False, indent=2)
    print("Токены обновлены и сохранены.")

auth = CloudTipsAuth(
    token=config["cloudtips_token"],
    refresh_token=config["cloudtips_refresh_token"],
    expires_at=config["cloudtips_expires_at"],
    on_token_refresh=on_token_refresh,
)

async def main():
    async with CloudTipsClient(auth) as client:
        donations = await client.get_all_donations()
        for d in donations:
            print(d)

asyncio.run(main())
```

## Получение донатов

```python
async with CloudTipsClient(auth) as client:
    # Все донаты за последние 24 часа
    donations = await client.get_all_donations()
    for d in donations:
        print(d)  # [2026-04-10 20:44] евгения → 50₽ — "оч крутой сервис"

    # Только за конкретный период
    from datetime import datetime, timedelta, timezone

    yesterday = datetime.now(tz=timezone.utc) - timedelta(days=1)
    recent = await client.get_donations(since=yesterday)
```

## Поллинг новых донатов

### Вариант 1 — async-генератор

```python
async with CloudTipsClient(auth) as client:
    print("Слушаем новые донаты...")
    async for donation in client.poll(interval=30):
        print(f"💰 {donation.name} задонатил {donation.amount}₽")
        if donation.comment:
            print(f"   Комментарий: {donation.comment}")
```

### Вариант 2 — async-колбэк

```python
async def handle_donation(donation):
    print(f"Новый донат от {donation.name}: {donation.amount}₽")
    # await bot.send_message(...)

async with CloudTipsClient(auth) as client:
    await client.poll(interval=15, callback=handle_donation)
```

### Вариант 3 — в фоновой задаче asyncio

```python
async def poll_task(client):
    async for donation in client.poll(interval=30):
        print(f"Новый донат: {donation}")

async def main():
    async with CloudTipsClient(auth) as client:
        task = asyncio.create_task(poll_task(client))
        # Основная логика...
        await task

asyncio.run(main())
```

## Профиль, карты и баланс

```python
async with CloudTipsClient(auth) as client:
    # Профиль пользователя
    me = await client.get_me()
    print(me.full_name)        # IRRing
    print(me.payout_method)    # Accumulation

    # Привязанные карты
    for card in await client.get_cards():
        print(card)            # MIR *3742 (T-BANK, до 08/34) [по умолчанию]
        print(card.token)      # tk_89e6b3c6827afd4e9ccc36db2d22f

    # Баланс к выводу
    s = await client.get_accumulation_summary()
    print(f"Накоплено: {s.accumulated_amount}₽")
    print(f"Комиссия: {s.commission_percent}%")
    print(f"Следующая выплата: {s.next_payout_date or 'не запланирована'}")

    # Информация о комиссиях
    fee = await client.get_payout_fee_info()
    print(fee.text)

    # Смена метода выплат
    await client.set_payout_method("Instant")        # мгновенно
    await client.set_payout_method("Accumulation")   # накопительно

    # Удаление карты
    for card in await client.get_cards():
        await client.delete_card(card.token)
```

## Структура `Donation`

```python
@dataclass
class Donation:
    transaction_id: int    # уникальный ID транзакции
    name: str              # имя донатера
    amount: int            # сумма в рублях
    tg_id: int             # Telegram ID
    comment: str           # комментарий (может быть пустым)
    date: datetime         # дата и время

str(donation)
# "[2026-04-10 23:04] Каспер → 200₽ — "спасибо за отличный сервис)""
```

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

```python
from cloudtips import CloudTipsAuthError, CloudTipsAPIError

try:
    async with CloudTipsClient(auth) as client:
        donations = await client.get_donations()
except CloudTipsAuthError as e:
    print(f"Проблема с аутентификацией: {e}")
except CloudTipsAPIError as e:
    print(f"Ошибка API (HTTP {e.status_code}): {e.detail}")
```

## Примечания

- **Refresh-токен одноразовый.** После каждого обновления старый токен становится недействительным. Всегда передавайте `on_token_refresh` и сохраняйте новые токены.
- `on_token_refresh` поддерживает как обычные (`def`), так и async-функции (`async def`).
- Библиотека автоматически обновляет токен за 2 минуты до истечения.
- Поллинг отслеживает уже виденные `transaction_id`, поэтому дублей не будет.
- Клиент — контекстный менеджер (`async with`), это рекомендуемый способ использования.

## Лицензия

MIT
