# 🎵 Beatport Discography Searcher

Универсальный веб-сервис для поиска и просмотра полной дискографии исполнителей на **Beatport** (электронная музыка). Реализован на Next.js + Beatport API v4 OAuth2.

![Dark Theme](https://img.shields.io/badge/theme-dark-18181b) ![Beatport](https://img.shields.io/badge/Beatport-API%20v4-FF6B00) ![Next.js](https://img.shields.io/badge/Next.js-16-black)

## ✨ Возможности

- 🔍 **Поиск артистов** по имени (Beatport catalog search)
- 👤 **Шапка профиля**: фото, имя, статистика
  - Релизов автор #1 (≥50% участия), всего релизов, треков, как артист/ремиксер, исключено по правилу 50%
- 📀 **3 вкладки:**
  1. **Releases** — собственные релизы, где артист первый автор **и** участвует минимум в 50% треков треклиста. Иначе релиз переходит только в All Releases
  2. **All Releases** — все релизы с участием (бейджи Автор #1 / Участник + % участия)
  3. **Tracks** — все треки с превью, BPM, ключ (Camelot), жанр, длина, роль
- ⏱️ **Общее время звучания** в карточках релизов и в статистике (сумма `length_ms` треков артиста в релизе)
- 🎧 **Аудио-плеер** — 30-секундные превью Beatport, фиксированная панель
- 🔑 **Универсальная конфигурация**: ввод своих `client_id / username / password` при первом запуске
  - Сохранение в `/tmp/bp_user_config.json` и `~/.beatport/config.json` (кросс-платформенно)
  - Поддержка `BP_CONFIG_PATH`, `BEATPORT_*` env vars
  - Авто-определение демо/пользовательского аккаунта
- 🕒 **Токен-менеджмент:**
  - Показ времени выпуска, истечения, обратного отсчёта (MM:SS)
  - Прогрессбар lifetime токена (10 мин)
  - Кнопка «Перевыпустить token» (refresh) + Full login
  - Чекбокс «Авто-перевыпуск за 1 мин до окончания»
  - Обработка HTML-ответов Cloudflare → понятные ошибки, retry
- 📊 **Правило 50%**: не считать собственным релиз, если в треклисте <50% треков искомого исполнителя (нет тегов). Такой релиз → только All Releases

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

### Требования
- Node.js 18+ / 20+
- NPM
- Аккаунт Beatport (для своего токена) + Client ID из https://api.beatport.com/v4/docs/ (JS бандл)

### Установка

```bash
npm install
cp .env.example .env
# Отредактируйте DATABASE_URL если нужно (для шаблона, не обязательно для Beatport)
```

### Запуск (dev)

```bash
npm run dev
# Открыть http://localhost:3000
```

### Production

```bash
npm run build
npm start
# или
npx next start -p 5555
```

### Первый запуск (универсальный)

1. Откройте http://localhost:3000
2. Если используется демо-конфиг (musinjector), увидите янтарный баннер «Используется демо-конфигурация»
3. Нажмите ⚙️ **Настроить** → введите:
   - **Client ID** — публичный, найдите в DevTools → Sources → `api.beatport.com/v4/docs/` → JS bundle содержит `client_id`. Дефолт: `0GIvkCltVIuPkkwSJHp6NDb3s0potTjLBQr388Dd`
   - **Username** — логин Beatport
   - **Password** — пароль Beatport
4. «Сохранить и получить токен» → токен выпускается за 2-3 сек (full login flow)
5. Сохранение: `/tmp/bp_user_config.json` + `~/.beatport/config.json` (права 600)
6. Токен: `/tmp/bp_tokens.json` (переопределение через `BP_TOKEN_PATH` / `BP_CONFIG_PATH` / `BP_TOKEN_DIR`)

**Env vars альтернатива:**

```bash
BEATPORT_CLIENT_ID=0GIvkClt...
BEATPORT_USERNAME=your_login
BEATPORT_PASSWORD=your_password
BP_CONFIG_PATH=~/.beatport/config.json
npm start
```

## 🔧 API

| Endpoint | Метод | Описание |
|---|---|---|
| `/api/beatport/search?q=` | GET | Поиск артистов |
| `/api/beatport/artist/[id]` | GET | Детали артиста |
| `/api/beatport/artist/[id]/discography` | GET | Все треки + релизы (пагинация 100, кэшируется) |
| `/api/beatport/token` | GET/POST | Статус токена, перевыпуск (refresh/full) |
| `/api/beatport/config` | GET/POST/DELETE | Конфигурация пользователя |
| `/api/health` | GET | Health check + token/config status |

### Токен flow

1. `POST https://account.beatport.com/identity/v1/login/ {username,password}` → cookies
2. `GET https://account.beatport.com/o/authorize/?client_id=&redirect_uri=&response_type=code` → 302 Location `code`
3. `POST https://account.beatport.com/o/token/ {client_id, code, grant_type=authorization_code}` → access_token (600s) + refresh_token
4. Refresh: `POST /o/token/ {client_id, refresh_token, grant_type=refresh_token}` → новый refresh_token (rotation!)

Сервис автоматически обновляет токен за 60 сек до истечения если включен чекбокс.

## 📏 Правило 50%

```ts
// Псевдокод
count = tracks.filter(t => t.release.id == release.id).length // треков артиста в релизе
total = release.track_count
rate = count / total
if (release.artists[0].id == artistId && rate >= 0.5) -> Releases
else -> только All Releases
```

Пример Delerium:
- Сырых релизов где автор #1: 113
- После 50%: 105 (исключено 8 типа Chillout Friends 4/16=25%, Armada compilations 1/40=2.5%)

## ⏱️ Время звучания

Для каждого релиза считается сумма `length_ms` треков артиста в нём:

```ts
releaseDurations.get(release.id) = { totalMs, count }
formatDurationMs(totalMs) => H:MM:SS
```

Показывается:
- Бейдж на обложке
- В карточке: `42:15` + `(1/1 треков • 100%)`
- В статистике: общее время всех собственных релизов

## 🛡️ Безопасность

- Пароль хранится в файле с правами 600, не попадает в git
- API никогда не отдаёт полный пароль или токен, только masked preview
- Client ID — публичный (встроен в JS бандл docs)
- `safeJsonParse()` детектит HTML от Cloudflare и показывает понятную ошибку вместо `<!doctype ... is not valid JSON`

## 🎨 Стек

- Next.js 16 (App Router, Turbopack)
- Tailwind CSS 4
- Beatport API v4
- TypeScript

## 📦 Структура

```
src/
  lib/
    beatport.ts      # OAuth2 + config + cache + fetch
    cache.ts         # In-memory LRU cache
  app/
    api/beatport/...
    page.tsx         # Монолитный клиент (можно разбить на components/)
    globals.css
    layout.tsx
```

## 🔮 Возможные улучшения (аудит)

- [x] Кэширование поиска и дискографии (in-memory TTL)
- [x] Debounce поиска + shareable URL (?q=, ?artist=)
- [x] Пагинация треков (50/страница) + сортировка по колонкам
- [x] Экспорт треков в CSV
- [x] Ленивая загрузка изображений, виртуализация
- [x] История поиска в localStorage
- [x] Настраиваемый порог 50% через slider
- [x] Health check расширенный
- [ ] Разбиение page.tsx на компоненты (TokenPanel, ConfigModal, etc.)
- [ ] E2E тесты
- [ ] Dockerfile + start.bat/start.sh
- [ ] PWA

## 📄 Лицензия

MIT — не аффилирован с Beatport. Используйте ответственно, соблюдайте rate limits.

---

*Пример: Delerium ID 10426 → 105 собственных (≥50%), 223 всего, 839 треков.*
