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 instance_exists = {
69                    let instances_lock = match mpv_state.instances.lock() {
70                        Ok(guard) => guard,
71                        Err(poisoned) => {
72                            log::warn!("Mutex for mpv instances was poisoned. Recovering.");
73                            poisoned.into_inner()
74                        }
75                    };
76                    instances_lock.contains_key(label)
77                };
78
79                if instance_exists {
80                    api.prevent_close();
81
82                    let app_handle_clone = app_handle.clone();
83                    let window_label = label.to_string();
84
85                    tauri::async_runtime::spawn(async move {
86                        log::info!(
87                            "Close requested for '{}', destroying mpv instance first...",
88                            &window_label
89                        );
90
91                        if let Err(e) = app_handle_clone.mpv().destroy(&window_label) {
92                            log::error!(
93                                "Failed to destroy mpv for '{}': {}. Still closing.",
94                                &window_label,
95                                e
96                            );
97                        }
98
99                        if let Some(window) = app_handle_clone.get_webview_window(&window_label) {
100                            if let Err(e) = window.close() {
101                                log::error!("Failed to close window '{}': {}", &window_label, e);
102                            }
103                        }
104                    });
105                }
106            }
107        })
108        .build()
109}