Files
metadata-agregator/docs/research/meelo/analysis/OVERVIEW.md
T
Alexander a1f6701bac feat: initial implementation of metadata aggregator
- gRPC service with MusicBrainz provider
- PostgreSQL schema with migrations
- Service layer with database-first caching
- Repository pattern for data access
- YAML configuration support
- Research documentation for 17 music metadata projects
2026-04-28 16:28:53 +02:00

375 lines
15 KiB
Markdown

# Meelo Overview
## Project Identity
**Repository**: https://github.com/Arthi-chaud/Meelo
**License**: GPL-3.0
**Stars**: 1,095
**Releases**: 40 (latest: v3.10.1)
**Primary Languages**: TypeScript, Go, Python
**Architecture**: Microservices monorepo
## Purpose
Meelo is a self-hosted music server designed for music collectors who need flexible metadata management. Unlike typical music servers that treat metadata as static, Meelo provides sophisticated versioning and relationship tracking. The system supports music videos as first-class citizens, not afterthoughts, and includes built-in scrobbling to Last.fm and ListenBrainz.
The project targets users with well-organized collections who want control over their metadata without sacrificing modern features like full-text search, mobile access, and streaming.
## Core Services
### Server (NestJS 11, TypeScript)
- **Port**: 4000
- **Role**: Central API and business logic
- **Stack**: NestJS framework, Prisma ORM, PostgreSQL
- **Responsibilities**: Authentication, data persistence, search coordination, streaming, scrobbling, event publishing
### Scanner (Go 1.25, Echo v5)
- **Port**: 8133
- **Role**: Filesystem monitoring and metadata extraction
- **Stack**: Echo HTTP framework, FFmpeg/FFprobe bindings
- **Responsibilities**: File watching, metadata parsing, AcoustID fingerprinting, filename regex parsing, file registration, match triggering
### Matcher (Python 3.14, FastAPI)
- **Port**: 6789
- **Role**: External metadata enrichment
- **Stack**: FastAPI, async HTTP clients
- **Responsibilities**: Consuming match events, querying 8 external providers, pushing enriched metadata to Server
### Front (Next.js 16, React)
- **Port**: 3000
- **Role**: User interface
- **Stack**: Next.js SSR, Material-UI, Jotai state management, TanStack Query
- **Variants**: Web (Next.js) and mobile (Expo/React Native)
## Infrastructure Dependencies
### PostgreSQL
Primary data store. Handles all persistent data through Prisma ORM. Stores users, artists, albums, songs, tracks, releases, files, playlists, external metadata, and relationships.
### MeiliSearch (v1.5)
Full-text search engine. Indexes artists, albums, songs, and videos for fast, typo-tolerant search. Provides instant results as users type.
### RabbitMQ (4.2-alpine)
Message queue for event-driven architecture. Decouples Scanner and Matcher from Server. Enables asynchronous metadata enrichment without blocking file scanning.
### Kyoo Transcoder
Video transcoding service. Handles music video streaming with adaptive bitrate. Converts source files to web-compatible formats on demand.
### Nginx (1.29.7-alpine)
Reverse proxy. Routes requests to appropriate services:
- `/` → Front
- `/api/` → Server
- `/scanner/` → Scanner
- `/matcher/` → Matcher
## Docker Images
All services ship as pre-built Docker images:
- `arthichaud/meelo-server`
- `arthichaud/meelo-front`
- `arthichaud/meelo-scanner`
- `arthichaud/meelo-matcher`
Images are built via GitHub Actions on every release. Development uses hot-reload containers with mounted source directories.
## Key Features
### Flexible Metadata Model
Albums can have multiple releases (original, remaster, deluxe). Songs can have multiple tracks (studio, live, acoustic). Tracks link to source files. This hierarchy mirrors real-world music organization.
### Music Video Support
Videos are not bolted on. They have dedicated types (official, live, lyric video, etc.), link to songs, and stream through the transcoder. The UI treats them as equals to audio tracks.
### Multi-Provider Metadata
Matcher queries 8 sources:
- MusicBrainz (primary database)
- Genius (lyrics, descriptions)
- Wikipedia (artist/album context)
- Wikidata (structured data)
- Discogs (release details)
- AllMusic (editorial reviews)
- Metacritic (critic scores)
- LrcLib (synced lyrics)
Users configure provider priority in settings.json.
### Scrobbling Integration
Built-in support for Last.fm and ListenBrainz. OAuth flow for Last.fm, token-based for ListenBrainz. Scrobbles track plays automatically.
### Geographic Context
Areas (countries, cities, regions) are first-class entities with ISO 3166 codes. Artists link to areas. Areas form parent/child trees (city → state → country).
### Search Performance
MeiliSearch provides sub-100ms search across thousands of tracks. Typo tolerance handles misspellings. Faceted search filters by genre, year, type.
## Development Activity
- **40 releases** show consistent iteration
- **1,095 stars** indicate healthy community interest
- **Active CI/CD** with GitHub Actions per service
- **SonarCloud integration** enforces quality gates
- **Multi-language testing**: Jest (TypeScript), pytest (Python), Go testing
## Configuration Approach
### Environment Variables (.env)
Deployment settings: ports, URLs, directories, credentials for external services (Genius, Discogs, Last.fm).
### Settings File (settings.json)
User preferences: track filename regex, metadata source priority, provider enable/disable, compilation detection rules.
This split keeps deployment config separate from user preferences. Docker Compose handles .env, users edit settings.json through the UI or manually.
## Target Use Case
Meelo fits users who:
- Maintain large, well-organized music collections
- Want metadata control without manual database editing
- Need music video support beyond YouTube links
- Value data accuracy over convenience
- Run home servers or NAS devices
- Prefer self-hosting to cloud services
It does not fit users who:
- Want plug-and-play setup (8+ containers, complex config)
- Have messy folder structures (requires clean metadata or standard naming)
- Need lightweight deployment (heavy infrastructure stack)
- Avoid GPL-3.0 licensing
## Architectural Philosophy
Meelo embraces microservices despite being a self-hosted app. Each service has a single responsibility:
- Scanner watches files
- Matcher enriches metadata
- Server manages state
- Front displays data
This separation enables:
- Independent scaling (run multiple scanners for large libraries)
- Language-specific optimization (Go for I/O, Python for HTTP scraping)
- Isolated failures (matcher crash doesn't stop playback)
- Parallel development (teams can work on different services)
The tradeoff is operational complexity. Users must manage 8 containers, 4 languages, and inter-service communication. For the target audience (technical music collectors), this is acceptable.
## Comparison Context
Among self-hosted music servers:
- **Navidrome**: Simpler (single binary), less metadata flexibility
- **Funkwhale**: Federated, social features, lighter metadata model
- **Airsonic**: Java monolith, basic metadata, stable but dated
- **Jellyfin**: General media server, music is secondary
- **Plex**: Proprietary, cloud-dependent, limited metadata control
Meelo occupies the "sophisticated metadata, self-hosted, open source" niche. It's more complex than Navidrome but more capable. It's more focused than Jellyfin but less mature.
## Technical Highlights
### Monorepo Structure
All services live in one repository with shared tooling (Biome, Docker Compose). This simplifies version coordination and cross-service changes.
### Event-Driven Enrichment
Scanner publishes "file added" events to RabbitMQ. Matcher consumes them asynchronously. Server receives enriched metadata via API. This decoupling prevents blocking and enables retries.
### Type Safety
TypeScript (Server, Front), Go (Scanner), Python with Pyright (Matcher). All services use static typing. Prisma generates TypeScript types from database schema.
### Health Monitoring
Every Docker service has health checks. Compose orchestrates startup order: database first, then message queue, then application services, finally nginx. This prevents race conditions.
### Mobile Parity
Front monorepo includes web (Next.js) and mobile (Expo). Shared components and state management. Mobile app is not an afterthought.
## Deployment Models
### Production (docker-compose.yml)
Pre-built images from Docker Hub. Fast startup. No build tools needed. Suitable for end users.
### Development (docker-compose.dev.yml)
Hot reload for all services. Exposed ports for debugging. Mounted source directories. Suitable for contributors.
### Local Build (docker-compose.local.yml)
Builds images from source. Tests Dockerfile changes. Suitable for CI or custom modifications.
All three share the same infrastructure services (PostgreSQL, MeiliSearch, RabbitMQ). Only application services differ.
## Data Flow Example
1. User adds music files to library folder
2. Scanner detects new files via filesystem watch
3. Scanner extracts metadata (tags, duration, bitrate) using FFmpeg
4. Scanner generates AcoustID fingerprint
5. Scanner registers file with Server API
6. Scanner publishes "file added" event to RabbitMQ
7. Matcher consumes event
8. Matcher queries MusicBrainz using AcoustID
9. Matcher queries Genius for lyrics
10. Matcher queries Wikipedia for artist bio
11. Matcher pushes enriched metadata to Server API
12. Server updates database
13. Server updates MeiliSearch index
14. Front queries Server API
15. User sees new track with complete metadata
This flow demonstrates the event-driven architecture and multi-provider enrichment.
## Quality Assurance
### Testing
- **Server**: Jest unit tests for NestJS modules
- **Matcher**: pytest with async support for provider modules
- **Scanner**: Go testing for file parsing and fingerprinting
- **Coverage**: SonarCloud tracks coverage per service
### Linting
- **TypeScript**: Biome (replaces ESLint + Prettier)
- **Python**: Ruff + Pyright
- **Go**: golangci-lint
### CI/CD
GitHub Actions per service:
1. Lint code
2. Run tests
3. Upload coverage to SonarCloud
4. Build Docker image
5. Push to Docker Hub (on release)
Quality gates block merges if coverage drops or bugs are introduced.
## Configuration Files
### biome.json
Formatting rules: tabs, double quotes, line width 100. Applies to TypeScript (Server, Front).
### settings.json
User-editable preferences:
- `trackRegex`: Filename parsing pattern
- `metadata.source`: Prefer embedded tags or external providers
- `metadata.order`: Provider priority list
- `providers`: Enable/disable specific providers
- `compilations`: Rules for detecting compilation albums
### .env
Deployment secrets:
- `JWT_SIGNATURE`: Auth token signing key
- `GENIUS_ACCESS_TOKEN`: Genius API key
- `DISCOGS_ACCESS_TOKEN`: Discogs API key
- `LASTFM_API_KEY`, `LASTFM_API_SECRET`: Last.fm OAuth
- `PUBLIC_URL`: External URL for OAuth callbacks
- `CONFIG_DIR`, `DATA_DIR`: Volume mount paths
## First-Time Setup
1. Clone repository
2. Copy `.env.example` to `.env`
3. Fill in required credentials (Genius, Discogs, Last.fm)
4. Create `settings.json` with track regex and provider preferences
5. Run `docker-compose up -d`
6. Wait for health checks to pass
7. Navigate to `http://localhost:3000`
8. Register admin user
9. Create library pointing to music folder
10. Trigger initial scan via Scanner API
The system will scan files, extract metadata, query providers, and populate the database. Initial scan time depends on library size and provider response times.
## Maintenance Operations
### Rescan Library
POST to `/scanner/scan/:libraryId` triggers full rescan. Useful after bulk file changes.
### Clean Orphans
POST to `/scanner/clean` removes database entries for deleted files.
### Refresh Metadata
POST to `/scanner/refresh` re-queries providers for existing tracks. Updates descriptions, ratings, lyrics.
### Backup Database
Standard PostgreSQL dump. Volume is `meelo_db` in Docker.
### Update Services
Pull new images, restart containers. Database migrations run automatically via Prisma.
## Extension Points
### Custom Providers
Add new provider modules to Matcher. Implement provider interface (search, fetch metadata). Register in factory. No Server changes needed.
### Additional Scrobblers
Implement scrobbler interface in Server. Add OAuth flow if needed. Store credentials in UserScrobbler table.
### Alternative Frontends
Server API is provider-agnostic. Build custom clients (CLI, desktop app, voice assistant) using REST API.
### Transcoding Profiles
Configure Kyoo transcoder with custom profiles. Adjust bitrates, codecs, resolutions for different devices.
## Performance Characteristics
### Scan Speed
Go scanner processes ~100 files/second on SSD. Bottleneck is FFprobe metadata extraction, not file I/O.
### Search Latency
MeiliSearch returns results in <100ms for libraries up to 100k tracks. Scales linearly beyond that.
### Streaming Startup
Direct file streaming (no transcoding) starts in <500ms. Transcoded streams add 2-5s for initial segment generation.
### Metadata Enrichment
Matcher processes ~10 tracks/second. Limited by external provider rate limits (MusicBrainz: 1 req/sec, Genius: 10 req/sec).
## Resource Requirements
### Minimum
- **CPU**: 2 cores
- **RAM**: 4GB
- **Storage**: 10GB + music library size
- **Network**: 10 Mbps upload for remote streaming
### Recommended
- **CPU**: 4 cores (for transcoding)
- **RAM**: 8GB (MeiliSearch benefits from memory)
- **Storage**: SSD for database and search index
- **Network**: 50 Mbps upload for multiple streams
## Security Considerations
### Authentication
JWT tokens with configurable expiration. Bcrypt password hashing. API keys for internal service communication.
### Anonymous Access
`ALLOW_ANONYMOUS=1` disables auth. Useful for private networks. Not recommended for internet-exposed instances.
### External Providers
Credentials stored in .env. Never logged or exposed via API. Matcher makes requests server-side, not from client.
### File Access
Scanner and Server run as non-root in Docker. File permissions must allow read access. No write operations on music files.
## Community and Support
### Documentation
README covers setup. Wiki has advanced topics (custom providers, troubleshooting). API docs at `/api/docs`.
### Issue Tracker
GitHub Issues for bugs and features. Active maintainer responses. Template for bug reports.
### Contributions
Pull requests welcome. CI checks must pass. SonarCloud quality gates enforced. Biome formatting required.
### Roadmap
GitHub Projects track planned features. Community votes on priorities. Regular releases (every 2-3 weeks).
## Licensing Implications
GPL-3.0 requires:
- Source code disclosure for modifications
- Same license for derivative works
- No proprietary forks
This prevents commercial services from using Meelo without open-sourcing their changes. Acceptable for self-hosters, restrictive for SaaS providers.
## Summary
Meelo is a sophisticated, microservices-based music server for technical users who value metadata accuracy and flexibility. It trades operational simplicity for data model richness and extensibility. The event-driven architecture, multi-provider metadata enrichment, and first-class video support distinguish it from simpler alternatives. The GPL-3.0 license and heavy infrastructure requirements limit its audience to self-hosting enthusiasts with technical skills and well-organized music collections.