Current version: v3.1.1 β Alembic Migration Tooling
Telegram Music Finder Bot is a Python Telegram bot for searching music, showing track information, saving favorites, viewing search history, opening lyrics pages, and providing admin maintenance tools.
The project is built as a backend-style portfolio project with modular architecture, PostgreSQL persistence via asyncpg, external API integrations, localization, logging, automated tests, coverage reports, Ruff checks, GitHub Actions, Docker support, release cleanup checks, admin diagnostics, database maintenance tools, and versioned releases.
- Replaced the hand-built schema-migration mechanism with Alembic (industry-standard tooling). Alembic now owns the database schema; the app runtime stays on asyncpg.
- Schema is applied via
alembic upgrade headat container start. init_db_pool()now only creates the connection pool β schema setup moved to Alembic.- Fixed a facade-rule violation in
aggregator.py. - No user-facing feature changes.
- Migrated the database from SQLite to PostgreSQL (asyncpg). All database access is now fully asynchronous via a connection pool.
asyncio.to_threadwrappers removed β all DB calls are natively async.deploy/docker-compose.ymlnow includes a PostgreSQL service with healthcheck and named volume.scripts/migrate_sqlite_to_postgres.pyprovided for one-time data migration from existing SQLite files.DATABASE_URLis now required at startup.- No user-facing feature changes.
- Full migration from pyTelegramBotAPI to aiogram 3.29.0. All handlers, callbacks, and bot lifecycle code are now async.
- Removed legacy dependencies:
pyTelegramBotAPI,deezer-python,lyricsgenius,requests. - Deezer search and lyrics fetching now use
httpxdirectly (no third-party SDKs). - All sync DB and I/O calls use
asyncio.to_threadfor non-blocking execution. - Dispatcher now wires
handlers_routerandcallbacks_routerat startup and drops pending updates before polling. - Database schema, localization, and all user-facing features unchanged.
- Internal technical-debt refactor β no new user-facing features.
/similarnow displays results grouped asπ€ Artist / π΅ Others, matching the inline π― Similar button./trendingformatting is now shared with the recommendations service (output unchanged).- Removed dead code, unused facade exports, and duplicated handler boilerplate.
- All database repository functions now close their connection safely even on errors.
- Localized favorites error alerts, which were previously shown in English regardless of the user's language.
- Localized the
/versioncommand output. - Added error handling to the language selection callback.
- Track card errors are now logged to the admin error log instead of only the application log file.
- Improved test coverage for favorites and history callbacks.
- Search tracks by title, artist, or free-text query.
- Uses Deezer as the main music data source.
- Shows paginated search results.
- Keeps temporary search context for pagination and track selection.
- Automatically cleans expired in-memory search contexts.
Each selected track can show:
- Track title.
- Artist name.
- Album title.
- Duration.
- Release date when available.
- Popularity/rank label when available.
- Deezer track link.
- Cover image when available.
- Spotify link when available.
- Genius lyrics link when available.
After the track card, the bot automatically sends a "You may also like" block with related tracks by the same artist from the local database. If the database has no data for the artist, the bot fetches the artist's top tracks from Deezer as a fallback.
The track card also includes a π― Similar inline button for quick access to tracks similar to the selected one using the Deezer radio endpoint.
/similarβ shows tracks similar to the last viewed track using the Deezer radio endpoint./trendingβ shows the top tracks of the week from the Deezer chart. Results are cached in-memory for 1 hour to reduce API load.- The last viewed track ID is saved in the database so
/similarworks across bot restarts.
- Deezer is the primary search source.
- Spotify enrichment is optional and controlled by environment variables.
- Spotify failures do not break the main Deezer-based result flow.
- Spotify 403 responses trigger a temporary cooldown to avoid repeated failed lookups.
- Genius lyrics lookup is optional and disabled safely when
GENIUS_TOKENis not configured.
- Add tracks to favorites.
- Remove tracks from favorites.
- View saved favorites.
- Clear favorites with confirmation.
- Favorite state is stored in PostgreSQL.
- Save user search queries.
- View recent search history.
- Re-run searches from history.
- Clear search history with confirmation.
- Search history is stored in PostgreSQL and can be trimmed by maintenance tools.
- Main menu and bot actions support multiple languages.
- Supported language set includes English, Ukrainian, Norwegian, German, French, Spanish, Italian, and Polish.
- English is the baseline language.
- Missing translation keys fall back to English.
- Locale coverage can be checked with a helper script.
Admin users can get an extra admin button in the main menu.
Admin access can be configured through:
ADMIN_IDin.env.- local
config/admins.jsonbased onconfig/admins.example.json.
The local config/admins.json file is ignored by Git and should not be committed.
Admin menu actions include:
- Statistics report.
- Maintenance report.
- Health report.
- Cleanup saved errors.
- Cleanup search history.
- Reload admin configuration cache.
Slash commands are also kept as fallback admin access:
/errors Show recent saved errors
/clear_errors Clear saved errors
/health Show runtime health checks
/stats Show users/searches/favorites/tracks/errors statistics
/maintenance Show database size, schema version and maintenance status
/cleanup_errors Keep newest saved errors and remove older rows
/cleanup_history Keep newest search history rows per user and remove older rows
Admin diagnostics include:
- Bot version.
- Database status.
- Database path.
- Database size.
- Table counts.
- Schema version.
- Spotify availability/cooldown status.
- Genius configuration status.
- Recent saved errors.
The project uses PostgreSQL for persistence, accessed via asyncpg with a connection pool.
Stored data includes:
- Users.
- Tracks.
- Favorites.
- Search history.
- Spotify cached links.
- Error history.
- Schema migration version.
Database features:
- Async connection pool (asyncpg).
- Schema initialization on first startup.
- Index creation.
- Repository modules split by domain.
- Compatibility repository facade for stable imports.
- Database maintenance helpers.
- One-time SQLiteβPostgreSQL migration script.
- Runtime errors can be saved into the database.
- Error logging is designed not to crash the bot if the database is unavailable.
- Admins can inspect and clear saved errors.
The project includes automated quality checks:
- Pytest test suite.
- Coverage reporting through
pytest-cov. - Minimum coverage gate.
- Ruff linting.
- GitHub Actions workflow.
- Release cleanup validation script.
- Locale coverage checker.
Useful commands:
python -m ruff check .
python -m pytest --cov=app --cov-report=term-missing
python scripts/check_release_clean.py
python scripts/check_locale_coverage.pyDocker files are stored in deploy/.
Build image:
docker build -f deploy/Dockerfile -t find-music-bot:test .Run with Docker Compose:
docker compose -f deploy/docker-compose.yml up --buildRun in background:
docker compose -f deploy/docker-compose.yml up --build -dStop:
docker compose -f deploy/docker-compose.yml downDocker Compose mounts:
data/β read-only access to the historical SQLite backup file, used only by the one-timescripts/migrate_sqlite_to_postgres.pymigration script. The live database is PostgreSQL, managed by its own named volume (postgres-data), not this mount.logs/to persist logs.config/as read-only config for admin IDs.
- Python
- aiogram
- httpx (Deezer search, Genius lyrics)
- Spotify Web API
- PostgreSQL (asyncpg)
- Alembic
- pytest
- pytest-cov
- pytest-asyncio
- testcontainers
- Ruff
- GitHub Actions
- Docker
- Docker Compose
app/
βββ bot/ # Telegram handlers, callbacks, keyboards and user flows
βββ config/ # Environment settings and admin access config
βββ database/ # PostgreSQL repositories and maintenance helpers (schema owned by Alembic β see migrations/)
βββ localization/ # Translations, languages and fallback translator
βββ platforms/ # Platform integrations, Spotify modules and aggregator
βββ services/ # Deezer, lyrics, formatting and platform service facades
βββ utils/ # Logging, text and time helpers
βββ admin_tools.py # Admin statistics, maintenance and cleanup reports
βββ health.py # Admin health diagnostics
βββ main.py # Bot startup
βββ version.py # Project version
config/
βββ admins.example.json # Public admin config template
deploy/
βββ Dockerfile # Container image definition
βββ docker-compose.yml # Local Docker Compose startup
docs/ # Architecture, deployment, roadmap and release workflow docs
migrations/ # Alembic schema migrations (versions/, env.py) β schema source of truth
requirements/
βββ base.txt # Production dependencies
βββ dev.txt # Development and test dependencies
scripts/ # Release, cleanup and quality helper scripts
tests/ # Automated tests
.github/workflows/ # GitHub Actions CI
git clone https://github.com/Ingwalde/Find-Music-Bot.git
cd Find-Music-Botpython -m venv venvWindows:
venv\Scripts\activateLinux/macOS:
source venv/bin/activateProduction dependencies:
python -m pip install -r requirements/base.txtDevelopment dependencies:
python -m pip install -r requirements/dev.txtCopy .env.example to .env and fill in your tokens.
Windows:
copy .env.example .envLinux/macOS:
cp .env.example .envRequired:
BOT_TOKEN=your_telegram_bot_token_hereOptional:
GENIUS_TOKEN=your_genius_token_here
SPOTIFY_ENABLED=true
SPOTIFY_CLIENT_ID=your_spotify_client_id_here
SPOTIFY_CLIENT_SECRET=your_spotify_client_secret_here
SPOTIFY_MARKET=NO
ADMIN_ID=your_telegram_user_id
DATABASE_PATH=data/music_bot.db
LOG_FILE_PATH=logs/bot.log
LOG_LEVEL=INFOCopy the example file:
copy config\admins.example.json config\admins.jsonLinux/macOS:
cp config/admins.example.json config/admins.jsonExample:
{
"admin_ids": [123456789]
}config/admins.json is local-only and should not be committed.
python run.pyExpected log:
Bot started successfully.
Build image:
docker build -f deploy/Dockerfile -t find-music-bot:test .Start with Compose:
docker compose -f deploy/docker-compose.yml up --buildStart in background:
docker compose -f deploy/docker-compose.yml up --build -dView logs:
docker compose -f deploy/docker-compose.yml logs -fStop:
docker compose -f deploy/docker-compose.yml downRun before committing:
python -m ruff check .
python -m pytest --cov=app --cov-report=term-missing
python scripts/check_release_clean.py
python scripts/check_locale_coverage.py
python -c "from app.version import __version__; print(__version__)"Docker check:
docker build -f deploy/Dockerfile -t find-music-bot:test .Do not commit or upload local/private files:
.env
config/admins.json
.git/
data/
logs/
.pytest_cache/
.ruff_cache/
.vscode/
__pycache__/
coverage.xml
.coverage
*.pyc
*.zip
Use this check before release:
python scripts/check_release_clean.pyAvoid sharing raw docker compose config output because it can expose secrets from .env.
Planned next stages:
v2.6.1 - Localization & Error Logging Fixes Update
v3.0.0 - aiogram Migration
This project is intended as a portfolio backend/bot project. It focuses on practical Telegram bot functionality, API integration, local persistence, maintainability, testing, Docker deployment and production-style cleanup practices.