Conversation
Major features: - Add local file media provider that scans directories for audio files using MP3 tags for metadata (ID3, Vorbis comments, etc.) - Introduce multi-provider architecture with database schema for tracking providers, tracks, and cross-provider linking - Add GUI setup wizard for configuring providers and settings - Simplify Docker deployment to 2 unified files (CPU/NVIDIA) Database changes: - New tables: provider, track, provider_track, app_settings - Add file_path and track_id columns to score table for linking - All changes are migration-safe with ON CONFLICT handling Key implementation details: - File path hash (SHA-256) used as stable identifier for local files - Providers can be tested before saving configuration - Existing installations auto-migrate with default provider from env - Analysis pipeline updated to store file_path for track linking Files added: - tasks/mediaserver_localfiles.py - Local file provider implementation - app_setup.py - Setup wizard API endpoints - templates/setup.html - Setup wizard UI - deployment/docker-compose-unified.yaml - Simplified CPU deployment - deployment/docker-compose-unified-nvidia.yaml - Simplified GPU deployment - docs/MULTI_PROVIDER_ARCHITECTURE.md - Architecture documentation https://claude.ai/code/session_011AebTWAucDafK4m6uoSSNg
Implements provider fallback logic for API calls: - When provider_id specified: look up in that provider, fall back to score - When provider_id NOT specified (backward compatible): 1. Try primary provider first 2. Try other enabled providers by priority 3. Fall back to direct score table (legacy mode) New helper functions: - get_track_by_item_id(item_id, provider_id=None) - get_tracks_by_item_ids(item_ids, provider_id=None) - get_primary_provider_id() - get_enabled_provider_ids() - resolve_item_id_to_provider(item_id) - get_item_id_for_provider(file_path_or_track_id, provider_id) - is_multi_provider_mode() - set_primary_provider(provider_id) https://claude.ai/code/session_011AebTWAucDafK4m6uoSSNg
- Add docker-compose-worker-cpu.yaml for CPU-only remote workers - Update docker-compose-worker-nvidia.yaml with all provider configs - Update docker-compose-server.yaml for server-only deployment - Add worker connection settings to .env.example (WORKER_REDIS_URL, WORKER_POSTGRES_HOST) - Add deployment mode selection to setup wizard (unified/split) - Add worker configuration section in setup wizard with connection info - Add server-info API endpoint for automatic IP detection This allows running ML analysis workers on separate machines from the main Flask server, useful for utilizing dedicated GPU servers or distributing workload across multiple workers. https://claude.ai/code/session_011AebTWAucDafK4m6uoSSNg
- Add Docker Compose file recommendation to setup summary - Show correct unified file based on hardware selection - Clarify CPU vs NVIDIA image usage in .env.example comments https://claude.ai/code/session_011AebTWAucDafK4m6uoSSNg
- Create settings.html with collapsible sections for: - Media Providers (list, add, edit, delete, set primary) - Deployment (unified/split mode, hardware type, worker info) - Analysis (CLAP, GPU clustering) - AI Integration (playlist naming provider) - Add /settings route in app_setup.py - Update sidebar navigation with Settings link - Keep Setup Wizard as separate option for initial configuration The Settings page provides quick access to modify individual settings without going through the full setup wizard flow. https://claude.ai/code/session_011AebTWAucDafK4m6uoSSNg
- Add provider selector dropdown to all playlist forms - Create shared provider-selector.js component for consistent UI - Add /api/providers/enabled endpoint for fetching available providers - Update create_playlist_from_ids to support provider_ids parameter - Add create_playlist_multi_provider for creating on multiple providers - Add get_all_playlists_multi_provider with deduplication - Update all templates: similarity, path, clap_search, mulan_search, sonic_fingerprint, alchemy, artist_similarity, map, chat - Support 'all' option to create playlist on all enabled providers https://claude.ai/code/session_011AebTWAucDafK4m6uoSSNg
Resolves conflicts in: - app_helper.py: Combined album_artist/year/rating fields with file_path support - tasks/analysis.py: Merged new metadata fields with multi-provider file_path handling https://claude.ai/code/session_011AebTWAucDafK4m6uoSSNg
…0.0.1:38511/git/rendyhd/AudioMuse-AI into claude/multi-provider-local-files-zseAX
- Add track table population functions: - get_or_create_track() - Creates/retrieves track record by file_path - link_provider_track() - Links provider item_id to track - update_score_track_id() - Links score analysis to track - get_track_by_file_path() - Lookup track by file path - find_existing_analysis_by_file_path() - Check for existing analysis - get_all_provider_item_ids_for_track() - Get all provider links for a track - Update save_track_analysis_and_embedding() to: - Accept optional provider_id parameter - Automatically create track record when file_path is provided - Link score to track via track_id - Create provider_track link if provider_id specified - Update analyze_album_task() to pass provider_id for track linking - Add enabled_only parameter to get_providers() function This completes the multi-provider track linking architecture allowing tracks to be identified across providers by their file path. https://claude.ai/code/session_011AebTWAucDafK4m6uoSSNg
The path normalization now handles more provider formats: - Jellyfin: /media/music/... paths - Navidrome: /music/... or relative paths - Lyrion: file:///music/... URLs (with URL decoding) - Various mount points: /mnt/*, /data/*, /share/*, /volume1/* Prefixes are stripped case-insensitively to get the relative path from the music library root, enabling track matching across providers that mount the same music folder at different paths. https://claude.ai/code/session_011AebTWAucDafK4m6uoSSNg
Each provider can now have a 'music_path_prefix' in its config that will be stripped during path normalization. This handles cases where providers have different folder structures: - Jellyfin: /media/music/MyLibrary/Artist/Album/song.mp3 - Navidrome: /music/Artist/Album/song.mp3 By setting music_path_prefix="MyLibrary" on Jellyfin, both normalize to "Artist/Album/song.mp3" enabling cross-provider track matching. https://claude.ai/code/session_011AebTWAucDafK4m6uoSSNg
Users can now configure a 'Music Path Prefix' for each provider to handle different folder structures: - Jellyfin: paths like "MyLibrary/Artist/Album/song.mp3" - Navidrome: paths like "Artist/Album/song.mp3" By setting music_path_prefix="MyLibrary" on Jellyfin, both normalize to "Artist/Album/song.mp3" enabling cross-provider track matching. The field appears in the setup wizard for all provider types. https://claude.ai/code/session_011AebTWAucDafK4m6uoSSNg
- Add get_sample_tracks_from_provider() to fetch tracks with ad-hoc config - Add detect_music_path_prefix() to compare paths between providers - Update provider test endpoint to auto-detect prefix after connection test - Add normalized_path column to track table for path comparison - Update setup UI to display detection results and auto-fill prefix field When adding a second provider, the system now: 1. Fetches sample tracks from the new provider 2. Compares paths with existing normalized tracks 3. Detects the prefix difference (e.g., "Library/" folder) 4. Auto-fills the music_path_prefix field in the setup form https://claude.ai/code/session_011AebTWAucDafK4m6uoSSNg
- Update find_existing_analysis_by_file_path() to accept provider_id - Add copy_analysis_to_new_item() to copy analysis between item_ids - Update analyze_album_task() to check for existing cross-provider analysis before downloading and processing audio files In multi-provider setups, when provider B tries to analyze a track that provider A already analyzed, the system now: 1. Checks for existing analysis via normalized file path hash 2. Copies score, embedding, CLAP, and MuLan data to the new item_id 3. Creates proper track linking for the new provider This prevents redundant GPU-intensive analysis of the same audio file when multiple providers point to the same music library. https://claude.ai/code/session_011AebTWAucDafK4m6uoSSNg
…arison Builds a complete testing framework that connects to two AudioMuse-AI instances (e.g., main vs feature branch) via API, PostgreSQL, Docker, and compares results across all dimensions: - Database comparator: schema validation (17 tables), row counts, data quality (NULL rates, duplicates, mood_vector format), embedding integrity (dimensions, coverage, NaN checks), referential integrity, score distributions, playlist quality, index presence, task health, provider config, and app settings comparison - API comparator: tests 30+ endpoints including config, playlists, search, similarity, map, CLAP, alchemy, path finding, sonic fingerprint, artist similarity, setup/providers, cron, external API, and error handling - comparing status codes, response shapes, keys, and list lengths between instances - Docker comparator: container health/status, restart counts, resource usage (memory/CPU), log error pattern analysis (tracebacks, OOM, timeouts, DB errors), warning detection, and service connectivity tests for Redis and PostgreSQL - Performance comparator: endpoint latency benchmarks (p50/p95/p99/mean) with warmup, concurrent load testing with configurable users, database query performance benchmarks for 8 critical queries - Existing test integration: discovers and runs all 17 unit test files, 2 integration tests, and 8 E2E API tests from the existing test suite, with per-file results and instance-specific E2E execution - HTML report generator: self-contained dark-themed report with status badges, per-category expandable sections, filterable tables, side-by- side instance comparison, and visual performance bar charts - CLI with full argument support, YAML config files, environment variable configuration, test category selection (--only/--skip), and --discover mode listing all 27 available tests https://claude.ai/code/session_0122SF3fSXM3e2dNqaJB5NDn
Covers architecture, prerequisites, quick start, all three config methods (CLI, YAML, env vars), detailed descriptions of all 5 test categories, deployment scenarios (local, remote SSH, API-only), report formats, selective testing, test discovery, result interpretation, and troubleshooting. https://claude.ai/code/session_0122SF3fSXM3e2dNqaJB5NDn
bug fixes and hardware selection on setup
Multi provider testing suite
|
I've been running a ton of tests, manual and automated. Mostly from new setups - will go over with my main setup tomorrow. It's becoming really stable. Attached are automated tests I ran. Curious about your thoughts @NeptuneHub |
added Prompt tests for multiple models
|
Just want to add that I've on the roadmap (Actually in Another things that I'm testing is a lightweight (distilled) version of CLAP model. If this work the plan is to remove Musicnn and use Clap for all. THis have an impact on the database strucutre but very small: practically instead of having embbeding and embbeidng clap table, we will have only embbeding. I'm sharing this because I look you have multiple idea on which you're working and I want to avoid that we create conflict each other. Till now I don't think. |
- Optimized the instant playlist by:
Files Modified
File: ai_mcp_client.py
Changes: New _build_system_prompt() replaces 4 hardcoded prompts; all provider
functions accept library_context; search_database tool schema adds scale,
year_min, year_max, min_rating; energy normalization (0-1 -> raw) in
execute_mcp_tool
────────────────────────────────────────
File: app_chat.py
Changes: Fetches library context at workflow start; iteration 0 simplified to one
line; iteration 2+ gets rich feedback (top artists, diversity ratio,
genres covered, tools used); pre-execution validation rejects empty
song_similarity and filterless search_database; artist diversity
enforcement (max 5/artist with backfill); song ordering for smooth
transitions
────────────────────────────────────────
File: tasks/mcp_server.py
Changes: New get_library_context() with caching; _database_genre_query_sync
enhanced with regex genre matching, relevance-scored ranking,
scale/year/rating filters; _ai_brainstorm_sync rewritten with strict
2-stage matching (exact then normalized fuzzy) requiring BOTH title AND
artist
────────────────────────────────────────
File: config.py
Changes: New: MAX_SONGS_PER_ARTIST_PLAYLIST (default 5), PLAYLIST_ENERGY_ARC
(default False)
New File
File: tasks/playlist_ordering.py
Purpose: Greedy nearest-neighbor ordering using composite distance (35% tempo +
35%
energy + 30% key via Circle of Fifths). Optional energy arc shaping.
Key Improvements
1. Unified prompts - One canonical prompt for all 4 AI providers with correct tool
names and library context
2. Smart iteration feedback - AI sees what was already found (top artists,
diversity metrics) so it can diversify
3. Library awareness - AI knows what genres/years/ratings exist in the user's
collection
4. Better search - Genre regex avoids false positives, relevance ranking replaces
random, year/rating/scale filters unlocked
5. Strict matching - ai_brainstorm no longer matches "All" in title to every song
with "all"
6. Normalized energy - AI uses intuitive 0-1 scale instead of raw 0.01-0.15
7. Smooth ordering - Songs transition smoothly by tempo, energy, and musical key
8. Artist diversity - No artist dominates with >5 songs; overflow backfilled
intelligently
9. Tool validation - Empty/filterless tool calls rejected before execution
…te tests
1. Fix rehash_provider_tracks_task silently doing nothing — was looking
for 'id'/'item_id' keys that get_sample_tracks_from_provider never
returns. Added 'id' key to all provider branches in
get_sample_tracks_from_provider (Jellyfin, Navidrome, Emby, Lyrion,
LocalFiles) and simplified the rehash lookup to use t.get('id').
2. Remove dead import add_item_id_to_results from app.py
3. Remove 3 dead functions from app_helper.py: is_multi_provider_mode,
set_primary_provider, get_path_quality (already removed in prior
cleanup; verified with grep — zero callers remain)
4. Remove 3 dead code blocks from mediaserver.py: PROVIDER_MODULES,
dispatch_to_provider, get_all_playlists_multi_provider
5. Update README.md compose file references to unified variants
6. Remove 2 duplicate test classes from test_app_chat.py:
TestArtistDiversity (duped by TestArtistDiversityEnforcement) and
TestPreExecutionValidation (duped by TestPreValidation).
TestStoppingConditions was already removed in prior cleanup.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
# Conflicts: # app_helper.py # tasks/analysis.py # tasks/mediaserver_navidrome.py
Settings API: - Auto-detect hardware_type from nvidia-smi and gpu_clustering from config when not in app_settings DB - Inject auto-detected values into category structure so frontend flattening works correctly - Fix duplicate check query: score.item_id → score.track_id after canonical migration - Move duplicate check into Analysis section (not its own section) Compose files: - Add USE_GPU_CLUSTERING env var to flask service in all nvidia compose files (was only on worker) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Hash matching: - _compute_file_path_hash now strips provider's music_path_prefix before hashing, so Jellyfin (music i/artist/song) and Navidrome (artist/song) produce the same hash - get_or_create_track uses the same prefix-aware normalization - Auto-rehash all tracks when music_path_prefix changes on a provider - Drop UNIQUE(provider_id, artist_name) constraint from artist_provider_mapping — same artist can have multiple provider IDs DB resilience: - Add pg_advisory_lock in init_db to prevent startup deadlock between flask and worker containers - Add reset_db_connection() to recover from poisoned transactions - link_provider_track and get_or_create_track: try/except with connection reset on failure - get_db() checks connection transaction status for auto-recovery Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Artist mappings: - Fix is_primary column queries in _get_default_provider_id and _get_default_secondary_provider_id — column doesn't exist, was poisoning DB connection on every call - upsert_artist_provider_mapping now returns True/False - upsert_artist_mapping_secondary propagates actual result - Secondary sync passes actual provider_id instead of guessing via _get_default_secondary_provider_id Analysis: - Fall back to first enabled provider when primary_provider_id not set, preventing single-provider from being treated as secondary - Batch secondary sync: chunked hash lookups (500/query) instead of per-track queries - Check link_provider_track return value for accurate link count - Fix missing get_or_create_track import in run_analysis_task Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
upsert_artist_mapping now delegates to upsert_artist_provider_mapping, which uses a 4-value tuple (name, provider_id, artist_id, is_primary). The test was checking values[1] (now provider_id) instead of values[2]. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix critical data destruction in cleaning.py where orphan detection compared provider UUIDs against integer track_ids, causing all tracks to be flagged as orphaned. Now joins provider_track to compare in the same ID space. - Fix clustering and AI playlist creation passing raw track_id integers to provider APIs expecting native string IDs. The backward-compat path in create_playlist_from_ids now routes through create_playlist_multi_provider which handles ID remapping. - Fix localfiles _get_songs_from_db fallback SQL referencing dropped score.item_id column (now uses track_id). - Fix create_provider POST upsert overwriting credentials with literal '********' by adding the same masking guard as the PUT handler. - Fix rehash merge path missing mulan_embedding update when MULAN_ENABLED is false, causing FK constraint violations. Uses SAVEPOINT pattern to handle table potentially not existing. - Fix inconsistent MPD removal: config.py now falls back to localfiles with a warning, and dispatcher functions log explicit errors instead of silently returning empty. - Fix advisory lock leak: add explicit pg_advisory_unlock after init_db commits, remove dead code add_item_id_to_results, fix artist mapping using wrong provider_id for secondary providers, centralize config reads in server-info endpoint. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…RVER_TYPE Sonic fingerprint and play history functions (get_top_played_songs, get_last_played_time) now resolve the primary provider from the multi-provider setup before falling back to the legacy env var. Added server_config support to all provider play history functions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Wrap init_db advisory lock in try/finally to prevent deadlock on exception - Use CURRENT_NORM_VERSION constant instead of hardcoded 1 in get_or_create_track - Add UniqueViolation retry in link_provider_track for concurrent race condition - Simplify delete_orphaned_albums_sync to use CASCADE from track table - Replace dropped artist_mapping reference with artist_provider_mapping - Fix string item_ids passed to integer track_id columns in _text_search_sync and _song_alchemy_sync - Replace LIKE with regex in _vibe_match_sync to prevent genre substring false positives - Route delete_automatic_playlists through primary provider resolver - Add Jellyfin/Emby fallback in resolve_emby_jellyfin_user for mixed-provider setups - Skip analysis early when file_path is None to avoid wasted compute - Add static file and param-existence guards in before_request handler - Fix test mock target for create_playlist_multi_provider (tasks.mediaserver not tasks.voyager_manager) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The multi-provider refactor requires tracks to have a file_path (via 'Path' key) to create track records. Without it, analyze_album_task skips the track entirely, so ONNX sessions are never loaded or cleaned up. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ic fingerprint UX - Migration now sets primary_provider_id after creating the first provider - get_primary_provider_id() falls back to first enabled provider and persists - Deployment/hardware cards in settings are now read-only indicators - Removed deployment_type/hardware_type from settings API allowlist - Sonic fingerprint: credentials default to provider config, override is collapsible; LocalFiles shows warning banner with disabled generate button - Added Emby support to sonic fingerprint credential handling Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ion read-only - init_db() now seeds AI settings (provider, URLs, models, keys) from env vars into app_settings on first boot using ON CONFLICT DO NOTHING, so .env values are reflected in the settings UI without manual setup - Analysis page AI Playlist Naming section is now read-only with disabled dropdown and readonly inputs, linking to Settings for configuration - When no AI provider is configured, shows a warning that playlists will use generic names instead of AI-generated ones (clustering still works) - Removed hardcoded fallback defaults from script.js renderConfig() Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- get_all_songs() now uses 3-phase delta scan: quick os.walk for paths, DB cache lookup, metadata extraction only for new/modified files - Compares file mtime against provider_track.last_synced to detect re-tagged files without expensive full mutagen reads - Fix LOCALFILES_FORMATS empty string env var falling through to broken default (empty string is now treated as unset) - Add external nas-music volume support to nvidia-local compose file - Remove redundant localfiles cache layer from app_setup.py (now handled by get_all_songs() itself) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…et, update docs - Fix sonic_fingerprint_manager to resolve provider-specific item IDs (Jellyfin hex, Navidrome strings) to canonical DB track_ids via resolve_track_id() before passing to get_tracks_by_ids(). Maintains reverse mapping for get_last_played_time() media server calls. - Add provider selection dropdown to clustering page so users can choose which provider(s) to create clustering playlists on (primary, all, or specific). Passes provider_ids through app_clustering.py to the RQ worker task and into create_playlist_from_ids(). - Rewrite ALGORITHM.md Section 8 (Instant Playlist) from stale SQL-generation docs to accurate MCP agentic tool-calling architecture with 6 tools. - Add ALGORITHM.md sections 12-17: MuLan, Artist Similarity, External API, Waveform, Collection Sync, Multi-Provider Architecture. - Update ALGORITHM.md Section 3 with file_path/album_artist response fields, mood_similarity param, multi-provider playlist creation, ID resolution. - Update ARCHITECTURE.md with LocalFiles provider and multi-provider DB tables. - Update PARAMETERS.md with multi-provider configuration section. - Consolidate CLAUDE.md: remove parent migration guide, update project CLAUDE.md to v0.9.3 with multi-provider tables and pending migrations. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…alysis page Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Set User-Agent header to 'AudioMuse-AI' on all Navidrome HTTP requests (mediaserver_navidrome.py and mediaserver.py test/sample endpoints). Previously defaulted to 'python-requests'. - Fix client name 'c' param in get_sample_tracks_from_provider from lowercase 'audiomuse' to 'AudioMuse-AI' to match the rest of the codebase. - Fix prefix detection returning 'low' confidence when paths match exactly (empty prefix). The empty string was not counted in prefix_candidates because of a truthy guard (`if prefix:`). Removed the guard so exact matches are properly counted. Now returns 'high' with 50 matches. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix LocalFiles delta scan returning 0 cached songs after restart. The DB cache returned score.file_path (Jellyfin's /data/Music I/...) but filesystem paths are /music/... — they never matched. Now indexes cache by track.normalized_path and normalizes filesystem paths the same way for lookup. Also overrides Path/FilePath on cached songs with the actual filesystem path so cross-provider hash linking works. - Fix LocalFiles re-linking reporting 0% match rate. Cached songs had Jellyfin paths in their Path field, producing wrong hashes during the linking phase. The path override ensures correct hashes. - Add Navidrome rating backfill during secondary provider linking. When Navidrome provides a userRating and score.rating is NULL, the rating is written to the score table. Jellyfin does not support ratings, so Navidrome is the primary rating source. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…only - Fix /api/config returning empty AI settings (ollama_server_url, model names). Used import-time constants instead of config module attributes which are updated at runtime by apply_settings_to_config(). Now reads config.OLLAMA_SERVER_URL etc. at call time. - Fix LocalFiles m3u playlist using wrong paths. create_playlist() used _get_songs_from_db() which returns score.file_path (primary provider path like /data/Music I/...) instead of actual LocalFiles filesystem paths (/music/...). Now uses get_all_songs() which returns correct case-preserving filesystem paths via the delta scan. - Make chat page AI configuration read-only, matching analysis page style. Shows provider, model, and server URL as disabled/readonly fields with "Configured in Settings" note and warning when no provider is set. - Fix dark mode link contrast on sonic_fingerprint.html Settings links. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add autouse fixture that mocks app_helper.resolve_track_id to avoid Flask app context / DB calls in unit tests. The fixture returns int(id) for numeric IDs, matching the real function's behavior for test data. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…etup path warning color - config.py: Treat MEDIASERVER_TYPE="" as explicit "no provider" instead of falling through to auto-detect localfiles. Only unset env var triggers auto-detection. Prevents phantom LocalFiles provider in clean test instances. - setup.html: Change Navidrome relative path warning from red (error) to orange (warning) during test connection — connection succeeded, it's just an advisory about enabling "Report Real Path". Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ath detection, harden setup wizard - mediaserver.py: Add _resolve_provider_type() that reads primary provider from DB, falling back to env var. All dispatcher functions (get_recent_albums, get_tracks_from_album, download_track, get_all_songs, get_playlist_by_name, create_playlist, create_instant_playlist) now use DB-first resolution. - mediaserver.py: Fix Lyrion sample track path detection — decode file:// URIs via _decode_lyrion_url before path format classification. - app_setup.py: Suppress noisy "Unknown provider type from env:" warning when MEDIASERVER_TYPE is explicitly empty. - setup.html: Add error checking to completeSetup() — verify selectedProviders is non-empty and check response status on provider save requests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
All four server-based providers (Jellyfin, Navidrome, Lyrion, Emby) now accept server_config in get_recent_albums, get_tracks_from_album, and download_track. Credentials are resolved from the DB provider config with fallback to env vars, matching the existing pattern used by get_top_played_songs and create_instant_playlist. The dispatcher in mediaserver.py resolves provider config from _resolve_play_history_provider() and passes it through. LocalFiles is unchanged (reads from filesystem, no credentials needed). Emby sub-functions (_get_recent_albums_only, _get_recent_standalone_tracks, get_recent_music_items) are also threaded through. Lyrion internal helpers (_count_albums, _get_all_albums_simple, _album_has_tracks_in_target_path) receive base_url for the full call chain. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
get_tracks_from_album used _get_songs_from_db() as primary source, only falling back to get_all_songs() when DB was completely empty. Once any album was analyzed, the DB returned a partial list, the filesystem fallback was skipped, and remaining albums returned 0 tracks. Now tries DB cache first (fast path for rescans), then falls back to get_all_songs() filesystem scan only when the specific album isn't found in cache. This preserves performance for NAS/SMB rescans while ensuring unanalyzed albums are always discoverable. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- app_setup.py: Only show relative path warnings in multi-provider setups. Single-provider Navidrome users never need path matching, so no warning is shown regardless of "Report Real Path" setting. - settings.html: Rescan Paths now shows "Rescan complete" to make it clear the operation finished (it's instant, not async). - settings.html: Rehash Tracks now polls for progress inline on the settings page instead of telling users to check the analysis page where the task was invisible. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ings UX - app.py: Move apply_settings_to_config() out of the Flask-only block so workers also read DB settings at startup. Previously workers only used env var defaults, ignoring settings changed via the UI. - clustering_helper.py: Read USE_GPU_CLUSTERING from config module at call time instead of import time, so toggling the setting in the UI takes effect without restarting workers. - settings.html: Fix rescan result blinking (save/restore HTML across provider list re-render). Show Rehash Tracks button after successful rescan. Fix rehash progress polling to use /api/status/<task_id> instead of /api/active_tasks which drops completed tasks. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Patch config.USE_GPU_CLUSTERING instead of tasks.clustering_helper.USE_GPU_CLUSTERING. The module reads it via _config_module.USE_GPU_CLUSTERING (import config as _config_module), not as a module-level attribute. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix setup wizard redirect on restored backups where MEDIASERVER_TYPE env var is empty but the migration already created a provider with linked tracks. is_setup_completed() now checks for enabled providers with provider_track entries as a fallback when env-var detection fails. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@NeptuneHub I've finished all my testing. It took a lot longer than I expected, I've been working a lot on this over the last 2 months. I've been running this version now for 1-2 weeks, while fine tuning and final bug fixes.
However, this change is massive, I fully recognize that. I've updated my opening post with the details. Please note! Before any testing make a backup of your production data, or test on a copy. Launching this branch will trigger an automatic migration to the new data architecture. |
…vars Clustering AI naming (Ollama, OpenAI, Gemini, Mistral) was reading import-time constants which are empty when configured via the Settings page. Now reads config module attributes at call time, which are updated by apply_settings_to_config() from the DB. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
Note! Before testing please backup your production data. This will fully migrate the database on launch.
This is a foundational architecture change that adds multi-provider support to AudioMuse-AI, allowing users to connect multiple media servers simultaneously (e.g., Jellyfin + Navidrome + local files). It ships four tightly coupled features that were developed and tested together to avoid duplicate integration testing:
track_idsystem with cross-provider deduplication/setup) — guided web UI for adding/configuring providers, replacing manual.envediting for most settings/settings) — runtime configuration management for analysis, clustering, AI, and deployment settingsWhy one PR?
These features are deeply interdependent. The Setup Wizard is the primary interface for configuring multi-provider, LocalFiles is a new provider type exercising the multi-provider plumbing, and Settings removes the need for
.envfor most configuration. Testing any one of these in isolation would have meant re-testing the same integration paths twice. This has been running in production for ~2 weeks with Jellyfin, Navidrome, and LocalFiles simultaneously.Stats
What's New
Multi-Provider Architecture
track(canonical identity),provider_track(links provider-specificitem_id→track_id),provider(JSONB config registry)file_path_hash(SHA-256) — same file from Jellyfin and Navidrome shares one analysisresolve_track_id()middleware inapp.py— all APIs accept either legacyitem_idor newtrack_idmigration_track_id.py, ~1,186 lines) — runs at startup, converts existing single-provider data to canonical schemaitem_idremapping for playlist creation (remap_item_ids_for_provider)LocalFiles Provider (
tasks/mediaserver_localfiles.py)Setup Wizard (
/setup,app_setup.py)music_path_prefix(on/off, with visual warnings). If Real Path is disabled and multiple providers are added it blocks analysis to avoid duplication.Settings Page (
/settings,templates/settings.html).envneeded for most options)app_settingstableDeployment
deployment/docker-compose-worker-cpu.yamlfor split worker deployments.env.examplewith comprehensive documentation and new defaultsOther Changes
item_idparams continue to workstatic/provider-selector.js)Breaking Changes
Running this branch triggers an automatic migration that restructures the database schema. Please back up your PostgreSQL data volume before upgrading.
Backup:
Restore (if needed):
New API Endpoints
/api/setup/status/api/setup/providers/types/api/setup/providers/api/setup/providers/api/setup/providers/<id>/api/setup/providers/<id>/api/setup/providers/<id>/test/api/setup/providers/test/api/setup/providers/<id>/rehash-tracks/api/setup/providers/<id>/rescan-paths/api/setup/providers/health/api/library/duplicates/api/setup/providers/libraries/api/setup/providers/<id>/sync/api/setup/settings/api/setup/settings/api/setup/complete/api/setup/multi-provider/api/setup/primary-provider/api/setup/server-info/api/setup/browse-directories/api/providers/enabled/api/track_by_path/api/tracks_by_pathsTested:
New Test Suites