# MyYouTube Персональный YouTube-клиент с категориями подписок и интеграцией с существующим MeTube. Работа агентской команды (opencode) описана в секции «Агентская команда (opencode)» ниже; роли агентов — в `.opencode/agent/`. Текущий статус: **функционально готово** (основные этапы 1–6 и доработки по итогам тестирования). Развёрнуто и вручную протестировано на тестовом окружении (`testmyyoutube.vrubel.xyz` → hermesVM `192.168.8.173` → MeTube на mediaVM `192.168.8.177`). ### Что сделано - Skeleton, Google OAuth (single-user allow-list), sync подписок/видео (APScheduler), категории (CRUD + many-to-many), лента с курсорной пагинацией, YouTube-плеер, полная MeTube-интеграция (download/delete, Socket.IO live-статусы, recovery после рестарта). - Режим «Каналы» на главной (`?view=channels`): переключатель «Лента | Каналы», список подписанных каналов по свежести последнего видео с тремя последними роликами в строке; фильтр категорий из сайдбара действует в обоих режимах. - Раздел **«На сервере»** — скачанные видео; `/saved` перенаправляет на `/local`. - Разделение видео на **Shorts** и обычные по длительности (`SHORTS_MAX_DURATION_SECONDS`, по умолчанию 180 сек; неизвестная длительность — обычное видео): сегмент-фильтр «Обычные | Shorts» во всех списках видео (по умолчанию «Обычные», `?type=short` для Shorts; `?type=all`/`?type=long`/неизвестное трактуются как «Обычные») и вертикальная full-screen лента Shorts (`/shorts/:youtubeVideoId`) с автоплеем активного ролика и бесконечной подгрузкой в контексте открытого фильтра. REST `GET /api/feed` по-прежнему поддерживает `type=all|long|short` (совместимость с будущим mobile/PWA-клиентом), UI вариант `all` не использует. - Тёмный адаптивный интерфейс: общая навигация, категории с постоянными URL, поиск по названиям видео и каналов, мобильное меню. - Отписанные каналы скрываются из списка каналов. - Реальная отписка от канала на YouTube (`subscriptions.delete`) реализована по запросу пользователя сверх исходного MVP. Из-за этого OAuth scope расширен с `youtube.readonly` до полного `youtube` (read/write) — см. `backend/app/services/google_oauth.py`. - Удаление скачанного видео с сервера (`DELETE /api/videos/{id}/download`) — тоже сверх исходного MVP-скоупа, добавлено по запросу. ### Что осталось / сознательно отложено - Дополнительные идеи после MVP пока не реализованы: PWA, watch later, SponsorBlock и т.д. - Hardening (retry/recovery, тесты) выполнялся по факту находок в live-тестировании, а не отдельным проходом — см. `git log` для конкретных багфиксов (flapping статусов загрузки, неверный id в MeTube `/delete`, OAuth scope mismatch). ## Стек - Backend: Python 3.13, FastAPI, SQLAlchemy 2.x, Alembic, Pydantic Settings - Frontend: React, TypeScript, Vite, React Router, TanStack Query - DB: PostgreSQL 16 - Deployment: Docker Compose ## Запуск в production (Docker Compose) 1. Скопируй `.env.example` в `.env` и заполни значения (Google OAuth credentials, секреты, MeTube URLs). 2. Собери и запусти: ```bash docker compose up -d --build ``` 3. Проверь health: ```bash curl http://localhost:8080/api/health ``` Миграции Alembic применяются автоматически при старте контейнера `app` (см. `entrypoint.sh`). ## Локальная разработка ### Агентская команда (opencode) Работа идёт в одной сессии opencode: она стартует агентом `orchestrator` (`default_agent` в `opencode.json`). Порядок работы: `orchestrator → analyst (аналитика/README) → coder → reviewer → tester`. Orchestrator сам декомпозирует задачу и вызывает субагентов через Task tool: `analyst` (до Coder'а фиксирует задачу в `analytics/*.md` и при необходимости актуализирует README), `coder` (единственный меняет код продукта), `reviewer` (read-only review, `edit: deny`) и `tester` (проверки без правок, `edit: deny`). Роли описаны в [`.opencode/agent/`](./.opencode/agent/). Аналитика задач ведётся в [`analytics/`](./analytics/) (см. `analytics/README.md`). ```bash opencode ``` Задачу пиши обычным сообщением: Orchestrator передаст её сначала Analyst'у (аналитика и README), затем Coder'у, соберёт review и QA, повторит цикл при находках и вернёт финальный отчёт. Вручную писать субагентам не нужно. ### Backend ```bash cd backend uv venv .venv uv pip install -p .venv -r requirements-dev.txt source .venv/bin/activate cd .. DATABASE_URL=postgresql+psycopg://youtube_app:password@localhost:5432/youtube_app \ APP_SECRET_KEY=dev APP_SECRET_KEY=dev TOKEN_ENCRYPTION_KEY=dev \ alembic upgrade head uvicorn app.main:app --reload --app-dir backend --port 8080 ``` Тесты: ```bash backend/.venv/bin/python -m pytest tests/ -v ``` ### Frontend ```bash cd frontend npm install npm run dev ``` Dev-сервер Vite проксирует `/api/*` на `http://127.0.0.1:8080` (см. `vite.config.ts`). ## Миграции ```bash alembic revision -m "описание" alembic upgrade head ``` `alembic.ini` и папка `migrations/` находятся в корне проекта и подключают модели из `backend/app`. ## Структура проекта ```text myyoutube/ ├── backend/ # FastAPI приложение ├── frontend/ # React SPA ├── migrations/ # Alembic migrations ├── tests/ # backend tests (pytest) ├── analytics/ # аналитика задач агентской команды ├── Dockerfile ├── compose.yml ├── .env / .env.example └── .opencode/ # агенты команды (orchestrator/analyst/coder/reviewer/tester) ``` ## Секреты `.env` в `.gitignore`, не коммитится. Обязательные секреты: `APP_SECRET_KEY`, `TOKEN_ENCRYPTION_KEY`, `GOOGLE_CLIENT_SECRET`, `POSTGRES_PASSWORD`.