# RUTUBE API: автоматическая загрузка видео

Реализация по официальной документации RUTUBE API: CMS загружает видеофайл на RUTUBE, RUTUBE присылает callback с готовым `video_id`, CMS сохраняет связку `article_id ↔ video_id` в своей БД.

Источник: `RUTUBE_Документация_API_загрузка_контента_каналы_и_плейлисты.docx`.

## Pipeline целиком

```
┌──────────────────────────────────────────────────────────────────┐
│ Редактор в CMS:                                                  │
│   1. Создаёт статью с article_id = 12345                         │
│   2. Загружает файл video.mp4 (drag-n-drop в админке)            │
└─────────────────────────────────┬────────────────────────────────┘
                                  ↓
┌──────────────────────────────────────────────────────────────────┐
│ CMS вашего сайта:                                                │
│   POST https://rutube.ru/api/video/                              │
│   Headers: Authorization: Token <RUTUBE_TOKEN>                   │
│   Body:                                                          │
│     url=https://woman.ru/uploads/video.mp4                       │
│     callback_url=https://woman.ru/rutube/callback                │
│     title=Заголовок видео                                        │
│     extra={"article_id":"12345"}                                 │
└─────────────────────────────────┬────────────────────────────────┘
                                  ↓ (мгновенно)
┌──────────────────────────────────────────────────────────────────┐
│ RUTUBE отвечает:                                                 │
│   {"video_id":"479c58a745de50383649a3a0c7c7f0c5"}                │
│                                                                  │
│ ↑ Можно сразу опубликовать статью. Плеер появится через 1-5 мин  │
│   после конвертации видео в плеер-формат.                        │
└─────────────────────────────────┬────────────────────────────────┘
                                  ↓ (через 1-5 минут)
┌──────────────────────────────────────────────────────────────────┐
│ RUTUBE сам дёргает ваш callback:                                 │
│   POST https://woman.ru/rutube/callback                          │
│   {                                                              │
│     "id": "479c58a745de50383649a3a0c7c7f0c5",                    │
│     "html": "<iframe ...></iframe>",                             │
│     "embed_url": "...",                                          │
│     "session": {"extra": {"article_id":"12345"}}                 │
│   }                                                              │
└─────────────────────────────────┬────────────────────────────────┘
                                  ↓
┌──────────────────────────────────────────────────────────────────┐
│ CMS вашего сайта:                                                │
│   Сохраняет в БД: article_id=12345 → video_id=479c...            │
└─────────────────────────────────┬────────────────────────────────┘
                                  ↓
┌──────────────────────────────────────────────────────────────────┐
│ При рендере статьи 12345:                                        │
│   <div data-rutube="479c58a745de50383649a3a0c7c7f0c5"></div>     │
│                                                                  │
│   Плеер появляется автоматически через rutube-video-wrapper.js.  │
└──────────────────────────────────────────────────────────────────┘
```

## Что нужно реализовать на вашей стороне

1. **Функция загрузки** в CMS - один HTTP POST к RUTUBE при сохранении статьи с видео
2. **Callback endpoint** - принимает POST от RUTUBE с финальным `video_id`
3. **Таблица в БД** - `rutube_videos(article_id, video_id, created_at)` - связка статьи и видео
4. **Шаблон статьи** - при рендере проверяет наличие `video_id` для статьи и вставляет `<div data-rutube="...">`

## Получение API-токена RUTUBE (один раз)

```bash
curl -X POST https://rutube.ru/api/accounts/token_auth/ \
  -d "username=ВАШ_EMAIL" \
  -d "password=ВАШ_ПАРОЛЬ"

# Ответ: {"token":"d9fec6ee60f40d2d937b36ea9c4920bca2219150"}
```

Токен сохраняете в env-переменной `RUTUBE_TOKEN` и используете во всех запросах.

## Примеры реализации

| Стек | Файл |
|---|---|
| Python / FastAPI / Flask | [`python-fastapi.py`](./python-fastapi.py) |
| PHP / WordPress | [`php-wordpress.php`](./php-wordpress.php) |
| Node.js / Express | [`nodejs-express.js`](./nodejs-express.js) |

## Параметры `POST /api/video/`

| Параметр | Тип | Обязателен | Описание |
|---|---|---|---|
| `url` | string | ✓ | Прямая HTTPS-ссылка на видеофайл на вашем CDN (например, `https://woman.ru/uploads/2026/05/video.mp4`). Файл должен быть доступен извне для RUTUBE-конвертера. |
| `callback_url` | string | - | URL, который RUTUBE вызовет после успешной конвертации |
| `errback_url` | string | - | URL для уведомления об ошибке конвертации |
| `title` | string | - | Название ролика (до 100 символов) |
| `description` | string | - | Описание (до 5000 символов) |
| `category_id` | int | - | ID категории RUTUBE (по умолчанию 13 - «Частные объявления») |
| `extra` | string (json) | - | Произвольные данные, возвращаются в callback. Сюда кладём `{"article_id":"..."}` |
| `is_hidden` | boolean | - | Скрытый ролик (только по ссылке) |
| `author` | int | - | ID канала-получателя (если у токена доступ к нескольким) |

## Что приходит в callback

```json
{
  "id": "479c58a745de50383649a3a0c7c7f0c5",
  "title": "Заголовок",
  "description": "...",
  "thumbnail_url": "https://pic.rutube.ru/...",
  "video_url": "https://rutube.ru/video/...",
  "embed_url": "/video/embed/...",
  "html": "<iframe ...></iframe>",
  "duration": 120,
  "session": {
    "extra": { "article_id": "12345" }  ← наш ключ для связки
  }
}
```

## Безопасность callback endpoint

⚠️ **Защитите callback от посторонних запросов.** RUTUBE не подписывает callback. Варианты:

1. **Проверка IP** - RUTUBE отправляет callback с известных IP, можно whitelist (запросите у менеджера)
2. **Секретный токен в URL** - `callback_url=https://woman.ru/rutube/callback?secret=ABCXYZ`
3. **Проверка существования `extra.article_id`** в вашей БД - только если статья реально была загружена через вас, callback валидный

Минимум - проверка `extra.article_id` существует в вашей системе.

## Сценарии ошибок

| Ситуация | Что приходит | Что делать |
|---|---|---|
| Файл недоступен по URL | POST на `errback_url` | Связаться с RUTUBE поддержкой, переключиться на ручной upload |
| Файл повреждён | POST на `errback_url` | Удалить из CMS, попросить редактора перезагрузить |
| Callback не пришёл за 30 мин | Тишина | Опросить `GET /api/video/<video_id>/` явно через ваш `video_id` из шага 1 |
| RUTUBE недоступен | 5xx на POST `/api/video/` | Retry с exponential backoff, или fallback на ручной upload |

## Другие способы интеграции

| Способ | Что делает редактор |
|---|---|
| CMS inline iframe | Вставляет 6 строк HTML в WYSIWYG |
| JS-сниппет с `data-rutube="..."` | Вставляет URL видео в поле CMS |
| API workflow (этот документ) | Загружает файл в админке |

## Поддержка

Вопросы - `hi@egor-yudin.ru` или https://github.com/yudinegor/embed/issues
