Skip to content

mideco-tech/ym2zvuk

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ym2zvuk

Кроссплатформенный npm/npx CLI для переноса треков, лайков и плейлистов из Яндекс Музыки в Звук / SberZvuk без какого-либо LLM в рантайме.

Логика работы детерминированная:

  1. export выгружает библиотеку Яндекс Музыки через прямые запросы к api.music.yandex.net.
  2. match ищет соответствия в Звуке и классифицирует треки как exact, fuzzy, ambiguous, missing или override.
  3. import воспроизводит заранее захваченные write-mutation запросы Звука, поддерживает checkpoint/resume и не создаёт дубли при повторных запусках.
  4. verify проверяет итоговое состояние в Звуке, включая fallback-проверку канонизированных треков по названию и артистам.

Node-клиент Яндекс Музыки в проекте реализован по мотивам и с опорой на референсную Python-библиотеку MarshalX/yandex-music-api для того среза API, который нужен мигратору.

Установка

npm install

Где хранится состояние

По умолчанию CLI хранит состояние в системной конфигурационной директории:

  • Windows: %APPDATA%/ym2zvuk
  • macOS: ~/Library/Application Support/ym2zvuk
  • Linux: ${XDG_CONFIG_HOME:-~/.config}/ym2zvuk

Основные файлы внутри этой директории:

  • config.json
  • overrides.csv
  • zvuk-write-templates.json
  • zvuk-probe-capture.json
  • runs/<timestamp>/...

Для локальной разработки или изолированных запусков используйте --state-dir <dir>.

Первый запуск

npx ym2zvuk init

Что делает init:

  • сохраняет токены Яндекса и Звука в config.json
  • создаёт overrides.csv, если его ещё нет
  • при необходимости устанавливает Playwright Chromium
  • запускает интерактивный probe Звука, если не передан --skip-probe

Важно: --zvuk-token имеет смысл и действительно нужен. Probe через браузер нужен для захвата шаблонов write-запросов Звука, но текущая реализация не извлекает и не сохраняет X-Auth-Token автоматически из браузерной сессии. Для команд match, import, verify и migrate проект использует отдельную API-сессию Звука, которой нужен этот токен.

Можно инициализировать проект без браузерного шага, если шаблоны уже есть:

npx ym2zvuk init \
  --yandex-token <token> \
  --zvuk-token <token> \
  --skip-probe \
  --templates path/to/zvuk_write_templates.json

Флаг --zvuk-token необязательно указывать именно в командной строке, но сам токен нужен. Если не передавать его флагом, init запросит его интерактивно и сохранит в config.json.

Где взять токены

Звук

После авторизации в браузере токен Звука обычно можно увидеть в данных, связанных с запросом:

  • https://zvuk.com/api/tiny/profile

На практике проект использует этот же endpoint для priming anti-bot cookie, но сам токен из браузера автоматически не вытаскивает, поэтому его нужно либо передать в init, либо сохранить вручную в config.json.

Яндекс Музыка

С токеном Яндекс Музыки сложнее. Актуальные пользовательские способы и обсуждение собраны здесь:

Если кратко, в обсуждении описаны варианты через браузерный OAuth-flow и DevTools/Network. Так как способы со временем меняются, лучше ориентироваться именно на эту живую ветку обсуждения, а не на зафиксированную инструкцию внутри проекта.

Доверие и безопасность

Самая чувствительная часть проекта это первый probe Звука, потому что он открывает настоящий браузер и просит пользователя войти вручную. Это нормально вызывает вопросы, поэтому важно явно описать поведение.

Что происходит на самом деле:

  • CLI запускает локальный Chromium через Playwright
  • пользователь сам входит на реальный сайт https://zvuk.com
  • скрипт ждёт подтверждения Enter после ручных действий
  • во время probe записываются только API-запросы Звука, которые нужны для вывода шаблонов трёх операций:
    • лайк трека
    • создание плейлиста
    • добавление трека в плейлист

