34d05b7a49
Smart Collections (musicfs-search/src/collections.rs): - CollectionStore with thread-safe Mutex<Connection> - CollectionQuery enum: Match, DateRange, RecentlyAdded/Played, MostPlayed, Genre, Compound - Builtin collections for Recently Added, 80s/90s Music Artwork Extraction & Caching: - ArtworkExtractor using symphonia Visual (musicfs-metadata) - ArtworkCache with CAS storage + on-demand resize (musicfs-cache) - ArtType: Front/Back/Other, ArtSize: Thumbnail/Medium/Full Predictive Prefetching: - PatternStore tracks access patterns with sequence prediction - PrefetchEngine listens to FileAccessed events, prefetches predictions - PrefetchOps exposes /.prefetch/ virtual directory with status/hints Oracle review fixes applied: - CollectionStore uses Mutex for thread safety - FileAccessed event now includes file_id for canonical correlation - JSON parse warnings in collection deserialization 130 tests pass (15 new tests added)
8.6 KiB
8.6 KiB
Smart Features API Documentation
Overview
MusicFS Week 9 introduces three intelligent features:
- Smart Collections - Dynamic playlists based on queries, time ranges, and listening patterns
- Artwork Extraction & Caching - Extract and serve album art in multiple sizes
- Predictive Prefetching - Learn listening patterns to preload likely-next tracks
Smart Collections
CollectionStore
Manages persistent smart collections using SQLite.
pub struct CollectionStore {
db: rusqlite::Connection,
}
pub struct Collection {
pub id: i64,
pub name: String,
pub query: CollectionQuery,
pub created_at: SystemTime,
pub updated_at: SystemTime,
}
CollectionQuery Types
| Query Type | Description | Example |
|---|---|---|
Match(String) |
tantivy search query | "artist:Metallica" |
DateRange { start, end } |
Files added within range | Last 30 days |
RecentlyAdded(days) |
Files added in last N days | RecentlyAdded(7) |
RecentlyPlayed(days) |
Files played in last N days | RecentlyPlayed(30) |
MostPlayed(limit) |
Top N most played tracks | MostPlayed(100) |
Genre(String) |
All tracks matching genre | "Progressive Rock" |
Compound(Vec) |
AND combination of queries | Multiple conditions |
API
impl CollectionStore {
fn create(&self, name: &str, query: CollectionQuery) -> Result<i64, CollectionError>;
fn get(&self, id: i64) -> Result<Option<Collection>, CollectionError>;
fn list(&self) -> Result<Vec<Collection>, CollectionError>;
fn update(&self, id: i64, name: &str, query: CollectionQuery) -> Result<(), CollectionError>;
fn delete(&self, id: i64) -> Result<(), CollectionError>;
fn evaluate(&self, id: i64, index: &SearchIndex, patterns: &PatternStore) -> Result<Vec<FileId>, CollectionError>;
}
FUSE Integration (Planned)
Collections will appear as virtual directories under /.collections/:
$ ls /mnt/musicfs/.collections/
Recent Additions/
Most Played/
80s Metal/
$ ls /mnt/musicfs/.collections/Most\ Played/
001. Track1.flac -> /mnt/musicfs/Artist/Album/Track1.flac
002. Track2.flac -> /mnt/musicfs/Artist/Album/Track2.flac
Artwork Extraction & Caching
ArtworkExtractor
Extracts embedded artwork from audio files.
pub struct Artwork {
pub data: Vec<u8>,
pub mime_type: String,
pub art_type: ArtType,
pub width: u32,
pub height: u32,
}
pub enum ArtType {
Front,
Back,
Other,
}
pub enum ArtSize {
Thumbnail, // 150x150 max
Medium, // 300x300 max
Full, // Original size
}
API
impl ArtworkExtractor {
fn extract(&self, path: &Path) -> Result<Vec<Artwork>, ArtworkError>;
fn extract_first(&self, path: &Path) -> Result<Option<Artwork>, ArtworkError>;
fn resize(data: &[u8], size: ArtSize) -> Result<Vec<u8>, ArtworkError>;
}
ArtworkCache
Caches artwork in CAS (Content-Addressable Storage).
impl ArtworkCache {
async fn store(&self, file_id: i64, artwork: &Artwork) -> Result<ChunkHash, ArtworkError>;
async fn get(&self, file_id: i64, art_type: &str, size: ArtSize) -> Result<Option<Vec<u8>>, ArtworkError>;
async fn has(&self, file_id: i64, art_type: &str) -> Result<bool, ArtworkError>;
}
Size Specifications
| Size | Max Dimension | Use Case |
|---|---|---|
| Thumbnail | 150px | List views, grids |
| Medium | 300px | Detail panels |
| Full | Original | High-res display |
Caching Strategy
- Original artwork stored in CAS with content hash
- SQLite maps
(file_id, art_type)→chunk_hash - Resizing performed on-demand, not cached (saves storage)
- Max input size: 10MB (reject larger images)
Predictive Prefetching
Access Patterns (PatternStore)
Tracks file access history to predict next tracks.
pub struct AccessPattern {
pub file_id: FileId,
pub timestamp: SystemTime,
pub context: AccessContext,
pub hour_of_day: u8,
}
pub struct AccessContext {
pub album_id: Option<i64>,
pub track_number: Option<u32>,
pub artist: Option<String>,
}
Pattern Learning
| Pattern Type | Description | Use Case |
|---|---|---|
| Sequential | A → B → C transitions | Album playback |
| Time-based | Hour-of-day preferences | Morning playlist |
| Frequency | Most played tracks | Popular content |
API
impl PatternStore {
fn record(&self, file_id: FileId, context: AccessContext) -> Result<(), PatternError>;
fn predict_next(&self, current: FileId, limit: usize) -> Vec<FileId>;
fn predict_for_time(&self, hour: u8, limit: usize) -> Vec<FileId>;
fn recently_played(&self, days: u32) -> Result<Vec<FileId>, PatternError>;
fn most_played(&self, limit: u32) -> Result<Vec<FileId>, PatternError>;
}
PrefetchEngine
Background engine that listens for file access events and prefetches predicted content.
pub struct PrefetchConfig {
pub lookahead: usize, // How many tracks to prefetch (default: 3)
pub max_concurrent: usize, // Concurrent prefetch limit (default: 2)
pub cooldown: Duration, // Delay between prefetch bursts (default: 100ms)
pub enabled: bool, // Master switch
}
Architecture
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ EventBus │────▶│ PrefetchEngine │────▶│ ContentFetcher │
│ (FileAccessed) │ │ (predictions) │ │ (CAS storage) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│
▼
┌─────────────────┐
│ PatternStore │
│ (SQLite DB) │
└─────────────────┘
FUSE Interface
Virtual directory /.prefetch/ exposes prefetch status and hints:
$ cat /mnt/musicfs/.prefetch/status
MusicFS Prefetch Status
=======================
running: true
in_flight: 2
most_played: [42, 57, 103, 89, 12]
$ ls /mnt/musicfs/.prefetch/
status
hint_0042
hint_0057
hint_0103
$ cat /mnt/musicfs/.prefetch/hint_0042
57
103
89
Performance Targets
| Feature | Metric | Target |
|---|---|---|
| Collection evaluation | Latency | <100ms for 100k files |
| Artwork extraction | Throughput | >10 files/sec |
| Artwork resize | Latency | <50ms per image |
| Pattern prediction | Latency | <10ms |
| Prefetch hit rate | Accuracy | >70% for sequential play |
Error Handling
CollectionError
| Error | Description |
|---|---|
Database(rusqlite::Error) |
SQLite operation failed |
NotFound |
Collection ID doesn't exist |
InvalidQuery |
Query failed to serialize |
Search(SearchError) |
tantivy query failed |
Pattern(PatternError) |
Pattern lookup failed |
ArtworkError
| Error | Description |
|---|---|
Database(rusqlite::Error) |
Cache DB operation failed |
Cas(CasError) |
CAS storage operation failed |
InvalidHash |
Stored hash is malformed |
NotFound |
Artwork not in cache |
ImageTooLarge(usize) |
Input exceeds 10MB limit |
InvalidImage |
Cannot decode image data |
ResizeFailed |
Image resize operation failed |
PatternError
| Error | Description |
|---|---|
Database(rusqlite::Error) |
SQLite operation failed |
Configuration
Default Settings
[prefetch]
enabled = true
lookahead = 3
max_concurrent = 2
cooldown_ms = 100
[artwork]
max_input_size_mb = 10
thumbnail_size = 150
medium_size = 300
[patterns]
max_history_days = 30
Tests
| Test | Type | Validates |
|---|---|---|
test_collection_crud |
Unit | Create, read, update, delete |
test_collection_evaluate_match |
Unit | Match query evaluation |
test_collection_persistence |
Unit | Collections survive restart |
test_artwork_extract_flac |
Unit | FLAC artwork extraction |
test_artwork_cache_store_get |
Unit | Cache round-trip |
test_artwork_resize |
Unit | Resize produces valid output |
test_pattern_prediction |
Unit | Sequential pattern learning |
test_pattern_persistence |
Unit | Patterns survive restart |
test_prefetch_config_defaults |
Unit | Default config values |
test_prefetch_ops_* |
Unit | FUSE PrefetchOps integration |