diff --git a/src-tauri/src/cmd.rs b/src-tauri/src/cmd.rs index f6a00f0cf0..97b537cb19 100644 --- a/src-tauri/src/cmd.rs +++ b/src-tauri/src/cmd.rs @@ -138,9 +138,9 @@ pub fn install_plugin(path_list: Vec) -> Result { let path = std::path::Path::new(&path); let file_name = path.file_name().unwrap().to_str().unwrap(); let file_name = file_name.replace(".potext", ""); - if !file_name.starts_with("[plugin]") { + if !file_name.starts_with("plugin") { return Err(Error::Error( - "Invalid Plugin: file name must start with [plugin]".into(), + "Invalid Plugin: file name must start with plugin".into(), )); } diff --git a/src-tauri/src/config.rs b/src-tauri/src/config.rs index 0b3b8769a3..f24dc1cd95 100644 --- a/src-tauri/src/config.rs +++ b/src-tauri/src/config.rs @@ -1,4 +1,4 @@ -use crate::APP; +use crate::{error::Error, APP}; use dirs::config_dir; use log::{info, warn}; use serde_json::{json, Value}; @@ -23,6 +23,144 @@ pub fn init_config(app: &mut tauri::App) { } } app.manage(StoreWrapper(Mutex::new(store))); + let _ = check_service_available(); +} + +fn check_available(list: Vec, builtin: Vec<&str>, plugin: Vec, key: &str) { + let origin_length = list.len(); + let mut new_list = list.clone(); + for service in list { + let name = service.split("@").collect::>()[0]; + let mut is_available = true; + if name.starts_with("plugin") { + if !plugin.contains(&name.to_string()) { + is_available = false; + } + } else { + if !builtin.contains(&name) { + is_available = false; + } + } + if !is_available { + new_list.retain(|x| x != &service); + } + } + if new_list.len() != origin_length { + set(key, new_list); + } +} + +pub fn check_service_available() -> Result<(), Error> { + let builtin_recognize_list: Vec<&str> = vec![ + "baidu_ocr", + "baidu_accurate_ocr", + "baidu_img_ocr", + "iflytek_ocr", + "iflytek_intsig_ocr", + "iflytek_latex_ocr", + "qrcode", + "simple_latex_ocr", + "system", + "tencent_ocr", + "tencent_accurate_ocr", + "tencent_img_ocr", + "tesseract", + "volcengine_ocr", + "volcengine_multi_lang_ocr", + ]; + let builtin_translate_list: Vec<&str> = vec![ + "alibaba", + "baidu", + "baidu_field", + "bing", + "bing_dict", + "caiyun", + "cambridge_dict", + "chatglm", + "deepl", + "geminipro", + "niutrans", + "ollama", + "openai", + "google", + "tencent", + "transmart", + "volcengine", + "yandex", + "youdao", + ]; + let builtin_tts_list: Vec<&str> = vec!["lingva_tts"]; + let builtin_collection_list: Vec<&str> = vec!["anki", "eudic"]; + + let plugin_recognize_list: Vec = get_plugin_list("recognize").unwrap_or_default(); + let plugin_translate_list: Vec = get_plugin_list("translate").unwrap_or_default(); + let plugin_tts_list: Vec = get_plugin_list("tts").unwrap_or_default(); + let plugin_collection_list: Vec = get_plugin_list("collection").unwrap_or_default(); + if let Some(recognize_service_list) = get("recognize_service_list") { + let recognize_service_list: Vec = serde_json::from_value(recognize_service_list)?; + check_available( + recognize_service_list, + builtin_recognize_list, + plugin_recognize_list, + "recognize_service_list", + ); + } + if let Some(translate_service_list) = get("translate_service_list") { + let translate_service_list: Vec = serde_json::from_value(translate_service_list)?; + check_available( + translate_service_list, + builtin_translate_list, + plugin_translate_list, + "translate_service_list", + ); + } + if let Some(tts_service_list) = get("tts_service_list") { + let tts_service_list: Vec = serde_json::from_value(tts_service_list)?; + check_available( + tts_service_list, + builtin_tts_list, + plugin_tts_list, + "tts_service_list", + ); + } + if let Some(collection_service_list) = get("collection_service_list") { + let collection_service_list: Vec = serde_json::from_value(collection_service_list)?; + check_available( + collection_service_list, + builtin_collection_list, + plugin_collection_list, + "tts_service_list", + ); + } + Ok(()) +} + +pub fn get_plugin_list(plugin_type: &str) -> Option> { + let app_handle = APP.get().unwrap(); + let config_dir = dirs::config_dir()?; + let config_dir = config_dir.join(app_handle.config().tauri.bundle.identifier.clone()); + let plugin_dir = config_dir.join("plugins"); + let plugin_dir = plugin_dir.join(plugin_type); + + // dirs in plugin_dir + let mut plugin_list = vec![]; + if plugin_dir.exists() { + let read_dir = std::fs::read_dir(plugin_dir).ok()?; + for entry in read_dir { + let entry = entry.ok()?; + + if entry.path().is_dir() { + let name = entry.file_name().to_str()?.to_string(); + if name.starts_with("plugin") { + plugin_list.push(name); + } else { + // Remove old plugin + let _ = std::fs::remove_dir_all(entry.path()); + } + } + } + } + Some(plugin_list) } pub fn get(key: &str) -> Option { diff --git a/src/utils/service_instance.ts b/src/utils/service_instance.ts index 10fa7d7162..766739da01 100644 --- a/src/utils/service_instance.ts +++ b/src/utils/service_instance.ts @@ -2,7 +2,7 @@ export enum ServiceType { TRANSLATE = 'translate', RECOGNIZE = 'recognize', TTS = 'tts', - COLLECTION = 'Collection' + COLLECTION = 'Collection', } export enum ServiceSourceType { @@ -11,40 +11,40 @@ export enum ServiceSourceType { } export function getServiceSouceType(serviceInstanceKey: string): ServiceSourceType { - if (serviceInstanceKey.startsWith('[plugin]')) { - return ServiceSourceType.PLUGIN + if (serviceInstanceKey.startsWith('plugin')) { + return ServiceSourceType.PLUGIN; } else { - return ServiceSourceType.BUILDIN + return ServiceSourceType.BUILDIN; } } export function whetherPluginService(serviceInstanceKey: string): boolean { - return getServiceSouceType(serviceInstanceKey) === ServiceSourceType.PLUGIN + return getServiceSouceType(serviceInstanceKey) === ServiceSourceType.PLUGIN; } - // The serviceInstanceKey consists of the service name and it's id, separated by @ // In earlier versions, the @ separator and id were optional, so they all have only one instance. export function createServiceInstanceKey(serviceName: string): string { - const randomId = Math.random().toString(36).substring(2) - return `${serviceName}@${randomId}` + const randomId = Math.random().toString(36).substring(2); + return `${serviceName}@${randomId}`; } - // if the serviceInstanceKey is from a plugin, serviceName is it's pluginId export function getServiceName(serviceInstanceKey: string): string { - return serviceInstanceKey.split('@')[0] + return serviceInstanceKey.split('@')[0]; } export function getDisplayInstanceName(instanceName: string, serviceNameSupplier: () => string): string { - return instanceName || serviceNameSupplier() + return instanceName || serviceNameSupplier(); } -export const INSTANCE_NAME_CONFIG_KEY = 'instanceName' - -export function whetherAvailableService(serviceInstanceKey: string, availableServices: Record>) { - const serviceSourceType = getServiceSouceType(serviceInstanceKey) - const serviceName = getServiceName(serviceInstanceKey) - return availableServices[serviceSourceType]?.[serviceName] !== undefined +export const INSTANCE_NAME_CONFIG_KEY = 'instanceName'; +export function whetherAvailableService( + serviceInstanceKey: string, + availableServices: Record> +) { + const serviceSourceType = getServiceSouceType(serviceInstanceKey); + const serviceName = getServiceName(serviceInstanceKey); + return availableServices[serviceSourceType]?.[serviceName] !== undefined; } diff --git a/src/window/Config/pages/History/index.jsx b/src/window/Config/pages/History/index.jsx index e5b1ac9f58..19e3b5f70d 100644 --- a/src/window/Config/pages/History/index.jsx +++ b/src/window/Config/pages/History/index.jsx @@ -153,7 +153,7 @@ export default function History() { }) && ( - {item.service.startsWith('[plugin]') ? ( + {item.service.startsWith('plugin') ? (
- {selectedItem.service.startsWith('[plugin]') ? ( + {selectedItem.service.startsWith('plugin') ? ( { - if (serviceName.startsWith('[plugin]')) { + if (serviceName.startsWith('plugin')) { const pluginConfig = (await store.get(serviceName)) ?? {}; let [func, utils] = await invoke_plugin( @@ -334,7 +334,7 @@ export default function History() { > diff --git a/src/window/Config/pages/Service/Collection/ServiceItem/index.jsx b/src/window/Config/pages/Service/Collection/ServiceItem/index.jsx index ca966d39c5..69c1f3bf3f 100644 --- a/src/window/Config/pages/Service/Collection/ServiceItem/index.jsx +++ b/src/window/Config/pages/Service/Collection/ServiceItem/index.jsx @@ -9,7 +9,7 @@ import * as builtinServices from '../../../../../../services/collection'; export default function ServiceItem(props) { const { name, deleteService, setConfigName, onConfigOpen, pluginList, ...drag } = props; - const serviceType = name.startsWith('[plugin]') ? 'plugin' : 'builtin'; + const serviceType = name.startsWith('plugin') ? 'plugin' : 'builtin'; const { t } = useTranslation(); return serviceType === 'plugin' && !(name in pluginList) ? ( diff --git a/src/window/Config/pages/Service/Recognize/ConfigModal/index.jsx b/src/window/Config/pages/Service/Recognize/ConfigModal/index.jsx index fb1dc87dec..47c905b65c 100644 --- a/src/window/Config/pages/Service/Recognize/ConfigModal/index.jsx +++ b/src/window/Config/pages/Service/Recognize/ConfigModal/index.jsx @@ -8,9 +8,9 @@ import { PluginConfig } from '../../PluginConfig'; export default function ConfigModal(props) { const { isOpen, onOpenChange, name, updateServiceList, pluginList } = props; - const serviceType = name.startsWith('[plugin]') ? 'plugin' : 'builtin'; + const serviceType = name.startsWith('plugin') ? 'plugin' : 'builtin'; const { t } = useTranslation(); - const ConfigComponent = name.startsWith('[plugin]') ? PluginConfig : builtinServices[name].Config; + const ConfigComponent = name.startsWith('plugin') ? PluginConfig : builtinServices[name].Config; return serviceType === 'plugin' && !(name in pluginList) ? ( <> diff --git a/src/window/Config/pages/Service/Recognize/ServiceItem/index.jsx b/src/window/Config/pages/Service/Recognize/ServiceItem/index.jsx index 7efc4171d1..cb48b91606 100644 --- a/src/window/Config/pages/Service/Recognize/ServiceItem/index.jsx +++ b/src/window/Config/pages/Service/Recognize/ServiceItem/index.jsx @@ -10,7 +10,7 @@ import { osType } from '../../../../../../utils/env'; export default function ServiceItem(props) { const { name, deleteService, setConfigName, onConfigOpen, pluginList, ...drag } = props; - const serviceType = name.startsWith('[plugin]') ? 'plugin' : 'builtin'; + const serviceType = name.startsWith('plugin') ? 'plugin' : 'builtin'; const { t } = useTranslation(); return serviceType === 'plugin' && !(name in pluginList) ? ( diff --git a/src/window/Config/pages/Service/Tts/ConfigModal/index.jsx b/src/window/Config/pages/Service/Tts/ConfigModal/index.jsx index 3e07f1d4b5..97724bb38b 100644 --- a/src/window/Config/pages/Service/Tts/ConfigModal/index.jsx +++ b/src/window/Config/pages/Service/Tts/ConfigModal/index.jsx @@ -7,9 +7,9 @@ import { PluginConfig } from '../../PluginConfig'; export default function ConfigModal(props) { const { isOpen, onOpenChange, name, updateServiceList, pluginList } = props; - const serviceType = name.startsWith('[plugin]') ? 'plugin' : 'builtin'; + const serviceType = name.startsWith('plugin') ? 'plugin' : 'builtin'; const { t } = useTranslation(); - const ConfigComponent = name.startsWith('[plugin]') ? PluginConfig : builtinServices[name].Config; + const ConfigComponent = name.startsWith('plugin') ? PluginConfig : builtinServices[name].Config; return serviceType === 'plugin' && !(name in pluginList) ? ( <> diff --git a/src/window/Config/pages/Service/Tts/ServiceItem/index.jsx b/src/window/Config/pages/Service/Tts/ServiceItem/index.jsx index 6bfc654cd5..91f773c894 100644 --- a/src/window/Config/pages/Service/Tts/ServiceItem/index.jsx +++ b/src/window/Config/pages/Service/Tts/ServiceItem/index.jsx @@ -9,7 +9,7 @@ import * as builtinServices from '../../../../../../services/tts'; export default function ServiceItem(props) { const { name, deleteService, setConfigName, onConfigOpen, pluginList, ...drag } = props; - const serviceType = name.startsWith('[plugin]') ? 'plugin' : 'builtin'; + const serviceType = name.startsWith('plugin') ? 'plugin' : 'builtin'; const { t } = useTranslation(); return serviceType === 'plugin' && !(name in pluginList) ? ( diff --git a/src/window/Recognize/ControlArea/index.jsx b/src/window/Recognize/ControlArea/index.jsx index 4536fa5fbc..5c2bc18a67 100644 --- a/src/window/Recognize/ControlArea/index.jsx +++ b/src/window/Recognize/ControlArea/index.jsx @@ -51,7 +51,7 @@ export default function ControlArea() { } > - {serviceName.startsWith('[plugin]') + {serviceName.startsWith('plugin') ? pluginList[serviceName].display : t(`services.recognize.${serviceName}.title`)} @@ -87,7 +87,7 @@ export default function ControlArea() { } > - {name.startsWith('[plugin]') + {name.startsWith('plugin') ? pluginList[name].display : t(`services.recognize.${name}.title`)} diff --git a/src/window/Recognize/TextArea/index.jsx b/src/window/Recognize/TextArea/index.jsx index 718e214463..bc80e1a43b 100644 --- a/src/window/Recognize/TextArea/index.jsx +++ b/src/window/Recognize/TextArea/index.jsx @@ -39,7 +39,7 @@ export default function TextArea() { setError(''); if (base64 !== '' && serviceName && autoCopy !== null && deleteNewline !== null && hideWindow !== null) { setLoading(true); - if (serviceName.startsWith('[plugin]')) { + if (serviceName.startsWith('plugin')) { if (language in pluginList[serviceName].language) { let id = nanoid(); recognizeId = id; diff --git a/src/window/Translate/components/SourceArea/index.jsx b/src/window/Translate/components/SourceArea/index.jsx index f77432e03f..15861b3b22 100644 --- a/src/window/Translate/components/SourceArea/index.jsx +++ b/src/window/Translate/components/SourceArea/index.jsx @@ -66,7 +66,7 @@ export default function SourceArea(props) { setWindowType('[IMAGE_TRANSLATE]'); const base64 = await invoke('get_base64'); const serviceName = recognizeServiceList[0]; - if (serviceName.startsWith('[plugin]')) { + if (serviceName.startsWith('plugin')) { if (recognizeLanguage in pluginList['recognize'][serviceName].language) { const pluginConfig = (await store.get(serviceName)) ?? {}; let [func, utils] = await invoke_plugin('recognize', serviceName); @@ -170,7 +170,7 @@ export default function SourceArea(props) { detected = await detect(sourceText); setDetectLanguage(detected); } - if (serviceName.startsWith('[plugin]')) { + if (serviceName.startsWith('plugin')) { if (!(detected in ttsPluginInfo.language)) { throw new Error('Language not supported'); } @@ -208,7 +208,7 @@ export default function SourceArea(props) { }, [hideWindow]); useEffect(() => { - if (ttsServiceList && ttsServiceList[0].startsWith('[plugin]')) { + if (ttsServiceList && ttsServiceList[0].startsWith('plugin')) { readTextFile(`plugins/tts/${ttsServiceList[0]}/info.json`, { dir: BaseDirectory.AppConfig, }).then((infoStr) => { diff --git a/src/window/Translate/components/TargetArea/index.jsx b/src/window/Translate/components/TargetArea/index.jsx index 2301b73755..03441567ce 100644 --- a/src/window/Translate/components/TargetArea/index.jsx +++ b/src/window/Translate/components/TargetArea/index.jsx @@ -317,7 +317,7 @@ export default function TargetArea(props) { // refresh tts config useEffect(() => { - if (ttsServiceList && ttsServiceList[0].startsWith('[plugin]')) { + if (ttsServiceList && ttsServiceList[0].startsWith('plugin')) { readTextFile(`plugins/tts/${ttsServiceList[0]}/info.json`, { dir: BaseDirectory.AppConfig, }).then((infoStr) => { @@ -329,7 +329,7 @@ export default function TargetArea(props) { // handle tts speak const handleSpeak = async () => { const ttsServiceName = ttsServiceList[0]; - if (ttsServiceName.startsWith('[plugin]')) { + if (ttsServiceName.startsWith('plugin')) { const config = (await store.get(ttsServiceName)) ?? {}; if (!(targetLanguage in ttsPluginInfo.language)) { throw new Error('Language not supported'); @@ -795,7 +795,7 @@ export default function TargetArea(props) { variant='light' size='sm' onPress={async () => { - if (collectionServiceName.startsWith('[plugin]')) { + if (collectionServiceName.startsWith('plugin')) { const pluginConfig = (await store.get(collectionServiceName)) ?? {}; let [func, utils] = await invoke_plugin( 'collection', @@ -832,7 +832,7 @@ export default function TargetArea(props) { >