Files
SoulStream/src-tauri/src/lib.rs
T
KeelrLeek f55562f0ab playback: a cached track plays without asking Soulseek where it lives
Hopping between songs of an already-cached album still ran the full
"finding best source…" resolve for audio sitting complete on disk — a
second of popup between every click. The player now remembers the source
each stream item was queued from (localStorage, LRU-capped at 400) and,
before any search, asks the backend whether that exact file is
byte-complete in the stream cache. If it is, the track plays those bytes
immediately: no resolver, no popup, and no online requirement — cached
audio is playable offline, so the check sits before requireOnline.

The memory is a hint, never a promise. It is written eagerly when an item
is queued to PLAY, because a source that never delivers leaves no complete
cache file and the byte-complete probe rejects it later at no cost;
eviction and half-finished transfers fall back to the normal resolver the
same way. First play of a track records it, every play after that is
instant.
2026-08-03 16:08:51 -05:00

152 lines
5.8 KiB
Rust

mod commands;
mod config;
mod cover_logo;
mod diagnostics;
mod hero_crop;
mod hero_detector;
mod loudness;
mod pipeline;
mod playback;
mod preview;
mod state;
#[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());
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::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::album_tracks,
commands::album_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::list_playlists,
commands::create_playlist,
commands::delete_playlist,
commands::playlist_tracks,
commands::add_to_playlist,
commands::remove_from_playlist,
commands::catalog_search,
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,
])
.run({
#[allow(unused_mut)]
let mut context = tauri::generate_context!();
// Debug builds expose CDP on 9222 for instrumentation (see HANDOFF.md).
// wry always sets AdditionalBrowserArguments programmatically, so the
// WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS env var is ignored; the flag has
// to go through the window config. Explicit args replace wry's defaults,
// so those are restated here.
#[cfg(debug_assertions)]
{
for window in &mut context.config_mut().app.windows {
window.additional_browser_args = Some(
"--disable-features=msWebOOUI,msPdfOOUI,msSmartScreenProtection \
--autoplay-policy=no-user-gesture-required \
--remote-debugging-port=9222"
.into(),
);
}
}
context
})
.expect("error while running tauri application");
}