Чего проект не делает:

  • не спрашивает пароль в терминале
  • не печатает логин и пароль за пользователя
  • не читает поля формы логина
  • не реализует keylogger
  • не отправляет захваченные данные куда-либо сам по себе
  • не использует никакие удалённые AI/LLM-сервисы в рантайме

Где это можно проверить в коде:

  • bootstrap и probe-flow: src/init.js
  • логика захвата запросов: src/probe.js
  • сессия и replay запросов к Звуку: src/zvuk/session.js
  • прямой HTTP-клиент Яндекса: src/yandex/client.js

Что сохраняется локально:

  • config.json с токенами
  • профиль браузера Playwright в state-директории
  • zvuk-probe-capture.json с захваченными request/response примерами
  • zvuk-write-templates.json с шаблонами мутаций

Проект не обещает невозможного и не пытается «криптографически доказать», что он безопасен. Честная гарантия тут уже: код открыт, чувствительная логика небольшая и обозримая, а все данные лежат локально в state-директории, которую можно посмотреть и удалить через ym2zvuk reset.

Как проверить это самому

Если вы осторожно относитесь к таким инструментам, лучший сценарий проверки такой:

  1. Прочитать src/probe.js и убедиться, что модуль только слушает ответы zvuk.com/api/ и ждёт ручных подтверждений Enter.
  2. Запустить проект с отдельной --state-dir и посмотреть все созданные там файлы.
  3. При желании параллельно наблюдать сетевую активность своими средствами.
  4. Для последующих запусков использовать --skip-probe --templates <file>, чтобы не повторять браузерный шаг.
  5. В любой момент удалить локальное состояние через ym2zvuk reset.

Корректная формулировка для такого проекта не «доверьтесь на слово», а «чувствительная часть маленькая, локальная, открытая и проверяемая».

Команды

npx ym2zvuk export
npx ym2zvuk match --limit 25 --report-format console
npx ym2zvuk import
npx ym2zvuk verify
npx ym2zvuk migrate

Поддерживаемые команды:

  • init
  • export
  • probe
  • match
  • import
  • verify
  • migrate
  • reset
  • version

Алиасы для совместимости:

  • probe-zvuk -> probe
  • dry-run-match -> match

Overrides

Ручные решения хранятся в overrides.csv:

source_id,zvuk_track_id,action,comment
54874190:6320030,131057283,force_match,Подтверждено вручную
104375865:41191790,,skip,Надёжного совпадения в Звуке нет

Поддерживаемые действия:

  • force_match
  • skip

Повторные запуски должны быть воспроизводимы через этот файл.

Артефакты прогонов

Каждый запуск пишет отдельную директорию внутри runs/:

  • export.json
  • export-summary.json
  • match-report.json
  • unmatched.csv
  • import-checkpoint.json
  • migration-report.json
  • migration-report.md
  • verification-report.json
  • run-manifest.json

Примечания

  • Все запросы к сервисам идут с принудительным обходом прокси.
  • Запись в Звук делается через replay реально захваченных браузерных мутаций, а не через угадывание private API.
  • import поддерживает resume и пишет checkpoint после каждого лайка и каждого элемента плейлиста.
  • verify сначала сверяет лайки по целевым id треков, а затем использует fallback по title + artist, если Звук канонизировал трек под другим внутренним id.
  • Если Звук временно возвращает HTML или maintenance-страницу вместо GraphQL JSON, слой сессии делает повторные попытки.
  • В репозитории уже есть готовый workflow CodeQL в .github/workflows/codeql.yml.

Тесты

npm test

Ключевые слова для поиска

  • миграция Яндекс Музыка в Звук
  • перенос треков из Яндекс Музыки в Звук
  • перенос плейлистов из Яндекс Музыки в Звук
  • перенос лайков из Яндекс Музыки в Звук
  • yandex music to zvuk
  • yandex music migration
  • zvuk playlist migration

About

CLI для миграции треков, лайков и плейлистов из Яндекс Музыки в Звук / SberZvuk.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors