From ce16beb0d3be45909cab01a0986cd0a967b0f14d Mon Sep 17 00:00:00 2001 From: TechDecryptor <145176897+TechDecryptor@users.noreply.github.com> Date: Fri, 13 Oct 2023 16:54:43 +0000 Subject: [PATCH] Pending changes exported from your codespace --- Cargo.lock | 12 +--- Cargo.toml | 4 +- README.md | 89 ++++++++--------------- README_EN.md | 71 ------------------- info.json | 52 +++++++------- lingva.svg | 188 ------------------------------------------------- src/lib.rs | 56 ++++++++++----- volcengine.svg | 100 ++++++++++++++++++++++++++ 8 files changed, 200 insertions(+), 372 deletions(-) delete mode 100644 README_EN.md delete mode 100644 lingva.svg create mode 100644 volcengine.svg diff --git a/Cargo.lock b/Cargo.lock index 8523aff..aec3428 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,9 +40,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.2" +version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" [[package]] name = "bitflags" @@ -543,10 +543,10 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" name = "plugin" version = "1.0.0" dependencies = [ + "base64", "openssl", "reqwest", "serde_json", - "urlencoding", ] [[package]] @@ -885,12 +885,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - [[package]] name = "vcpkg" version = "0.2.15" diff --git a/Cargo.toml b/Cargo.toml index 52b8671..bcbd425 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,15 +1,15 @@ [package] name = "plugin" # 名称固定为plugin,请勿更改 version = "1.0.0" -authors = ["pot-app"] +authors = ["TechDecryptor"] edition = "2021" [lib] crate-type = ["dylib"] # pot只支持dylib类型动态库,请勿修改 [dependencies] +base64 = "0.21.4" reqwest = {version="0.11.18",features = ["blocking","json"]} -urlencoding = "2.1.3" serde_json = "1.0" [target.'cfg(target_os = "linux")'.dependencies] diff --git a/README.md b/README.md index 110ca0f..1e1b2fb 100644 --- a/README.md +++ b/README.md @@ -1,70 +1,43 @@ -# Pot-App 语音合成插件模板仓库 (以 [Lingva](https://github.com/TheDavidDelta/lingva-translate) 为例) +# Pot-App 火山 语音合成插件 (无需配置,直接使用) -### [English](./README_EN.md) | 简体中文 +## 使用方法 -### 此仓库为模板仓库,编写插件时可以直接由此仓库创建插件仓库 +### 安装 Pot -## 插件编写指南 +此插件为 [Pot App](https://github.com/pot-app/pot-desktop) 翻译插件,必须配合 [Pot App](https://github.com/pot-app/pot-desktop) 来使用 -### 1. 插件仓库创建 +### 安装插件 -- 以此仓库为模板创建一个新的仓库 -- 仓库名为 `pot-app-tts-plugin-<插件名>`,例如 `pot-app-tts-plugin-lingva_tts` +1. 下载对应平台的插件,解压得到 `.potext` 文件 +2. 打开 Pot-偏好设置-服务设置-翻译-添加外部插件-安装外部插件 +3. 选择刚刚解压得到的 `.potext` 文件,安装成功 +4. 将插件添加到服务列表即可使用 -### 2. 插件信息配置 +## Speaker -编辑 `info.json` 文件,修改以下字段: +### zh-CN -- `id`:插件唯一 id,必须以`[plugin]`开头,例如 `[plugin].com.pot-app.lingva_tts` -- `homepage`: 插件主页,填写你的仓库地址即可,例如 `https://github.com/pot-app/pot-app-tts-plugin-template` -- `display`: 插件显示名称,例如 `Lingva` -- `icon`: 插件图标,例如 `lingva.svg` -- `needs`: 插件依赖,一个数组,每个依赖为一个对象,包含以下字段: - - `key`: 依赖 key,对应该项依赖在配置文件中的名称,例如 `requestPath` - - `display`: 依赖显示名称,对应用户显示的名称,例如 `请求地址` -- `language`: 插件支持的语言映射,将 pot 的语言代码和插件发送请求时的语言代码一一对应 +| Name | Value | +|------|----------------| +| 嘻哈歌手 | zh_male_rap | +| 四川女声 | zh_female_sichuan | +| 影视配音 | zh_male_xiaoming | +| 男主播 | zh_male_zhubo | +| 女主播 | zh_female_zhubo | +| 清新女声 | zh_female_qingxin | +| 少儿故事 | zh_female_story | -### 3. 插件编写/编译 +### en -编辑 `src/lib.rs` 实现 `tts` 函数 +| Name | Value | +|------|----------------| +| 美式男声 | en_male_adam | +| 英式男声 | en_male_bob | +| 澳洲女声 | en_female_sarah | -#### 输入参数 +### jp -```rust - text: &str, - lang: &str, - needs: HashMap, // 插件需要的其他配置信息,由info.json定义 -``` - -#### 返回值 - -```rust -// 返回用Value包裹的字节数组 - let result = res.to_vec(); - return Ok(json!(result)); -``` - -#### 测试/编译 - -```bash -cargo test --package plugin --lib -- tests --nocapture # 运行测试用例 -cargo build --release # 编译 -``` - -### 4. 打包 pot 插件 - -1. 在`target/release`目录找到`plugin.dll`(Windows)/`libplugin.dylib`(MacOS)/`libplugin.so`(Linux)文件,统一删除`lib`前缀. - -2. 将`plugin.dll`/`libplugin.dylib`/`libplugin.so`文件和`info.json`以及图标文件压缩为 zip 文件。 - -3. 将文件重命名为`<插件id>.potext`,例如`[plugin].com.pot-app.lingva_tts.potext`,即可得到 pot 需要的插件。 - -## 自动编译打包 - -本仓库配置了 Github Actions,可以实现推送后自动编译打包插件。 - -每次将仓库推送到 GitHub 之后 actions 会自动运行,将打包好的插件上传到 artifact,在 actions 页面可以下载 - -每次提交 Tag 之后,actions 会自动运行,将打包好的插件上传到 release,在 release 页面可以下载打包好的插件 - -> 注意需要在仓库设置中添加一个名为`TOKEN`的 secret,值为一个有权限的 GitHub Token,用于上传 release +| Name | Value | +|------|----------------| +| 日语男声 | jp_male_satoshi | +| 日语女声 | jp_female_mai | diff --git a/README_EN.md b/README_EN.md deleted file mode 100644 index 7e10938..0000000 --- a/README_EN.md +++ /dev/null @@ -1,71 +0,0 @@ -# Pot-App TTS Plugin Template Repository (Take [Lingva](https://github.com/TheDavidDelta/lingva-translate) for example) - -### English | [简体中文](./README.md) - -### This repository is a template repository. You can directly create a plugin repository from this repository when writing plugins - -## Plugin Writing Guide - -### 1. Create a plugin repository - -- Create a new repository using this repository as a template -- Named `pot-app-tts-plugin-`,Eg: `pot-app-tts-plugin-lingva_tts` - -### 2. Plugin information configuration - -Edit the `info.json` file and modify the following fields: - -- `id`: The unique ID of the plugin, which must start with `[plugin]`, for example `[plugin].com.pot-app.lingva_tts` -- `homepage`: The homepage of the plugin, simply fill in your repository address, for example `https://github.com/pot-app/pot-app-tts-plugin-template` -- `display`: The display name of the plugin, for example `Lingva` -- `icon`: The icon of the plugin, for example `lingva.svg` -- `needs`: Dependencies required by the plugin. It is an array where each dependency is an object that includes the following fields: - - `key`: The key of the dependency, corresponding to its name in the configuration file. For example,`requestPath`. - - `display`: The display name of the dependency as shown to users. For example,`Request Path`. - - `language`: Mapping between language codes used in Pot and language codes used when sending requests to plugins. - -### 3. Plugin writing/compiling - -Edit `src/lib.rs` to implement `tts` function - -#### Input parameters - -```rust - text: &str, - lang: &str, - needs: HashMap, // Additional configuration information required by the plugin, defined by info.json -``` - -#### Return value - -```rust -// Return the byte array wrapped by Value - let result = res.to_vec(); - - Ok(json!(result)) -``` - -#### Test/Compile - -```bash -cargo test --package plugin --lib -- tests --nocapture # run the test case -cargo build --release # Compile -``` - -### 4. Package pot Plugin - -1. Find the `plugin.dll` (Windows)/`libplugin.dylib` (MacOS)/`libplugin.so` (Linux) file in the `target/release` directory and delete the prefix `lib`. - -2. Compress the `plugin.dll`/`libplugin.dylib`/`libplugin.so`, with the `info.json` and icon files, into a zip file. - -3. Rename the file as `.potext`, for example `[plugin].com.pot-app.lingva_tts.potext`, to obtain the plugin required by pot. - -## Automatic Compilation and Package - -This repository is configured with Github Actions, which allows for automatic compilation and packaging of plugins after pushing. - -Every time the commit is pushed to GitHub, actions will run automatically and upload the packaged plugin to artifacts. The packaged plugin can be downloaded from the actions page. - -After each tag submission, actions will also run automatically and upload the packaged plugin to releases. The packaged plugin can be downloaded from the release page. - -> Please note that you need to add a secret named `TOKEN` in the repository settings. The value should be a GitHub Token with appropriate permissions, which will be used for uploading releases. diff --git a/info.json b/info.json index 240423f..a199e6e 100644 --- a/info.json +++ b/info.json @@ -1,31 +1,31 @@ { - "id": "[plugin].com.pot-app.lingva_tts", + "id": "[plugin].com.TechDecryptor.volcengine_tts", "plugin_type": "tts", - "icon": "lingva.svg", - "display": "Lingva", - "homepage": "https://github.com/pot-app/pot-app-tts-plugin-template", - "needs": [{ "key": "requestPath", "display": "请求地址" }], + "icon": "volcengine.svg", + "display": "火山 TTS", + "homepage": "https://github.com/TechDecryptor/pot-app-tts-plugin-volcengine", + "needs": [{ "key": "speaker", "display": "Speaker" }], "language": { - "zh_cn": "zh", - "zh_tw": "zh_HANT", - "en": "en", - "ja": "ja", - "ko": "ko", - "fr": "fr", - "es": "es", - "ru": "ru", - "de": "de", - "it": "it", - "tr": "tr", - "pt": "pt", - "pt_br": "pt", - "vi": "vi", - "id": "id", - "th": "th", - "ms": "ms", - "ar": "ar", - "hi": "hi", - "mn_cy": "mn", - "km": "km" + "zh_cn": "", + "zh_tw": "", + "en": "", + "ja": "", + "ko": "", + "fr": "", + "es": "", + "ru": "", + "de": "", + "it": "", + "tr": "", + "pt_pt": "", + "pt_br": "", + "vi": "", + "id": "", + "th": "", + "ms": "", + "ar": "", + "hi": "", + "mn_cy": "", + "km": "" } } diff --git a/lingva.svg b/lingva.svg deleted file mode 100644 index d5a9bf7..0000000 --- a/lingva.svg +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/lib.rs b/src/lib.rs index 66bca2a..4633a6d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,34 +1,54 @@ +use base64::{engine::general_purpose, Engine as _}; use serde_json::{json, Value}; use std::collections::HashMap; use std::error::Error; -use urlencoding::encode; #[no_mangle] pub fn tts( text: &str, - lang: &str, + _lang: &str, needs: HashMap, ) -> Result> { let client = reqwest::blocking::ClientBuilder::new().build()?; - let mut url = match needs.get("requestPath") { - Some(url) => url.to_string(), - None => "lingva.pot-app.com".to_string(), - }; - - if !url.starts_with("http") { - url = format!("https://{}", url); - } - - let plain_text = text.replace("/", "%2F"); - let encode_text = encode(plain_text.as_str()); - let res = client - .get(format!("{url}/api/v1/audio/{lang}/{encode_text}")) + let url = "https://translate.volcengine.com/crx/tts/v1/"; + let speaker = match needs.get("speaker") { + Some(v) => v, + None => "zh_male_xiaoming", + }; + let res:Value = client + .post(url) + .header("authority", "translate.volcengine.com") + .header("origin", "chrome-extension://klgfhbdadaspgppeadghjjemk") + .header("accept", "application/json, text/plain, */*") + .header("sec-fetch-dest", "empty") + .header("sec-fetch-mode", "cors") + .header("sec-fetch-site", "none") + .header("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36") + .json(&json!({ + "text": text, + "speaker":speaker, + })) .send()? - .bytes()?; + .json()?; - let result = res.to_vec(); + fn parse_res(json: Value) -> Option { + let data = json + .as_object()? + .get("audio")? + .as_object()? + .get("data")? + .as_str()? + .to_string(); + Some(data) + } + let base64 = match parse_res(res) { + Some(v) => v, + None => return Err("Parse Response Error".into()), + }; + let data = general_purpose::STANDARD.decode(base64)?; + let result = data.to_vec(); Ok(json!(result)) } @@ -38,7 +58,7 @@ mod tests { #[test] fn try_request() { let mut needs = HashMap::new(); - needs.insert("requestPath".to_string(), "lingva.pot-app.com".to_string()); + needs.insert("speaker".to_string(), "zh_male_rap".to_string()); let result = tts("你好", "zh", needs).unwrap(); println!("{result}"); } diff --git a/volcengine.svg b/volcengine.svg new file mode 100644 index 0000000..a53bd17 --- /dev/null +++ b/volcengine.svg @@ -0,0 +1,100 @@ + + + +