diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index e8b3ff70..6a32ad96 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -420,6 +420,47 @@ async fn streamed_fetch( } +use std::path::PathBuf; +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT +fn handle_file_associations(app: AppHandle, files: Vec) { + // -- Scope handling start -- + + // You can remove this block if you only want to know about the paths, but not actually "use" them in the frontend. + + // This requires the `fs` tauri plugin and is required to make the plugin's frontend work: + // use tauri_plugin_fs::FsExt; + // let fs_scope = app.fs_scope(); + + // This is for the `asset:` protocol to work: + let asset_protocol_scope = app.asset_protocol_scope(); + + for file in &files { + // This requires the `fs` plugin: + // let _ = fs_scope.allow_file(file); + + // This is for the `asset:` protocol: + let _ = asset_protocol_scope.allow_file(file); + } + + // -- Scope handling end -- + + let files = files + .into_iter() + .map(|f| { + let file = f.to_string_lossy().replace("\\", "\\\\"); // escape backslash + format!("\"{file}\"",) // wrap in quotes for JS array + }) + .collect::>() + .join(","); + + tauri::WebviewWindowBuilder::new(&app, "main", Default::default()) + .initialization_script(&format!("window.tauriOpenedFiles = [{files}]")) + .build() + .unwrap(); + } + fn main() { tauri::Builder::default() .plugin(tauri_plugin_http::init()) @@ -429,6 +470,35 @@ fn main() { .plugin(tauri_plugin_dialog::init()) .plugin(tauri_plugin_os::init()) .plugin(tauri_plugin_fs::init()) + .setup(|#[allow(unused_variables)] app| { + #[cfg(any(windows, target_os = "linux"))] + { + let mut files = Vec::new(); + + // NOTICE: `args` may include URL protocol (`your-app-protocol://`) + // or arguments (`--`) if your app supports them. + // files may aslo be passed as `file://path/to/file` + for maybe_file in std::env::args().skip(1) { + // skip flags like -f or --flag + if maybe_file.starts_with("-") { + continue; + } + + // handle `file://` path urls and skip other urls + if let Ok(url) = url::Url::parse(&maybe_file) { + if let Ok(path) = url.to_file_path() { + files.push(path); + } + } else { + files.push(PathBuf::from(maybe_file)) + } + } + + handle_file_associations(app.handle().clone(), files); + } + + Ok(()) + }) .invoke_handler(tauri::generate_handler![ greet, native_request, @@ -441,8 +511,26 @@ fn main() { install_py_dependencies, streamed_fetch, ]) - .run(tauri::generate_context!()) - .expect("error while running tauri application"); + .build(tauri::generate_context!()) + .expect("error while running tauri application") + .run( + // Copyright 2019-2024 Tauri Programme within The Commons Conservancy + // SPDX-License-Identifier: Apache-2.0 + // SPDX-License-Identifier: MIT + #[allow(unused_variables)] + |app, event| { + #[cfg(any(target_os = "macos", target_os = "ios"))] + if let tauri::RunEvent::Opened { urls } = event { + let files = urls + .into_iter() + .filter_map(|url| url.to_file_path().ok()) + .collect::>(); + + handle_file_associations(app.clone(), files); + } + }, + ); + } fn header_map_to_json(header_map: &HeaderMap) -> serde_json::Value { diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 3d8c81e0..8165990b 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -18,7 +18,14 @@ "src-python/*" ], "targets": "all", - "createUpdaterArtifacts": "v1Compatible" + "createUpdaterArtifacts": "v1Compatible", + "fileAssociations": [ + { + "ext": [ + "risum", "risup", "charx" + ] + } + ] }, "productName": "RisuAI", "mainBinaryName": "RisuAI", diff --git a/src/ts/characterCards.ts b/src/ts/characterCards.ts index 47b3a91a..9c50d158 100644 --- a/src/ts/characterCards.ts +++ b/src/ts/characterCards.ts @@ -15,6 +15,7 @@ import type { OnnxModelFiles } from "./process/transformers" import { CharXReader, CharXWriter } from "./process/processzip" import { Capacitor } from "@capacitor/core" import { exportModule, readModule, type RisuModule } from "./process/modules" +import { readFile } from "@tauri-apps/plugin-fs" export const hubURL = "https://sv.risuai.xyz" @@ -408,6 +409,41 @@ export async function characterURLImport() { } }); } + + if("tauriOpenedFiles" in window){ + //@ts-ignore + const files:string[] = window.tauriOpenedFiles + if(files){ + for(const file of files){ + const data = await readFile(file) + if(file.endsWith('.charx')){ + await importCharacterProcess({ + name: file, + data: data + }) + } + if(file.endsWith('.risupreset') || file.endsWith('.risup')){ + await importPreset({ + name: file, + data: data + }) + SettingsMenuIndex.set(1) + settingsOpen.set(true) + alertNormal(language.successImport) + } + if(file.endsWith('risum')){ + const md = await readModule(Buffer.from(data)) + md.id = v4() + const db = get(DataBase) + db.modules.push(md) + setDatabase(db) + alertNormal(language.successImport) + SettingsMenuIndex.set(14) + settingsOpen.set(true) + } + } + } + } } diff --git a/tsconfig.json b/tsconfig.json index ca06bddc..80c16c31 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,9 +1,9 @@ { "extends": "@tsconfig/svelte/tsconfig.json", "compilerOptions": { - "target": "ESNext", + "target": "ES2022", "useDefineForClassFields": true, - "module": "ESNext", + "module": "ES2022", "resolveJsonModule": true, "baseUrl": ".", /**