Трек, который играет у тебя в Spotify, автоматически становится музыкой профиля в Telegram. Доиграл — снимается, начался следующий — встаёт на его место. Плеер молчит — в профиле пусто.
Работает от личного аккаунта через MTProto (mtcute), а не через Bot API: музыку профиля боту поставить нельзя, это возможность обычного пользователя.
Три шага в цикле.
1. Что играет. Раз в несколько секунд спрашиваем Spotify Web API. Он отдаёт название, исполнителей, длительность и позицию — но не сам файл: полного аудио в Web API нет вовсе, а 30-секундный preview_url с конца 2024 года закрыт для новых приложений.
2. Где взять файл. Ищем внутри Telegram, в двух местах по порядку:
| # | Источник | Что делает |
|---|---|---|
| 1 | свои чаты | messages.searchGlobal по всем диалогам: если трек уже где-то лежит, берём ссылку на готовый файл |
| 2 | инлайн-боты | спрашиваем ботов из MUSIC_INLINE_BOTS, результат уходит в промежуточный чат, оттуда забираем документ |
Скачивания нет нигде и намеренно: программа работает фоном и часто, а тянуть файл со стороны по десять секунд ради строчки в профиле не стоит. Не нашлось быстро — трек пропускается, в профиле остаётся предыдущий.
Первый источник со временем становится и кэшем: раз полученное от бота оседает в промежуточном чате, а он попадает в область поиска — второй раз тот же трек находится сразу.
3. Поставить в профиль. Музыка профиля — это не сообщения и не закреплённое в «Избранном», а отдельный список документов: account.saveMusic добавляет трек, он же с флагом unsave убирает. Поэтому программа никому ничего не пишет и ничего не удаляет — только правит этот список, и только тот трек, который поставила сама. Добавленное тобой руками остаётся на месте.
Нужен Node.js 22 или новее.
git clone https://github.com/bot4pi/spotify-telegram-sync.git
cd spotify-telegram-sync
npm install
cp .env.example .envОткрой my.telegram.org → API development tools, создай приложение. Положи api_id и api_hash в .env:
TG_API_ID=1234567
TG_API_HASH=0123456789abcdef0123456789abcdef
npm run loginСпросит телефон, код из Telegram и пароль двухфакторной защиты, если он у тебя стоит. Создаст файл сессии в data/.
Файл сессии — это полный доступ к аккаунту без пароля. Он остаётся на твоей машине, никуда не отправляется и лежит в
.gitignore. Никому его не передавай — ни в поддержку, ни «для настройки».
Открой developer.spotify.com/dashboard, создай приложение. В его настройках добавь Redirect URI ровно такой:
http://127.0.0.1:8888/callback
Именно петлевой IP — localhost Spotify не принимает.
Client ID и Client Secret положи в .env, затем:
npm run spotify:loginСкрипт напечатает ссылку — открой её, разреши доступ. Обратно вернётся SPOTIFY_REFRESH_TOKEN, впиши его в .env. Запрашивается одно право, user-read-currently-playing: читать, что играет. Управлять плеером программа не может.
npm startВключи что-нибудь в Spotify — трек появится в профиле.
Все — в .env, все необязательные, кроме ключей.
| Переменная | По умолчанию | Что делает |
|---|---|---|
MUSIC_INLINE_BOTS |
Shazambot |
инлайн-боты, у которых спрашиваем трек, через запятую и по порядку. Пусто — путь выключен, останется только поиск по своим чатам |
MUSIC_CACHE_CHAT |
«Избранное» | куда складывать полученное от бота. Отдельный приватный чат чище: не мешает заметкам и работает кэшем |
POLL_MS |
3000 |
раз во сколько миллисекунд спрашивать Spotify |
TG_SESSION_PATH |
./data/session.sqlite |
где лежит сессия |
LOG_LEVEL |
info |
debug покажет, какие треки не нашлись и почему |
Про POLL_MS. Это же время реакции на перемотку и ручное переключение: расчёт конца трека умеет только сокращать сон, но не удлинять, поэтому потолок задаёт именно эта величина. У Spotify лимит около 180 запросов в минуту, так что 3000 мс — это примерно двадцать в минуту, девятая часть бюджета. Меньше секунды смысла не имеет: сам запрос идёт 200–800 мс, и проверки начнут накладываться друг на друга.
Про инлайн-ботов. Годится не всякий: нужен именно инлайн-режим — тот, что показывает выпадающий список, когда набираешь @бот запрос в поле ввода, — и полные треки в выдаче, а не превью. Проверяется за пять секунд руками: если списка не появилось, инлайна у бота нет. Выдача фильтруется по длительности, битрейту и приметам вроде live, remix, snippet, так что обрезок вместо трека не проедет.
Пример юнита systemd:
[Unit]
Description=spotify-telegram-sync
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=sync
WorkingDirectory=/srv/spotify-telegram-sync
Environment=NODE_ENV=production
Environment=HOME=/srv/spotify-telegram-sync
ExecStart=/srv/spotify-telegram-sync/node_modules/.bin/tsx src/index.ts
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.targetnpm run login выполняется до запуска службы: он интерактивный. Файл сессии перенеси на сервер сам — повторный вход сбросил бы текущий.
- Не управляет плеером. Запрошено одно право на чтение.
- Не скачивает музыку. Только ссылки на файлы, уже лежащие в Telegram.
- Не трогает чужое. Ни сообщений, ни закреплённого, ни треков, добавленных в профиль вручную.
- Не работает с подкастами и локальными файлами. Их не найти в Telegram, профиль просто останется с предыдущим треком.
MIT.