a1f6701bac
- 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
378 lines
17 KiB
Markdown
378 lines
17 KiB
Markdown
# Melodee: Project Overview
|
|
|
|
## Executive Summary
|
|
|
|
Melodee is a self-hosted music server and metadata aggregator built on .NET 10 and Blazor Server. The project positions itself as a modern alternative to traditional music servers, emphasizing metadata quality, multi-protocol API support, and extensibility. With 62 GitHub stars and active development, Melodee represents a niche but technically sophisticated approach to personal music library management.
|
|
|
|
The system's core value proposition centers on intelligent metadata aggregation from six different providers, a multi-stage processing pipeline that transforms raw audio files into organized library entries, and compatibility with existing music client ecosystems through three distinct API protocols.
|
|
|
|
## Project Identity
|
|
|
|
**Repository**: https://github.com/melodee-project/melodee
|
|
**Version**: 1.8.0
|
|
**License**: MIT
|
|
**Primary Language**: C# (.NET 10)
|
|
**UI Framework**: Blazor Server with Radzen components
|
|
**Database**: PostgreSQL 17 (primary), SQLite (MusicBrainz cache)
|
|
**Stars**: 62
|
|
**Status**: Active development
|
|
|
|
The MIT license makes Melodee suitable for both personal and commercial use without significant legal constraints. The choice of .NET 10 indicates commitment to modern framework features and performance characteristics, though it also creates a dependency on Microsoft's release cycle.
|
|
|
|
## Core Capabilities
|
|
|
|
### Multi-Protocol API Support
|
|
|
|
Melodee implements three distinct API protocols, each serving different client ecosystems:
|
|
|
|
1. **Native REST API** (`/api/v1/`): JWT-based authentication, modern RESTful design, full feature access
|
|
2. **OpenSubsonic** (`/rest/`): Token and salt authentication, compatibility with Subsonic clients (DSub, Ultrasonic, Sublime Music)
|
|
3. **Jellyfin API** (`/api/jf/`): Custom token authentication, compatibility with Jellyfin clients
|
|
|
|
This multi-protocol approach maximizes client compatibility without forcing users into a single ecosystem. The rate limiting differs per protocol: Native API allows 30 requests per 30 seconds, authentication endpoints limit to 10 per 60 seconds, and Jellyfin endpoints permit 200 per 60 seconds.
|
|
|
|
### Metadata Aggregation Pipeline
|
|
|
|
The system processes music files through four distinct stages:
|
|
|
|
1. **Inbound**: Raw file ingestion and validation
|
|
2. **Staging**: Metadata extraction and provider queries
|
|
3. **Storage**: File organization and normalization
|
|
4. **Database**: Entity persistence and indexing
|
|
|
|
Six metadata providers contribute to the aggregation process:
|
|
|
|
- **MusicBrainz**: Primary source with local SQLite cache, monthly updates
|
|
- **Last.fm**: Social metadata, play counts, similar artists
|
|
- **Spotify**: Album art, popularity metrics (client credentials flow)
|
|
- **iTunes**: Commercial metadata, preview URLs
|
|
- **Deezer**: European market metadata
|
|
- **Brave Search**: Fallback web search for obscure releases
|
|
|
|
The MusicBrainz cache strategy deserves attention. Rather than querying the remote API for every lookup, Melodee maintains a local SQLite database updated monthly. This reduces latency and respects MusicBrainz rate limits while ensuring metadata freshness.
|
|
|
|
### Background Job Architecture
|
|
|
|
Melodee uses Quartz.NET to orchestrate 17 background jobs with dependency chaining. Jobs handle:
|
|
|
|
- Metadata provider synchronization
|
|
- Library scanning and updates
|
|
- Scrobble submission (Last.fm and internal)
|
|
- Database maintenance and optimization
|
|
- Cache invalidation
|
|
- Statistics calculation
|
|
- Podcast feed updates
|
|
|
|
Job chaining allows complex workflows. For example, a library scan job triggers metadata enrichment jobs, which then trigger cache invalidation, which finally triggers statistics recalculation. This declarative approach keeps the system responsive while handling computationally expensive operations asynchronously.
|
|
|
|
## Technical Foundation
|
|
|
|
### .NET 10 and Blazor Server
|
|
|
|
The choice of Blazor Server over Blazor WebAssembly or traditional SPA frameworks has specific implications:
|
|
|
|
**Advantages**:
|
|
- Full .NET runtime access without WASM limitations
|
|
- Smaller initial payload (no framework download)
|
|
- Direct database access without API layer overhead
|
|
- Real-time updates via SignalR (used for Party Mode)
|
|
|
|
**Tradeoffs**:
|
|
- Server-side rendering requires persistent connection
|
|
- Higher server resource usage per user
|
|
- Network latency affects UI responsiveness
|
|
- Scaling requires sticky sessions or Redis backplane
|
|
|
|
For a self-hosted music server with typically 1-10 concurrent users, these tradeoffs favor Blazor Server. The SignalR connection enables Party Mode, where multiple users see synchronized playback state.
|
|
|
|
### Database Architecture
|
|
|
|
PostgreSQL 17 serves as the primary data store with over 100 migrations and 40+ entities. The migration count suggests iterative development and schema evolution. Entity Framework Core 10 provides the ORM layer.
|
|
|
|
SQLite handles the MusicBrainz cache separately. This dual-database approach isolates read-heavy cache queries from transactional music library operations. The cache can be rebuilt without affecting user data.
|
|
|
|
Key entity categories:
|
|
- **Library entities**: Albums, Artists, Tracks, Genres
|
|
- **User entities**: Users, Playlists, Favorites, Scrobbles
|
|
- **Metadata entities**: Provider mappings, external IDs, cached responses
|
|
- **System entities**: Jobs, Logs, Settings, Health checks
|
|
|
|
The 100+ migrations indicate active schema development. This can complicate upgrades if migrations aren't carefully managed, but the Docker entrypoint.sh script handles automatic migration application on container startup.
|
|
|
|
### Audio Processing
|
|
|
|
FFmpeg handles transcoding for format conversion and bitrate adjustment. ImageSharp processes album art (resizing, format conversion, optimization). Audio tagging uses two libraries:
|
|
|
|
- **ATL (Audio Tools Library)**: Primary tagging engine, supports 20+ formats
|
|
- **IdSharp**: Fallback for ID3v2 edge cases
|
|
|
|
This dual-library approach suggests the developers encountered limitations in a single tagging library and opted for redundancy rather than forking or extensive patching.
|
|
|
|
## User-Facing Features
|
|
|
|
### Party Mode
|
|
|
|
SignalR-powered synchronized playback across multiple clients. One user controls playback, others see real-time updates. This feature differentiates Melodee from traditional music servers that treat each session independently.
|
|
|
|
Implementation likely uses SignalR groups to broadcast playback state changes. The Blazor Server architecture makes this natural since the SignalR connection already exists for UI updates.
|
|
|
|
### Podcast Support
|
|
|
|
Melodee handles podcast feeds alongside music libraries. This positions it as a unified media server rather than music-only. Podcast-specific features likely include:
|
|
|
|
- RSS feed parsing and updates
|
|
- Episode download management
|
|
- Playback position tracking
|
|
- Subscription management
|
|
|
|
The background job system handles periodic feed checks and episode downloads.
|
|
|
|
### MQL Query Language
|
|
|
|
Melodee implements a custom query language (MQL) for advanced library searches. This suggests power users can construct complex queries beyond simple text search. Examples might include:
|
|
|
|
- `artist:Radiohead AND year:>2000`
|
|
- `genre:Jazz OR genre:Blues`
|
|
- `playcount:>10 AND rating:>=4`
|
|
|
|
The implementation likely uses a parser (possibly ANTLR or hand-written recursive descent) to convert MQL strings into LINQ expressions or SQL queries.
|
|
|
|
### Charts and Analytics
|
|
|
|
The system generates charts based on listening history:
|
|
|
|
- Most played tracks/albums/artists
|
|
- Listening trends over time
|
|
- Genre distribution
|
|
- Discovery metrics (new vs. familiar content)
|
|
|
|
These features require the scrobbling system to capture play events and the background jobs to aggregate statistics.
|
|
|
|
### User Requests
|
|
|
|
Users can request missing albums or corrections. This creates a feedback loop where library gaps become visible to administrators. The feature likely stores requests as database entities with status tracking (pending, fulfilled, rejected).
|
|
|
|
## Internationalization
|
|
|
|
Support for 10 languages indicates a global user base or internationalization-first design. Blazor's localization system uses resource files (.resx) for string management. The 10 languages suggest community contributions for translations.
|
|
|
|
Language support affects:
|
|
- UI strings
|
|
- Error messages
|
|
- Email templates
|
|
- API documentation
|
|
|
|
The Scalar API documentation tool likely generates localized API docs automatically.
|
|
|
|
## Authentication and Security
|
|
|
|
### Google OAuth Integration
|
|
|
|
OAuth support allows users to authenticate with Google accounts rather than managing separate credentials. This reduces friction for new users and delegates security concerns to Google's infrastructure.
|
|
|
|
Implementation uses standard OAuth 2.0 authorization code flow:
|
|
1. User clicks "Sign in with Google"
|
|
2. Redirect to Google consent screen
|
|
3. Google redirects back with authorization code
|
|
4. Melodee exchanges code for access token
|
|
5. Melodee retrieves user profile
|
|
6. Melodee creates or updates local user account
|
|
|
|
### JWT for Native API
|
|
|
|
The native REST API uses JWT tokens for stateless authentication. Clients receive a token after login and include it in the `Authorization: Bearer <token>` header for subsequent requests.
|
|
|
|
JWT advantages:
|
|
- Stateless (no server-side session storage)
|
|
- Self-contained (claims embedded in token)
|
|
- Scalable (no session affinity required)
|
|
|
|
JWT tradeoffs:
|
|
- Token revocation requires additional infrastructure (blacklist or short expiry)
|
|
- Token size larger than session IDs
|
|
- Clock skew can cause validation issues
|
|
|
|
### Rate Limiting
|
|
|
|
Per-protocol rate limits prevent abuse:
|
|
- **API endpoints**: 30 requests per 30 seconds
|
|
- **Authentication**: 10 requests per 60 seconds
|
|
- **Jellyfin endpoints**: 200 requests per 60 seconds
|
|
|
|
The higher Jellyfin limit suggests those clients make more frequent requests, possibly for real-time playback state updates.
|
|
|
|
Rate limiting implementation likely uses in-memory sliding window counters keyed by IP address or user ID. For distributed deployments, this would require Redis or similar shared state.
|
|
|
|
## Observability
|
|
|
|
### Logging with Serilog
|
|
|
|
Serilog provides structured logging with two sinks:
|
|
- **Console**: Human-readable output for development and container logs
|
|
- **File (CLEF)**: Compact Log Event Format for machine parsing
|
|
|
|
CLEF (Compact Log Event Format) is JSON-based, making logs easily ingestible by log aggregation tools (Seq, Elasticsearch, Splunk). This suggests the developers anticipate production deployments where centralized logging matters.
|
|
|
|
### Health Checks
|
|
|
|
The `/health` endpoint exposes system status for monitoring tools. Health checks likely verify:
|
|
- Database connectivity
|
|
- Metadata provider availability
|
|
- Background job status
|
|
- Disk space
|
|
- Cache validity
|
|
|
|
Kubernetes and Docker Swarm can use this endpoint for liveness and readiness probes.
|
|
|
|
### Admin UI
|
|
|
|
Blazor-based admin interface provides visibility into:
|
|
- Job execution history and status
|
|
- User management
|
|
- Library statistics
|
|
- System settings
|
|
- Log viewing
|
|
|
|
This eliminates the need for database access or log file inspection for routine administration.
|
|
|
|
## Platform Compatibility
|
|
|
|
### Raspberry Pi Support
|
|
|
|
Explicit Raspberry Pi compatibility indicates ARM architecture support and resource-conscious design. Running on Raspberry Pi 4 (4GB RAM) requires:
|
|
- Efficient memory usage
|
|
- ARM64 .NET runtime
|
|
- Minimal CPU overhead for background jobs
|
|
- Optimized database queries
|
|
|
|
This positions Melodee as suitable for home server deployments on low-power hardware.
|
|
|
|
### Podman Support
|
|
|
|
Podman compatibility alongside Docker shows awareness of rootless container runtimes. Podman's daemonless architecture and rootless mode appeal to security-conscious users.
|
|
|
|
The Docker Compose file likely works with Podman Compose with minimal or no modifications. Volume mounts and networking must avoid Docker-specific assumptions.
|
|
|
|
## Development Practices
|
|
|
|
### Testing Strategy
|
|
|
|
Three testing frameworks indicate comprehensive test coverage:
|
|
|
|
1. **xUnit**: Unit and integration tests for business logic
|
|
2. **bUnit**: Blazor component testing
|
|
3. **NBomber**: Load and performance testing
|
|
|
|
The inclusion of NBomber suggests performance is a first-class concern. Load tests likely verify:
|
|
- API throughput under concurrent requests
|
|
- Database query performance with large libraries
|
|
- Memory usage during metadata aggregation
|
|
- Background job execution time
|
|
|
|
### Code Quality
|
|
|
|
Biome linting enforces code style and catches common errors. Biome is a fast, Rust-based linter and formatter that supports JavaScript, TypeScript, JSON, and CSS. Its presence suggests frontend code (likely for admin UI customization or build scripts) follows consistent style rules.
|
|
|
|
The combination of .NET analyzers (built into SDK) and Biome creates a multi-layered quality gate.
|
|
|
|
## Competitive Positioning
|
|
|
|
Melodee competes with established music servers:
|
|
|
|
- **Subsonic/Airsonic**: Older Java-based servers with large client ecosystems
|
|
- **Navidrome**: Go-based, lightweight, OpenSubsonic-compatible
|
|
- **Jellyfin**: Full media server (music, video, TV) with broad client support
|
|
- **Plex**: Commercial media server with free tier
|
|
- **Emby**: Commercial media server, Jellyfin's predecessor
|
|
|
|
Melodee's differentiators:
|
|
- **Metadata quality**: Six providers vs. typical 1-2
|
|
- **Multi-protocol**: Native + OpenSubsonic + Jellyfin vs. single protocol
|
|
- **Modern stack**: .NET 10 + Blazor vs. older frameworks
|
|
- **Party Mode**: Synchronized playback vs. independent sessions
|
|
- **MQL**: Advanced queries vs. basic search
|
|
|
|
The 62 stars suggest Melodee hasn't achieved mainstream adoption. This could reflect:
|
|
- Newer project (less time to accumulate stars)
|
|
- Niche appeal (power users who value metadata quality)
|
|
- Competition from established alternatives
|
|
- .NET ecosystem smaller than Go/Rust for self-hosted tools
|
|
|
|
## Use Cases
|
|
|
|
### Personal Music Library
|
|
|
|
Primary use case: individual managing a local music collection with high metadata standards. The six-provider aggregation ensures accurate artist names, release dates, genres, and album art even for obscure releases.
|
|
|
|
### Family Media Server
|
|
|
|
Multiple user accounts, playlists, and Party Mode support family sharing. Google OAuth simplifies account creation for non-technical family members.
|
|
|
|
### Podcast Aggregator
|
|
|
|
Podcast support makes Melodee a unified audio server. Users avoid separate podcast apps and music apps.
|
|
|
|
### Music Discovery Platform
|
|
|
|
Charts, analytics, and Last.fm integration enable discovery workflows. Users see listening patterns and explore similar artists.
|
|
|
|
### Development Platform
|
|
|
|
MIT license and modern .NET stack make Melodee suitable as a foundation for custom music server projects. Developers can fork and extend without licensing concerns.
|
|
|
|
## Limitations and Considerations
|
|
|
|
### Blazor Server Scalability
|
|
|
|
Persistent SignalR connections limit horizontal scaling. Each user consumes server memory and CPU for UI rendering. Scaling beyond 50-100 concurrent users requires careful architecture (Redis backplane, sticky sessions, or migration to Blazor WebAssembly).
|
|
|
|
### Metadata Provider Dependencies
|
|
|
|
Six providers create six points of failure. If MusicBrainz, Last.fm, or Spotify change APIs or rate limits, metadata quality degrades. The local MusicBrainz cache mitigates this for the primary provider.
|
|
|
|
### Migration Complexity
|
|
|
|
100+ migrations complicate upgrades, especially if users skip versions. The Docker entrypoint handles automatic migration, but rollback scenarios require careful planning.
|
|
|
|
### .NET Ecosystem
|
|
|
|
.NET 10 requires users comfortable with .NET runtime installation or Docker. This narrows the audience compared to Go or Rust single-binary distributions.
|
|
|
|
### Client Compatibility
|
|
|
|
While OpenSubsonic and Jellyfin APIs provide broad client support, the native API requires custom clients or API consumers. The project's 62 stars suggest limited native client development.
|
|
|
|
## Future Potential
|
|
|
|
### Federated Libraries
|
|
|
|
Multiple Melodee instances could federate, allowing users to share libraries across households while maintaining local control.
|
|
|
|
### Machine Learning
|
|
|
|
Listening history and metadata enable recommendation engines, auto-playlist generation, and mood-based categorization.
|
|
|
|
### Blockchain Integration
|
|
|
|
NFT-based music ownership or decentralized metadata storage could differentiate Melodee in web3 contexts.
|
|
|
|
### Mobile Apps
|
|
|
|
Native iOS and Android apps using the REST API would reduce dependence on third-party clients.
|
|
|
|
### Video Support
|
|
|
|
Expanding beyond audio to music videos or concerts would position Melodee as a full media server competitor to Jellyfin and Plex.
|
|
|
|
## Conclusion
|
|
|
|
Melodee represents a technically sophisticated music server built on modern .NET foundations. The multi-protocol API support, six-provider metadata aggregation, and Blazor Server UI create a compelling package for users who prioritize metadata quality and extensibility.
|
|
|
|
The project's 62 stars indicate niche appeal rather than mainstream adoption. This likely reflects the competitive landscape (established alternatives like Navidrome and Jellyfin) and the .NET ecosystem's smaller footprint in self-hosted software compared to Go or Rust.
|
|
|
|
For developers evaluating music server options, Melodee offers:
|
|
- **Strengths**: Metadata quality, modern stack, multi-protocol support, MIT license
|
|
- **Tradeoffs**: Blazor Server scalability, .NET runtime dependency, smaller community
|
|
|
|
The project's active development (version 1.8.0, 100+ migrations) suggests ongoing improvement. Whether Melodee achieves broader adoption depends on community growth, client ecosystem development, and continued differentiation from established competitors.
|