tauri_plugin_mpv/
lib.rs

1use tauri::{
2    plugin::{Builder, TauriPlugin},
3    Manager, RunEvent, Runtime, WindowEvent,
4};
5
6pub use models::*;
7
8#[cfg(desktop)]
9mod desktop;
10#[cfg(mobile)]
11mod mobile;
12
13mod commands;
14mod error;
15mod events;
16mod ipc;
17mod models;
18mod process;
19mod utils;
20
21pub use error::{Error, Result};
22
23#[cfg(desktop)]
24use desktop::Mpv;
25#[cfg(mobile)]
26use mobile::Mpv;
27
28pub trait MpvExt<R: Runtime> {
29    fn mpv(&self) -> &Mpv<R>;
30}
31
32impl<R: Runtime, T: Manager<R>> crate::MpvExt<R> for T {
33    fn mpv(&self) -> &Mpv<R> {
34        self.state::<Mpv<R>>().inner()
35    }
36}
37
38pub fn init<R: Runtime>() -> TauriPlugin<R> {
39    Builder::new("mpv")
40        .invoke_handler(tauri::generate_handler![
41            commands::init,
42            commands::destroy,
43            commands::command,
44            commands::set_video_margin_ratio,
45        ])
46        .setup(|app, api| {
47            unsafe {
48                let locale = std::ffi::CString::new("C").unwrap();
49                libc::setlocale(libc::LC_NUMERIC, locale.as_ptr());
50            }
51
52            #[cfg(mobile)]
53            let mpv = mobile::init(app, api)?;
54            #[cfg(desktop)]
55            let mpv = desktop::init(app, api)?;
56            app.manage(mpv);
57            Ok(())
58        })
59        .on_event(|app_handle, run_event| {
60            if let RunEvent::WindowEvent {
61                label,
62                event: WindowEvent::CloseRequested { api, .. },
63                ..
64            } = run_event
65            {
66                let mpv_state = app_handle.state::<Mpv<R>>();
67
68                let instances_lock = match mpv_state.instances.lock() {
69                    Ok(guard) => guard,
70                    Err(poisoned) => {
71                        log::warn!("Mutex for mpv instances was poisoned. Recovering.");
72                        poisoned.into_inner()
73                    }
74                };
75
76                if instances_lock.contains_key(label) {
77                    api.prevent_close();
78
79                    let app_handle_clone = app_handle.clone();
80                    let window_label = label.to_string();
81
82                    tauri::async_runtime::spawn(async move {
83                        log::info!(
84                            "Close requested for '{}', destroying mpv instance first...",
85                            &window_label
86                        );
87
88                        if let Err(e) = app_handle_clone.mpv().destroy(&window_label) {
89                            log::error!(
90                                "Failed to destroy mpv for '{}': {}. Still closing.",
91                                &window_label,
92                                e
93                            );
94                        }
95
96                        if let Some(window) = app_handle_clone.get_webview_window(&window_label) {
97                            if let Err(e) = window.close() {
98                                log::error!("Failed to close window '{}': {}", &window_label, e);
99                            }
100                        }
101                    });
102                }
103            }
104        })
105        .build()
106}