feat: wire up file-based logging for the Windows player path

Release builds use windows_subsystem="windows" (no console) and there
was no logger backend registered at all -- every log::warn!/error! call
in the player code was silently dropped. Adds tauri-plugin-log writing
to the app's log dir, and logs every step of native player surface
setup, load attempts, and mpv end-file events so a real failure reason
is visible instead of just "it went back to the previous screen".
This commit is contained in:
KhooLy 2026-06-18 02:14:13 +03:00
parent 0e57892ab8
commit e7aedd796e
6 changed files with 282 additions and 1 deletions

245
src-tauri/Cargo.lock generated
View file

@ -43,6 +43,17 @@ dependencies = [
"subtle",
]
[[package]]
name = "ahash"
version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9"
dependencies = [
"getrandom 0.2.17",
"once_cell",
"version_check",
]
[[package]]
name = "aho-corasick"
version = "1.1.4"
@ -73,6 +84,23 @@ version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[package]]
name = "android_log-sys"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84521a3cf562bc62942e294181d9eef17eb38ceb8c68677bc49f144e4c3d4f8d"
[[package]]
name = "android_logger"
version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbb4e440d04be07da1f1bf44fb4495ebd58669372fe0cffa6e48595ac5bd88a3"
dependencies = [
"android_log-sys",
"env_filter",
"log",
]
[[package]]
name = "android_system_properties"
version = "0.1.5"
@ -106,6 +134,12 @@ dependencies = [
"rustversion",
]
[[package]]
name = "arrayvec"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
[[package]]
name = "assert_cfg"
version = "0.1.0"
@ -533,6 +567,30 @@ dependencies = [
"piper",
]
[[package]]
name = "borsh"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a"
dependencies = [
"borsh-derive",
"bytes",
"cfg_aliases",
]
[[package]]
name = "borsh-derive"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfcfdc083699101d5a7965e49925975f2f55060f94f9a05e7187be95d530ca59"
dependencies = [
"once_cell",
"proc-macro-crate 3.5.0",
"proc-macro2",
"quote",
"syn 2.0.117",
]
[[package]]
name = "brotli"
version = "8.0.2"
@ -580,6 +638,40 @@ version = "3.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
[[package]]
name = "byte-unit"
version = "5.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37bcaa4a0975bed4a760af3efe4368825098ce5f9d37a30c5a021d635dc63d8f"
dependencies = [
"rust_decimal",
"schemars 1.2.1",
"serde",
"utf8-width",
]
[[package]]
name = "bytecheck"
version = "0.6.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2"
dependencies = [
"bytecheck_derive",
"ptr_meta",
"simdutf8",
]
[[package]]
name = "bytecheck_derive"
version = "0.6.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "bytemuck"
version = "1.25.0"
@ -1373,6 +1465,16 @@ dependencies = [
"syn 2.0.117",
]
[[package]]
name = "env_filter"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2"
dependencies = [
"log",
"regex",
]
[[package]]
name = "equivalent"
version = "1.0.2"
@ -1436,6 +1538,15 @@ dependencies = [
"simd-adler32",
]
[[package]]
name = "fern"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4316185f709b23713e41e3195f90edef7fb00c3ed4adc79769cf09cc762a3b29"
dependencies = [
"log",
]
[[package]]
name = "field-offset"
version = "0.3.6"
@ -1500,6 +1611,7 @@ dependencies = [
"tauri-plugin-fs",
"tauri-plugin-http",
"tauri-plugin-libmpv",
"tauri-plugin-log",
"tauri-plugin-notification",
"tauri-plugin-process",
"tauri-plugin-shell",
@ -2077,6 +2189,9 @@ name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
dependencies = [
"ahash",
]
[[package]]
name = "hashbrown"
@ -3011,6 +3126,9 @@ name = "log"
version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
dependencies = [
"value-bag",
]
[[package]]
name = "lru-slab"
@ -3307,6 +3425,15 @@ dependencies = [
"syn 2.0.117",
]
[[package]]
name = "num_threads"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
dependencies = [
"libc",
]
[[package]]
name = "objc2"
version = "0.6.4"
@ -3916,6 +4043,26 @@ version = "2.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac"
[[package]]
name = "ptr_meta"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1"
dependencies = [
"ptr_meta_derive",
]
[[package]]
name = "ptr_meta_derive"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "publicsuffix"
version = "2.3.0"
@ -4197,6 +4344,15 @@ version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
[[package]]
name = "rend"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c"
dependencies = [
"bytecheck",
]
[[package]]
name = "reqwest"
version = "0.12.28"
@ -4321,6 +4477,35 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "rkyv"
version = "0.7.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2297bf9c81a3f0dc96bc9521370b88f054168c29826a75e89c55ff196e7ed6a1"
dependencies = [
"bitvec",
"bytecheck",
"bytes",
"hashbrown 0.12.3",
"ptr_meta",
"rend",
"rkyv_derive",
"seahash",
"tinyvec",
"uuid",
]
[[package]]
name = "rkyv_derive"
version = "0.7.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84d7b42d4b8d06048d3ac8db0eb31bcb942cbeb709f0b5f2b2ebde398d3038f5"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "rlimit"
version = "0.10.2"
@ -4340,6 +4525,23 @@ dependencies = [
"ordered-multimap",
]
[[package]]
name = "rust_decimal"
version = "1.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be2a24f50780bc85f09cc6ac299bdf1424302742d77221106859c9d8b102126a"
dependencies = [
"arrayvec",
"borsh",
"bytes",
"num-traits",
"rand 0.8.6",
"rkyv",
"serde",
"serde_json",
"wasm-bindgen",
]
[[package]]
name = "rustc-hash"
version = "2.1.2"
@ -4529,6 +4731,12 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "seahash"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
[[package]]
name = "security-framework"
version = "3.7.0"
@ -4998,6 +5206,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
@ -5375,6 +5584,28 @@ dependencies = [
"thiserror 2.0.18",
]
[[package]]
name = "tauri-plugin-log"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7545bd67f070a4500432c826e2e0682146a1d6712aee22a2786490156b574d93"
dependencies = [
"android_logger",
"byte-unit",
"fern",
"log",
"objc2",
"objc2-foundation",
"serde",
"serde_json",
"serde_repr",
"swift-rs",
"tauri",
"tauri-plugin",
"thiserror 2.0.18",
"time",
]
[[package]]
name = "tauri-plugin-notification"
version = "2.3.3"
@ -5654,7 +5885,9 @@ checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c"
dependencies = [
"deranged",
"itoa",
"libc",
"num-conv",
"num_threads",
"powerfmt",
"serde_core",
"time-core",
@ -6170,6 +6403,12 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
name = "utf8-width"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1292c0d970b54115d14f2492fe0170adf21d68a1de108eebc51c1df4f346a091"
[[package]]
name = "utf8_iter"
version = "1.0.4"
@ -6188,6 +6427,12 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "value-bag"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0"
[[package]]
name = "version-compare"
version = "0.2.1"

View file

@ -37,6 +37,7 @@ tauri-plugin-single-instance = "2"
tauri-plugin-updater = "2"
tauri-plugin-process = "2"
tauri-plugin-dialog = "2"
tauri-plugin-log = "2"
[target.'cfg(target_os = "linux")'.dependencies]
gtk = "0.18"

View file

@ -301,6 +301,15 @@ pub fn run() {
}
}
}))
.plugin(
tauri_plugin_log::Builder::new()
.level(log::LevelFilter::Debug)
.targets([
tauri_plugin_log::Target::new(tauri_plugin_log::TargetKind::LogDir { file_name: None }),
tauri_plugin_log::Target::new(tauri_plugin_log::TargetKind::Stdout),
])
.build(),
)
.plugin(tauri_plugin_updater::Builder::new().build())
.plugin(tauri_plugin_process::init())
.plugin(tauri_plugin_dialog::init())

