mod commands; mod config; mod cover_logo; mod diagnostics; mod hero_crop; mod import; mod hero_detector; mod loudness; mod lyric_align; mod lyric_prep; mod lyrics; mod pipeline; mod playback; mod playlist_formats; mod playlists; mod provider_playlist; mod preview; mod setlist_scan; mod shazam; mod smtc; mod state; mod thumbbar; mod vocal_sep; mod youtube_playlist; mod youtube_setlist; mod ytdlp; #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { tauri::Builder::default() .manage(state::AppState::default()) .setup(|app| { app.handle().plugin( tauri_plugin_log::Builder::default() .level(log::LevelFilter::Info) .clear_targets() .target(tauri_plugin_log::Target::new( tauri_plugin_log::TargetKind::Stdout, )) .build(), )?; app.handle().plugin(tauri_plugin_dialog::init())?; // Must run before anything touches the app-data dir. config::migrate_app_data(app.handle()); // Prepare the small local vision model while the user is still on // the app shell, so a first artist visit pays only warm inference. hero_detector::warm_up(app.handle().clone()); // Before playback::init: the event pump it spawns starts pushing // transport state at the card immediately, and the card has to be // registered by then or the first track's status is dropped. smtc::init(app.handle()); // Only subclasses the window here; the buttons themselves go up // when the shell says the taskbar button exists. thumbbar::init(app.handle()); playback::init(app.handle()); playback::prune_cache(app.handle()); preview::init(app.handle()); loudness::init(app.handle()); diagnostics::init(app.handle()); if let Err(e) = pipeline::init(app.handle()) { log::error!("library init failed: {e}"); } Ok(()) }) .invoke_handler(tauri::generate_handler![ commands::app_status, commands::excluded_search_phrases, commands::get_credentials, commands::connect_and_login, commands::connect_stored, commands::disconnect, commands::start_search, commands::stop_search, commands::download_file, commands::copy_stream_to_folder, commands::save_to_library, commands::stream_cache_len, commands::cancel_download, commands::show_in_folder, commands::refresh_artist_art, commands::play_stream, commands::play_local, commands::preload_local, commands::player_control, commands::player_state, commands::waveform, commands::library_albums, commands::library_album_stats, commands::album_tracks, commands::album_art, commands::library_art_prewarm, commands::stream_embedded_art, commands::refresh_album_art, commands::refresh_all_album_art, commands::get_settings, commands::set_settings, commands::forget_credentials, commands::pick_folder, commands::open_external, commands::record_play, commands::add_play_seconds, commands::artist_play_stats, commands::recent_albums, commands::clear_play_history, commands::play_row_count, commands::followed_artists, commands::follow_artist, commands::unfollow_artist, commands::home_artist_news, commands::home_warm, commands::mini_open, commands::mini_close, commands::window_glass, playlists::list_playlists, playlists::create_playlist, playlists::rename_playlist, playlists::set_playlist_description, playlists::set_playlist_pinned, playlists::duplicate_playlist, playlists::delete_playlist, playlists::playlist_items, playlists::playlist_add_items, playlists::playlist_remove_items, playlists::playlist_set_order, playlists::playlist_relink_item, playlists::playlist_cover, playlists::playlist_cover_pick, playlists::playlist_cover_clear, playlists::playlist_import_probe, playlists::playlist_import_folder, playlists::playlist_import_text, playlists::playlist_import_youtube, playlists::playlist_import_youtube_playlist, playlists::playlist_import_link, playlists::playlist_import_track_links, playlists::playlist_import_commit, setlist_scan::playlist_scan_youtube, setlist_scan::playlist_pick_set_file, setlist_scan::playlist_scan_file, setlist_scan::playlist_scan_cancel, ytdlp::ytdlp_status, ytdlp::ytdlp_download, ytdlp::deno_download, playlists::playlist_export, playlists::library_track_search, lyrics::lyrics_get, lyrics::lyrics_search, lyrics::lyrics_select, lyrics::lyrics_set_offset, lyrics::lyrics_set_auto_sync, lyrics::lyrics_prepare_instrumental, lyrics::lyrics_vocal_activity, lyrics::lyrics_save_lines, lyrics::lyrics_save_text, lyrics::lyrics_clear, commands::catalog_search, commands::catalog_search_tracks, commands::catalog_artist_track_candidates, commands::catalog_track_by_isrc, import::import_scan, import::import_portable_root, import::import_resolve_root, import::import_session_get, import::import_session_set, import::import_session_clear, import::import_get_dest, import::import_set_dest, import::import_apply, import::import_identify, import::import_cover_report, import::import_local_art, import::import_audition, import::import_audition_missing, import::import_audition_clear, import::import_probe_file, pipeline::rescan_library, commands::catalog_artist, commands::catalog_artist_art, commands::catalog_artist_logos, commands::catalog_artist_identity, commands::catalog_artist_socials, commands::remember_fused_artist_portrait, commands::catalog_artist_bio, commands::catalog_cached_cover_logo, commands::catalog_cover_logo, commands::catalog_cover_logo_debug, commands::catalog_ocr_experiment, commands::catalog_artist_hero_seed, commands::catalog_artist_overview, commands::catalog_artist_popular, commands::pick_artist_hero, commands::clear_artist_hero, commands::catalog_related, commands::catalog_track_listeners, commands::catalog_artist_profile, commands::catalog_album, commands::catalog_album_info, commands::catalog_art, commands::catalog_cover, commands::invalidate_catalog_cover, commands::catalog_hero_preview, commands::catalog_hero_gpu_source, commands::catalog_cached_hero_art, commands::catalog_hero_art, commands::preload_stream, commands::preload_cached_stream, commands::stream_waveform, commands::stream_cache_ready, preview::preview_resolve, preview::preview_prewarm, preview::preview_load, preview::preview_control, preview::preview_dispose, preview::player_pause_acked, preview::player_fade_pause_acked, preview::player_fade_resume, diagnostics::debug_stats, smtc::smtc_metadata, lyric_prep::lyric_prep_request, lyric_align::lyric_model_status, lyric_align::lyric_model_download, vocal_sep::vocal_sep_status, vocal_sep::vocal_sep_download, ]) .run({ let mut context = tauri::generate_context!(); // Browser args ride the WINDOW CONFIG, nothing else: wry always sets // AdditionalBrowserArguments programmatically, and at least WebView2 // 151.x then drops the WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS env var // entirely — flags "delivered" that way vanish silently on some // runtimes (they held on the home machine, gone on the work one). // Verify in the browser process command line (Get-CimInstance // Win32_Process), never by assumption. Explicit args replace wry's // defaults, so those are restated. Two WebView2 presentation fixes // live here (2026-08-26, the dark-glass work): // // 1. NO delegated compositing: with it, DWM composes the webview's // layers at rest and blends semi-transparent darks in the wrong // colorspace — the app rested washed-out LIGHT and looked correct // only while an animation forced Chromium to compose in-process. // 2. Force the sRGB color profile: on an HDR display the MAXIMIZED // window's rest path takes a different SDR-white tone mapping // than the animated path — covers blew out near-white at rest // and snapped correct on hover. One profile, one mapping, both // paths agree. // 3. Force the wheel scroll animator ON: this WebView2 shipped // wheel detents as INSTANT 120px jumps (measured: a dispatched // detent moved scrollTop in exactly one frame) while the // present pipeline ran a flawless 144Hz — scroll position // updating at detent cadence reads as "choppy but the FPS // says 144". The system animation setting is on and // prefers-reduced-motion is off, so the snap is WebView2's // embedded default, not the Chromium system heuristic; the // switch pins enable_scroll_animator=true in WebPreferences. // // Debug builds add CDP on 9222 for instrumentation (see HANDOFF.md). let base = "--disable-features=msWebOOUI,msPdfOOUI,msSmartScreenProtection,DelegatedCompositing \ --autoplay-policy=no-user-gesture-required \ --enable-smooth-scrolling \ --force-color-profile=srgb"; #[cfg(debug_assertions)] let args = format!("{base} --remote-debugging-port=9222"); #[cfg(not(debug_assertions))] let args = base.to_string(); for window in &mut context.config_mut().app.windows { window.additional_browser_args = Some(args.clone()); } context }) .expect("error while running tauri application"); }