# Sort YM Раскладывает лайкнутые треки Яндекс.Музыки по плейлистам вида `Жанр — RU` / `Жанр — INT`. ``` $ python -m sort_ym report Распределение по плейлистам: Рок — INT: 143 Рок — RU: 287 Рэп — RU: 512 ... Отчёт сохранён: out/report.csv ``` ## Установка Требования: Python 3.11+ (используется `tomllib` из стандартной библиотеки), Windows/Linux/macOS, доступ в интернет. ``` python -m venv .venv .venv\Scripts\pip install -r requirements.txt ``` Для разработки (тесты): ``` .venv\Scripts\pip install -r requirements-dev.txt ``` ## Что делает ``` .venv\Scripts\python -m sort_ym auth # войти в аккаунт Яндекса через device-flow и сохранить токен в .token .venv\Scripts\python -m sort_ym fetch # скачать лайкнутые треки (cache/tracks.json) и жанры их артистов (cache/artist_genres.json); аккаунт не меняет .venv\Scripts\python -m sort_ym report # посчитать жанр и язык каждого трека, сохранить out/report.csv (аккаунт не меняет) .venv\Scripts\python -m sort_ym apply --limit 20 --yes # пробный запуск: создать плейлисты и добавить в них первые 20 треков .venv\Scripts\python -m sort_ym apply --yes # создать плейлисты и добавить в них все треки (меняет аккаунт) ``` При повторных запусках `fetch` докачивает только новые треки, а `apply` не дублирует уже добавленные треки. ## Полная очистка кэша Если требуется начать с чистого листа (переполучить все данные с нуля), удалите папку `cache/`: ``` Remove-Item -Recurse -Force cache ``` Кэш состоит из четырёх файлов: - `cache/tracks.json` — список лайкнутых треков и их метаданные (включая id артистов); - `cache/artist_genres.json` — жанровые теги каждого артиста (может быть несколько на артиста); - `cache/genre_catalog.json` — снимок дерева жанров Яндекса на момент последнего запуска; - `cache/lyrics_lang.json` — определённые языки текстов для каждого трека. Удаление `cache/` заставит `fetch` и `report` переполучить всё с нуля при следующем запуске. Также можно удалить сгенерированный отчёт: ``` Remove-Item -Recurse -Force out ``` Это просто результаты анализа, их удаление не повлияет на следующий запуск `report`. **Важно:** файл `.token` (OAuth-токен) не входит в кэш и не удаляется при очистке `cache/`. Очистка кэша вас не разлогирует. Если нужна повторная авторизация, удалите `.token` отдельно: ``` Remove-Item .token ``` ## Как определяется жанр и язык - **Жанр** определяется на **под-жанровом** уровне (Рок, Панк, Инди, Альтернатива, Метал, ..., не только 11 крупных групп), комбинируя два сигнала: 1. Жанр **альбома** трека (`genre_raw`) — сигнал по конкретному треку. 2. Жанры **артиста** (`Artist.genres`, может быть несколько тегов на артиста, точнее одного альбомного жанра) — сигнал по исполнителю в целом. Если сигналы совпадают — берётся под-жанр как есть. При конфликте: если альбомный тег общий ("зонтичный", вроде `rock`/`alternative`/`pop` — типичный дефолт Яндекса низкой уверенности) — побеждает жанр артиста; если альбомный тег точный/специфичный (`numetal`, `dnb`, `shanson`) — побеждает он, потому что это, скорее всего, реальный эксперимент артиста в другом жанре, а не шум. Так один и тот же артист с разными по духу треками (например, рОк-трек и панк-трек) раскладывается по разным плейлистам, а не весь скопом по одному "основному" жанру. Под-жанровые группы меньше `small_group_min` (по умолчанию 12 треков, `config.toml`) схлопываются в родительскую крупную корзину (Поп, Рок, Метал, Рэп, Электроника, Джаз и блюз, Классика, Фолк и world, Инди и альтернатива, Саундтреки, Разное), чтобы не плодить плейлисты на 1-2 трека. Реализация — `sort_ym/genres.py` (`classify_track`, `ROOT_BUCKET`) — таблица корней легко дополняется, если Яндекс вернёт незнакомый корневой жанр. - **Язык** — гибрид: 1. Если у трека есть текст песни — реальный язык из API (`ru` → RU, иначе → INT). 2. Иначе — подсказка по жанру (`rusrap`, `shanson`, `bard`, ...). 3. Иначе — по алфавиту названия/исполнителя (кириллица/латиница). 4. Если ничего не сработало — трек попадает в `... — Не определено`. После `report` в консоли также печатается список нераспознанных жанров (попавших в «Разное»), чтобы можно было дополнить таблицу в `sort_ym/genres.py`. ## Handy things - Первый прогон `apply` делайте с `--limit 20 --yes` и проверьте результат в приложении, прежде чем запускать на все ~2000 треков. - Настройки задержек между запросами — в `config.toml` (`[throttle]`). - Минимальный размер под-жанрового плейлиста — `config.toml` (`[classify] small_group_min`). ## Риски (неофициальный API) Официального API для личной библиотеки Яндекс.Музыки нет — инструмент использует неофициальную библиотеку `yandex-music`. OAuth-токен в `.token` даёт полный доступ к аккаунту Яндекса — храните его локально и не публикуйте. Инструмент выполняет только безопасные действия (чтение лайков, создание плейлистов, добавление треков) и ничего не удаляет. ## For developers Python 3.11+, `yandex-music==3.0.0`, стандартная библиотека (`tomllib`, `csv`, `unicodedata`). ``` .venv\Scripts\python -m pytest tests/ -v .venv\Scripts\python -m sort_ym auth .venv\Scripts\python -m sort_ym fetch .venv\Scripts\python -m sort_ym report .venv\Scripts\python -m sort_ym apply --limit 20 --yes ``` Структура кода и поток данных — в [ARCHITECTURE.md](ARCHITECTURE.md).