View file

@ -673,6 +673,7 @@ impl MpvRenderer {
let text = unsafe { CStr::from_ptr(msg.text) }.to_string_lossy();
let text = text.trim_end();
if !text.is_empty() {
log::debug!("mpv: {text}");
if self.log_ring.len() >= 20 {
self.log_ring.pop_front();
}

View file

@ -256,6 +256,7 @@ pub fn player_load(
start_at: Option<u64>,
total_duration: Option<u64>,
) -> Result<(), String> {
log::info!("player_load: url={url} start_at={start_at:?} total_duration={total_duration:?}");
*state.thumb_url.lock().unwrap() = Some(url.clone());
#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
@ -263,6 +264,7 @@ pub fn player_load(
if let Some(surface) = ensure_native_player_surface(&app, &state) {
return surface.load(url, start_at, total_duration);
}
log::warn!("player_load: no native player surface available, falling back to headless renderer");
}
let _ = app;

View file

@ -129,6 +129,7 @@ pub fn install(app_handle: AppHandle) -> Result<NativePlayerSurface, String> {
let app = app_handle.clone();
std::thread::spawn(move || {
log::info!("player surface: install thread starting");
// Register the OpenGL-capable window class once per process.
static CLASS_REGISTERED: OnceLock<()> = OnceLock::new();
CLASS_REGISTERED.get_or_init(|| {
@ -168,6 +169,7 @@ pub fn install(app_handle: AppHandle) -> Result<NativePlayerSurface, String> {
)
};
if child_hwnd == 0 {
log::error!("player surface: CreateWindowExW failed for mpv surface");
let _ = setup_tx.send(Err("CreateWindowExW failed for mpv surface".to_string()));
return;
}
@ -180,6 +182,7 @@ pub fn install(app_handle: AppHandle) -> Result<NativePlayerSurface, String> {
// WGL context setup
let hdc = unsafe { GetDC(child_hwnd) };
if hdc == 0 {
log::error!("player surface: GetDC failed");
let _ = setup_tx.send(Err("GetDC failed".to_string()));
return;
}
@ -195,20 +198,24 @@ pub fn install(app_handle: AppHandle) -> Result<NativePlayerSurface, String> {
let pf_idx = unsafe { ChoosePixelFormat(hdc, &pfd) };
if pf_idx == 0 {
log::error!("player surface: ChoosePixelFormat failed");
let _ = setup_tx.send(Err("ChoosePixelFormat failed".to_string()));
return;
}
if unsafe { SetPixelFormat(hdc, pf_idx, &pfd) } == FALSE {
log::error!("player surface: SetPixelFormat failed");
let _ = setup_tx.send(Err("SetPixelFormat failed".to_string()));
return;
}
let hglrc = unsafe { wglCreateContext(hdc) };
if hglrc == 0 {
log::error!("player surface: wglCreateContext failed");
let _ = setup_tx.send(Err("wglCreateContext failed".to_string()));
return;
}
if unsafe { wglMakeCurrent(hdc, hglrc) } == FALSE {
log::error!("player surface: wglMakeCurrent failed");
unsafe { wglDeleteContext(hglrc) };
let _ = setup_tx.send(Err("wglMakeCurrent failed".to_string()));
return;
@ -224,8 +231,12 @@ pub fn install(app_handle: AppHandle) -> Result<NativePlayerSurface, String> {
let mut renderer = state.player_renderer.lock().unwrap();
if renderer.is_none() {
match crate::mpv_render::MpvRenderer::new() {
Ok(r) => *renderer = Some(r),
Ok(r) => {
log::info!("player surface: MpvRenderer::new() succeeded");
*renderer = Some(r);
}
Err(e) => {
log::error!("player surface: MpvRenderer::new() failed: {e}");
unsafe {
wglMakeCurrent(0 as _, 0 as _);
wglDeleteContext(hglrc);
@ -237,6 +248,7 @@ pub fn install(app_handle: AppHandle) -> Result<NativePlayerSurface, String> {
}
if let Some(r) = renderer.as_mut() {
if let Err(e) = r.prepare_opengl_context() {
log::error!("player surface: prepare_opengl_context() failed: {e}");
unsafe {
wglMakeCurrent(0 as _, 0 as _);
wglDeleteContext(hglrc);
@ -252,6 +264,7 @@ pub fn install(app_handle: AppHandle) -> Result<NativePlayerSurface, String> {
}
}
log::info!("player surface: setup complete, entering render loop");
let _ = setup_tx.send(Ok(()));
// Render + command loop
@ -263,6 +276,7 @@ pub fn install(app_handle: AppHandle) -> Result<NativePlayerSurface, String> {
while let Ok(cmd) = receiver.try_recv() {
match cmd {
SurfaceCommand::Load { url, start_at, .. } => {
log::info!("player surface: loading url={url} start_at={start_at:?}");
unsafe { ShowWindow(child_hwnd, SW_SHOW) };
unsafe {
SetWindowPos(
@ -282,11 +296,16 @@ pub fn install(app_handle: AppHandle) -> Result<NativePlayerSurface, String> {
let mut renderer = state.player_renderer.lock().unwrap();
if let Some(r) = renderer.as_mut() {
if let Err(e) = r.load(&url, start_at) {
log::error!("player surface: load() failed: {e}");
drop(renderer);
let _ = app.emit("native-player-error", e);
visible = false;
unsafe { ShowWindow(child_hwnd, SW_HIDE) };
} else {
log::info!("player surface: load() command accepted by mpv");
}
} else {
log::error!("player surface: Load command received but renderer is None");
}
}
SurfaceCommand::Hide => {
@ -378,7 +397,9 @@ fn check_player_events(app: &AppHandle) {
};
for event in events {
let crate::mpv_render::PlayerEvent::EndFile { eof, error } = event;
log::info!("player surface: mpv END_FILE event eof={eof} error={error:?}");
if let Some(message) = error {
log::error!("player surface: stream failed to play: {message}");
let _ = app.emit("native-player-error", message);
continue;
}
@ -388,8 +409,10 @@ fn check_player_events(app: &AppHandle) {
let next_sub = state.next_ep_subtitle.lock().unwrap().clone();
let auto_play = *state.auto_play_next_episode.lock().unwrap();
if !next_sub.is_empty() && auto_play {
log::info!("player surface: eof reached, auto-playing next episode");
let _ = app.emit("native-player-next-episode", ());
} else {
log::info!("player surface: eof reached, closing player");
let _ = app.emit("native-player-close-requested", ());
}
}