Sort_YM/README.ru.md
Andrew Pimenov 544765db3f split docs into EN/RU, add MIT license
README/ARCHITECTURE now bilingual (EN default, .ru.md cross-linked) per public-repo convention; added MIT license and Credits/License sections; tightened .gitignore against stray AI-tool files.
2026-08-09 11:59:39 +03:00

140 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[English](README.md)
# 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.ru.md](ARCHITECTURE.ru.md).
## Credits
Andrew Pimenov
## License
[MIT License](LICENSE)