mod commands; mod community; mod config; mod cover_logo; mod diagnostics; mod freenet; mod friends; mod persona; mod hero_crop; mod import; mod inbox; mod ledger; mod hero_detector; mod loudness; mod lyric_align; mod lyric_prep; mod lyrics; mod paths; mod pipeline; mod playback; mod profile; mod playlist_formats; mod playlists; mod provider_playlist; mod preview; mod setlist_scan; mod shared_playlists; mod shazam; mod slsk_link; mod smtc; mod spaces; mod proposals; mod overlap; 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()); // The experimental Freenet layer: applies the saved opt-in (off // by default) and forwards adapter status to the webview. Fully // isolated — its absence or failure touches nothing else. freenet::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::slsk_join_room, commands::slsk_leave_room, commands::slsk_say_room, commands::slsk_message_user, commands::slsk_room_list, commands::slsk_browse_user, commands::slsk_user_info, commands::slsk_user_interests, commands::slsk_similar_users, slsk_link::slsk_link_status, slsk_link::slsk_link_self, slsk_link::slsk_link_unlink, slsk_link::slsk_link_check, slsk_link::slsk_link_forget, friends::friends_list, friends::friend_request, friends::friend_request_by_key, friends::friend_accept, friends::friend_decline, friends::friend_remove, friends::friend_forget, shared_playlists::shared_playlists_mine, shared_playlists::shared_playlist_publish, shared_playlists::shared_playlist_withdraw, shared_playlists::shared_playlist_fetch, shared_playlists::shared_playlist_import, shared_playlists::share_send, shared_playlists::shares_inbox, shared_playlists::share_dismiss, inbox::inbox_status, inbox::inbox_publish, inbox::inbox_check, spaces::spaces_list, spaces::space_create, spaces::space_open, spaces::space_post, spaces::space_invite, spaces::space_remove_member, spaces::space_set_pinned, spaces::space_leave, proposals::space_board, proposals::space_propose, proposals::space_decide, overlap::overlap_list, overlap::overlap_compute, overlap::overlap_forget, commands::buddy_list, commands::buddy_add, commands::buddy_remove, 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, freenet::freenet_status, freenet::freenet_set_enabled, freenet::freenet_detect, freenet::freenet_set_load_remote_images, freenet::freenet_node_info, freenet::freenet_node_start, freenet::freenet_node_stop, community::contacts_meta_list, community::contact_meta_set, community::community_pick_file, persona::persona_status, persona::persona_create, persona::persona_export, persona::persona_import, persona::persona_rotate, persona::persona_remove, profile::profile_get, profile::profile_publish, profile::profile_set_avatar, profile::profile_clear_avatar, 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)] // A second instance needs its own CDP port, or it silently fails // to bind and cannot be driven at all. let cdp = std::env::var("SOULSTREAM_CDP_PORT").unwrap_or_else(|_| "9222".into()); let args = format!("{base} --remote-debugging-port={cdp}"); #[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"); }