├── .gitignore
├── .vscode
└── extensions.json
├── LICENSE
├── README.md
├── index.html
├── package-lock.json
├── package.json
├── public
├── tauri.svg
└── vite.svg
├── src-tauri
├── 2
├── .gitignore
├── Cargo.lock
├── Cargo.toml
├── build.rs
├── capabilities
│ └── default.json
├── icons
│ ├── 128x128.png
│ ├── 128x128@2x.png
│ ├── 32x32.png
│ ├── Square107x107Logo.png
│ ├── Square142x142Logo.png
│ ├── Square150x150Logo.png
│ ├── Square284x284Logo.png
│ ├── Square30x30Logo.png
│ ├── Square310x310Logo.png
│ ├── Square44x44Logo.png
│ ├── Square71x71Logo.png
│ ├── Square89x89Logo.png
│ ├── StoreLogo.png
│ ├── icon.icns
│ ├── icon.ico
│ └── icon.png
├── src
│ ├── lib.rs
│ ├── main.rs
│ └── utils
│ │ ├── api.rs
│ │ ├── custom_result.rs
│ │ ├── mod.rs
│ │ ├── sub_marker.rs
│ │ └── tts.rs
├── tauri.conf.json
└── test
│ ├── output.srt
│ ├── sub_title_test.rs
│ ├── 复杂文本.json
│ ├── 复杂文本.mp3
│ ├── 复杂文本.srt
│ ├── 复杂文本.txt
│ ├── 复杂文本2.json
│ ├── 复杂文本2.mp3
│ ├── 复杂文本2.srt
│ ├── 复杂文本2.txt
│ ├── 复杂文本3.json
│ ├── 复杂文本3.mp3
│ ├── 复杂文本3.txt
│ ├── 英文文本.json
│ ├── 英文文本.mp3
│ ├── 英文文本.srt
│ └── 英文文本.txt
├── src
├── App.vue
├── assets
│ ├── base.css
│ ├── gitee.png
│ ├── github.svg
│ └── vue.svg
├── auto-imports.d.ts
├── components.d.ts
├── main.js
├── pages
│ ├── SetPage.vue
│ └── TTS.vue
├── router
│ └── index.js
├── store
│ ├── option.js
│ └── voices.js
└── utils
│ ├── function.js
│ ├── mitt.js
│ └── sqlite.js
└── vite.config.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 | build
15 |
16 | # Editor directories and files
17 | .vscode/*
18 | !.vscode/extensions.json
19 | .idea
20 | .DS_Store
21 | *.suo
22 | *.ntvs*
23 | *.njsproj
24 | *.sln
25 | *.sw?
26 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "Vue.volar",
4 | "tauri-apps.tauri-vscode",
5 | "rust-lang.rust-analyzer"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 Manson
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Tauri + Vue 3
2 |
3 | 使用Tauri开发的微软配音工具
4 |
5 | ## 注意事项
6 |
7 | - 第一次使用Tauri发布公开软件,据说Tauri的兼容性不好,有问题请提交。
8 | - 音频使用base64传输,文本过多时会有性能问题
9 |
10 | ## 已完成功能
11 |
12 | - [x] 基本配音功能
13 | - [x] 字幕生成功能
14 | - [x] 配音界面的设置保存
15 | - [x] 设置页面
16 |
17 | ## 后续计划
18 |
19 | - [ ] 多角色配音
20 | - [ ] 长文本切片(可提高性能)
21 | - [ ] 试听朗读(可用于小说阅读)
22 | - [ ] 自定义停顿间隔(暂时无法适应字幕)
23 | - [ ] 多端适配(Mac,Linux,安卓)
24 | - [ ] 解决base64引发的长音频性能问题
25 |
26 | ## 开发
27 |
28 | ### 克隆代码
29 |
30 | ```
31 | git clone https://gitee.com/lieranhuasha/tts-tauri.git
32 | 或
33 | git clone https://github.com/zs1083339604/tts-tauri.git
34 | ```
35 |
36 | ### 安装依赖
37 |
38 | ```
39 | cd tts-tauri
40 | npm install
41 | ```
42 |
43 | ### 运行
44 |
45 | ```
46 | npm run tauri dev
47 | ```
48 |
49 | ### 注意事项
50 |
51 | 使用Tauri开发,需要完成前置条件:[Tauri前置条件](https://tauri.app/zh-cn/start/prerequisites/)
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Tauri + Vue 3 App
8 |
18 |
19 |
20 |
21 |
22 |
23 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tts-tauri",
3 | "private": true,
4 | "version": "0.2.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview",
10 | "tauri": "tauri"
11 | },
12 | "dependencies": {
13 | "@element-plus/icons-vue": "^2.3.1",
14 | "@tauri-apps/api": "^2",
15 | "@tauri-apps/plugin-dialog": "^2.2.1",
16 | "@tauri-apps/plugin-opener": "^2",
17 | "@tauri-apps/plugin-shell": "^2.2.1",
18 | "@tauri-apps/plugin-sql": "^2.2.0",
19 | "element-plus": "^2.9.8",
20 | "mitt": "^3.0.1",
21 | "pinia": "^3.0.2",
22 | "unplugin-auto-import": "^19.1.2",
23 | "unplugin-icons": "^22.1.0",
24 | "unplugin-vue-components": "^28.5.0",
25 | "vite-plugin-inspect": "^11.0.1",
26 | "vue": "^3.5.13",
27 | "vue-router": "^4.5.1"
28 | },
29 | "devDependencies": {
30 | "@tauri-apps/cli": "^2",
31 | "@vitejs/plugin-vue": "^5.2.1",
32 | "vite": "^6.0.3"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/public/tauri.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src-tauri/.gitignore:
--------------------------------------------------------------------------------
1 | # Generated by Cargo
2 | # will have compiled files and executables
3 | /target/
4 |
5 | # Generated by Tauri
6 | # will have schema files for capabilities auto-completion
7 | /gen/schemas
8 |
--------------------------------------------------------------------------------
/src-tauri/2:
--------------------------------------------------------------------------------
1 |
2 | added 1 package in 4s
3 |
4 | 45 packages are looking for funding
5 | run `npm fund` for details
6 |
--------------------------------------------------------------------------------
/src-tauri/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "tts-tauri"
3 | version = "0.1.0"
4 | description = "A Tauri App"
5 | authors = ["you"]
6 | edition = "2021"
7 |
8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
9 |
10 | [lib]
11 | # The `_lib` suffix may seem redundant but it is necessary
12 | # to make the lib name unique and wouldn't conflict with the bin name.
13 | # This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519
14 | name = "tts_tauri_lib"
15 | crate-type = ["staticlib", "cdylib", "rlib"]
16 |
17 | [build-dependencies]
18 | tauri-build = { version = "2", features = [] }
19 |
20 | [dependencies]
21 | tauri = { version = "2", features = [] }
22 | tauri-plugin-opener = "2"
23 | serde = { version = "1", features = ["derive"] }
24 | serde_json = "1"
25 | chrono = "0.4.40"
26 | sha2 = "0.10.8"
27 | uuid = {version = "1.16.0", features = ["v4"] }
28 | url = "2.5.4"
29 | regex = "1.11.1"
30 | hex = "0.4.3"
31 | tokio = {version = "1.44.2", features = ["full"] }
32 | tokio-tungstenite = {version = "0.26.2", features = ["native-tls"] }
33 | futures-util = "0.3.31"
34 | reqwest = "0.12.15"
35 | base64 = "0.22.1"
36 | tauri-plugin-dialog = "2"
37 | tauri-plugin-shell = "2"
38 |
39 | [dependencies.tauri-plugin-sql]
40 | features = ["sqlite"] # or "postgres", or "mysql"
41 | version = "2.0.0"
42 |
43 | [profile.dev]
44 | incremental = true # 以较小的步骤编译您的二进制文件。
45 |
46 | [profile.release]
47 | codegen-units = 1 # 允许 LLVM 执行更好的优化。
48 | lto = true # 启用链接时优化。
49 | opt-level = "s" # 优先考虑小的二进制文件大小。如果您更喜欢速度,请使用 `3`。
50 | panic = "abort" # 通过禁用 panic 处理程序来提高性能。
51 | strip = true # 确保移除调试符号。
52 |
--------------------------------------------------------------------------------
/src-tauri/build.rs:
--------------------------------------------------------------------------------
1 | fn main() {
2 | tauri_build::build()
3 | }
4 |
--------------------------------------------------------------------------------
/src-tauri/capabilities/default.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "../gen/schemas/desktop-schema.json",
3 | "identifier": "default",
4 | "description": "Capability for the main window",
5 | "windows": [
6 | "main"
7 | ],
8 | "permissions": [
9 | "core:default",
10 | "opener:default",
11 | "sql:default",
12 | "sql:allow-execute",
13 | "core:window:allow-close",
14 | "dialog:default",
15 | "shell:default"
16 | ]
17 | }
--------------------------------------------------------------------------------
/src-tauri/icons/128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zs1083339604/tts-tauri/559be104806e6d0cb77e9c34715643aff71cefe5/src-tauri/icons/128x128.png
--------------------------------------------------------------------------------
/src-tauri/icons/128x128@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zs1083339604/tts-tauri/559be104806e6d0cb77e9c34715643aff71cefe5/src-tauri/icons/128x128@2x.png
--------------------------------------------------------------------------------
/src-tauri/icons/32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zs1083339604/tts-tauri/559be104806e6d0cb77e9c34715643aff71cefe5/src-tauri/icons/32x32.png
--------------------------------------------------------------------------------
/src-tauri/icons/Square107x107Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zs1083339604/tts-tauri/559be104806e6d0cb77e9c34715643aff71cefe5/src-tauri/icons/Square107x107Logo.png
--------------------------------------------------------------------------------
/src-tauri/icons/Square142x142Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zs1083339604/tts-tauri/559be104806e6d0cb77e9c34715643aff71cefe5/src-tauri/icons/Square142x142Logo.png
--------------------------------------------------------------------------------
/src-tauri/icons/Square150x150Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zs1083339604/tts-tauri/559be104806e6d0cb77e9c34715643aff71cefe5/src-tauri/icons/Square150x150Logo.png
--------------------------------------------------------------------------------
/src-tauri/icons/Square284x284Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zs1083339604/tts-tauri/559be104806e6d0cb77e9c34715643aff71cefe5/src-tauri/icons/Square284x284Logo.png
--------------------------------------------------------------------------------
/src-tauri/icons/Square30x30Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zs1083339604/tts-tauri/559be104806e6d0cb77e9c34715643aff71cefe5/src-tauri/icons/Square30x30Logo.png
--------------------------------------------------------------------------------
/src-tauri/icons/Square310x310Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zs1083339604/tts-tauri/559be104806e6d0cb77e9c34715643aff71cefe5/src-tauri/icons/Square310x310Logo.png
--------------------------------------------------------------------------------
/src-tauri/icons/Square44x44Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zs1083339604/tts-tauri/559be104806e6d0cb77e9c34715643aff71cefe5/src-tauri/icons/Square44x44Logo.png
--------------------------------------------------------------------------------
/src-tauri/icons/Square71x71Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zs1083339604/tts-tauri/559be104806e6d0cb77e9c34715643aff71cefe5/src-tauri/icons/Square71x71Logo.png
--------------------------------------------------------------------------------
/src-tauri/icons/Square89x89Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zs1083339604/tts-tauri/559be104806e6d0cb77e9c34715643aff71cefe5/src-tauri/icons/Square89x89Logo.png
--------------------------------------------------------------------------------
/src-tauri/icons/StoreLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zs1083339604/tts-tauri/559be104806e6d0cb77e9c34715643aff71cefe5/src-tauri/icons/StoreLogo.png
--------------------------------------------------------------------------------
/src-tauri/icons/icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zs1083339604/tts-tauri/559be104806e6d0cb77e9c34715643aff71cefe5/src-tauri/icons/icon.icns
--------------------------------------------------------------------------------
/src-tauri/icons/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zs1083339604/tts-tauri/559be104806e6d0cb77e9c34715643aff71cefe5/src-tauri/icons/icon.ico
--------------------------------------------------------------------------------
/src-tauri/icons/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zs1083339604/tts-tauri/559be104806e6d0cb77e9c34715643aff71cefe5/src-tauri/icons/icon.png
--------------------------------------------------------------------------------
/src-tauri/src/lib.rs:
--------------------------------------------------------------------------------
1 | // Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
2 | use utils::api::{get_exe_path, get_voices_list, start_tts, get_app_version};
3 | pub mod utils;
4 |
5 | #[tauri::command]
6 | fn greet(name: &str) -> String {
7 | format!("Hello, {}! You've been greeted from Rust!", name)
8 | }
9 |
10 | #[cfg_attr(mobile, tauri::mobile_entry_point)]
11 | pub fn run() {
12 | tauri::Builder::default()
13 | .plugin(tauri_plugin_shell::init())
14 | .plugin(tauri_plugin_dialog::init())
15 | .plugin(tauri_plugin_opener::init())
16 | .plugin(tauri_plugin_sql::Builder::default().build())
17 | .invoke_handler(tauri::generate_handler![
18 | greet,
19 | get_voices_list,
20 | start_tts,
21 | get_exe_path,
22 | get_app_version
23 | ])
24 | .run(tauri::generate_context!())
25 | .expect("error while running tauri application");
26 | }
27 |
--------------------------------------------------------------------------------
/src-tauri/src/main.rs:
--------------------------------------------------------------------------------
1 | // Prevents additional console window on Windows in release, DO NOT REMOVE!!
2 | #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
3 |
4 | fn main() {
5 | tts_tauri_lib::run()
6 | }
7 |
--------------------------------------------------------------------------------
/src-tauri/src/utils/api.rs:
--------------------------------------------------------------------------------
1 | use crate::utils::custom_result::CustomResult;
2 | use crate::utils::sub_marker::generate_srt;
3 | use crate::utils::tts::TTS;
4 | use base64::{engine::general_purpose, Engine as _};
5 | use futures_util::{sink::SinkExt, StreamExt};
6 | use reqwest::get;
7 | use serde::Deserialize;
8 | use serde_json::Value;
9 | use serde_json::{from_str, json};
10 | use std::fs::{self, File};
11 | use std::io::Write;
12 | use std::path::Path;
13 | use std::process::Command;
14 | use tokio_tungstenite::{
15 | connect_async,
16 | tungstenite::{client::IntoClientRequest, Message},
17 | };
18 | use uuid::Uuid;
19 |
20 | #[derive(Deserialize)]
21 | pub struct TTSData {
22 | voice: String,
23 | text: String,
24 | pitch: i32,
25 | rate: i32,
26 | volume: i32,
27 | gender_sub_marker: bool,
28 | sub_marker_type: String,
29 | merge_by_number_number: i32,
30 | root_path: String,
31 | open_folders: bool,
32 | }
33 |
34 | #[tauri::command]
35 | pub async fn get_voices_list() -> Result {
36 | let url = "https://speech.platform.bing.com/consumer/speech/synthesize/readaloud/voices/list?trustedclienttoken=6A5AA1D4EAFF4E9FB37E23D68491D6F4";
37 |
38 | let response = get(url)
39 | .await
40 | .map_err(|e| CustomResult::error(Some(e.to_string()), None))?;
41 |
42 | if response.status().is_success() {
43 | let body = response
44 | .text()
45 | .await
46 | .map_err(|e| CustomResult::error(Some(e.to_string()), None))?;
47 | let json: serde_json::Value =
48 | from_str(body.as_str()).map_err(|e| CustomResult::error(Some(e.to_string()), None))?;
49 | return Ok(CustomResult::success(None, Some(json)));
50 | }
51 |
52 | return Err(CustomResult::error(
53 | Some(response.status().to_string()),
54 | None,
55 | ));
56 | }
57 |
58 | #[tauri::command]
59 | pub async fn start_tts(data: TTSData) -> Result {
60 | let voice = data.voice;
61 | let text = data.text;
62 | let pitch = data.pitch;
63 | let rate = data.rate;
64 | let volume = data.volume;
65 | let sub_marker_switch = data.gender_sub_marker;
66 | let sub_marker_option = data.sub_marker_type;
67 | let merge_number = data.merge_by_number_number;
68 | let mut root_path = data.root_path;
69 | let open_folders = data.open_folders;
70 |
71 | // 检查参数
72 | if voice.is_empty() || text.is_empty() || sub_marker_option.is_empty() {
73 | return Err(CustomResult::error(Some("参数错误".to_string()), None));
74 | }
75 |
76 | // 格式化数据
77 | let pitch_str = if pitch >= 0 {
78 | format!("+{}", pitch)
79 | } else {
80 | format!("{}", pitch)
81 | };
82 |
83 | let rate_str = if rate >= 0 {
84 | format!("+{}", rate)
85 | } else {
86 | format!("{}", rate)
87 | };
88 |
89 | let volumn_str = if volume >= 0 {
90 | format!("+{}", volume)
91 | } else {
92 | format!("{}", volume)
93 | };
94 |
95 | let tts_client = TTS {};
96 | let send_request_id = Uuid::new_v4().to_string().replace('-', "");
97 | let sec_ms_gec_value = tts_client.generate_sec_ms_gec()?.data["hax"].clone();
98 | let sec_ms_gec = sec_ms_gec_value
99 | .as_str()
100 | .ok_or_else(|| CustomResult::error(Some("生成令牌字符串失败".to_string()), None))?;
101 | let audio_output_format = "audio-24khz-48kbitrate-mono-mp3";
102 | let binary_delim = "Path:audio\r\n";
103 |
104 | let url_str = format!(
105 | "wss://speech.platform.bing.com/consumer/speech/synthesize/readaloud/edge/v1?\
106 | TrustedClientToken=6A5AA1D4EAFF4E9FB37E23D68491D6F4&Sec-MS-GEC={}&Sec-MS-GEC-Version=1-130.0.2849.68&ConnectionId={}",
107 | sec_ms_gec, send_request_id
108 | );
109 |
110 | let mut request = url_str
111 | .into_client_request()
112 | .map_err(|e| CustomResult::error(Some(format!("编码URL失败:{}", e.to_string())), None))?;
113 |
114 | // 添加请求头
115 | request
116 | .headers_mut()
117 | .insert("Pragma", "no-cache".parse().unwrap());
118 | request
119 | .headers_mut()
120 | .insert("Cache-Control", "no-cache".parse().unwrap());
121 | request.headers_mut().insert(
122 | "Origin",
123 | "chrome-extension://jdiccldimpdaibmpdkjnbmckianbfold"
124 | .parse()
125 | .unwrap(),
126 | );
127 | request.headers_mut().insert("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0".parse().unwrap());
128 | request
129 | .headers_mut()
130 | .insert("Accept-Encoding", "gzip, deflate, br".parse().unwrap());
131 | request
132 | .headers_mut()
133 | .insert("Accept-Language", "en-US,en;q=0.9".parse().unwrap());
134 |
135 | let (mut socket, _) = connect_async(request)
136 | .await
137 | .map_err(|e| CustomResult::error(Some(format!("连接wss失败:{}", e.to_string())), None))?;
138 |
139 | // 发送音频格式设定
140 | let audio_config = tts_client.convert_to_audio_format_websocket_string(audio_output_format);
141 | socket
142 | .send(Message::Text(audio_config.into()))
143 | .await
144 | .map_err(|e| CustomResult::error(Some(format!("发送音频格式失败:{}", e)), None))?;
145 |
146 | // 发送 SSML 文本
147 | let ssml = tts_client.convert_to_ssml_websocket_string(
148 | &send_request_id,
149 | &voice,
150 | &text,
151 | &pitch_str,
152 | &rate_str,
153 | &volumn_str,
154 | );
155 | socket
156 | .send(Message::Text(ssml.into()))
157 | .await
158 | .map_err(|e| CustomResult::error(Some(format!("发送SSML文本失败:{}", e)), None))?;
159 |
160 | // 接收数据
161 | let mut audio_data: Vec = Vec::new();
162 | let mut messages: Vec = vec![];
163 |
164 | while let Some(msg) = socket.next().await {
165 | let msg =
166 | msg.map_err(|e| CustomResult::error(Some(format!("读取WS输出失败:{}", e)), None))?;
167 |
168 | match msg {
169 | Message::Text(txt) => {
170 | if txt.contains("Path:turn.end") {
171 | break;
172 | } else if txt.contains("Path:audio.metadata") {
173 | // 找到第一个空行之后的第一个非空行,这应该是 JSON 数据的开始
174 | if let Some(start_index) = txt.find("\r\n\r\n") {
175 | let json_start = start_index + 2; // 跳过两个换行符
176 | let json_part = &txt[json_start..];
177 | // 尝试解析 JSON
178 | if let Ok(json) = serde_json::from_str(json_part) {
179 | messages.push(json);
180 | } else {
181 | eprintln!("JSON 解析失败: {}", json_part);
182 | }
183 | }
184 | }
185 | }
186 | Message::Binary(bin) => {
187 | if let Some(index) = bin
188 | .windows(binary_delim.len())
189 | .position(|w| w == binary_delim.as_bytes())
190 | {
191 | audio_data.extend_from_slice(&bin[index + binary_delim.len()..]);
192 | }
193 | }
194 | _ => {}
195 | }
196 | }
197 |
198 | if root_path.is_empty() {
199 | root_path = ".".to_string();
200 | }
201 |
202 | let path_str = format!("{}/{}", root_path, send_request_id);
203 | let folder_path = Path::new(&path_str);
204 | if !folder_path.exists() {
205 | fs::create_dir_all(folder_path)
206 | .map_err(|e| CustomResult::error(Some(format!("创建文件夹失败:{}", e)), None))?;
207 | }
208 |
209 | // 保存音频数据
210 | let output_path = format!("{}/output_{}.mp3", path_str, send_request_id);
211 | let mut file = File::create(&output_path)
212 | .map_err(|e| CustomResult::error(Some(format!("创建音频文件失败:{}", e)), None))?;
213 | file.write_all(&audio_data)
214 | .map_err(|e| CustomResult::error(Some(format!("写入音频文件失败:{}", e)), None))?;
215 |
216 | // 写入JSON数据(仅用于测试)
217 | // let json_path = format!("{}/output_{}.json", path_str, send_request_id);
218 | // let mut json_file = File::create(&json_path)
219 | // .map_err(|e| CustomResult::error(Some(format!("创建JSON文件失败:{}", e)), None))?;
220 | // let json_str = serde_json::to_string(&messages)
221 | // .map_err(|e| CustomResult::error(Some(format!("序列化JSON失败:{}", e)), None))?;
222 | // json_file
223 | // .write_all(json_str.as_bytes())
224 | // .map_err(|e| CustomResult::error(Some(format!("写入JSON文件失败:{}", e)), None))?;
225 |
226 | // 写入文本数据(仅用于测试)
227 | // let text_path = format!("{}/output_{}.txt", path_str, send_request_id);
228 | // let mut text_file = File::create(&text_path)
229 | // .map_err(|e| CustomResult::error(Some(format!("创建文本文件失败:{}", e)), None))?;
230 | // let text = text.replace("\n", "\r\n");
231 | // text_file
232 | // .write_all(text.as_bytes())
233 | // .map_err(|e| CustomResult::error(Some(format!("写入文本文件失败:{}", e)), None))?;
234 |
235 | if sub_marker_switch {
236 | let _ = generate_srt(
237 | &messages,
238 | &format!("{}/output_{}.srt", path_str, send_request_id),
239 | &sub_marker_option,
240 | merge_number,
241 | Some(&text),
242 | );
243 | }
244 |
245 | if open_folders {
246 | // 打开文件夹
247 | let final_path = if cfg!(target_os = "windows") {
248 | path_str.replace("/", "\\")
249 | } else {
250 | path_str
251 | };
252 | Command::new("explorer")
253 | .arg(Path::new(final_path.as_str()))
254 | .status()
255 | .map_err(|e| {
256 | CustomResult::error(
257 | Some(format!(
258 | "打开文件夹失败:{}
请手动前往文件夹查看:{}",
259 | e, final_path
260 | )),
261 | None,
262 | )
263 | })?;
264 | }
265 |
266 | // 编码成base64
267 | let base64_audio = encode_audio_to_base64(&output_path)?;
268 |
269 | Ok(CustomResult::success(
270 | None,
271 | Some(json!({"audio": base64_audio})),
272 | ))
273 | }
274 |
275 | #[tauri::command]
276 | pub async fn get_exe_path() -> Result {
277 | let exe_path = std::env::current_exe()
278 | .map_err(|e| CustomResult::error(Some(format!("当前执行路径获取失败:{}", e)), None))?;
279 |
280 | if let Some(exe_dir) = exe_path.parent() {
281 | return Ok(CustomResult::success(
282 | None,
283 | Some(json!({"path": exe_dir.display().to_string()})),
284 | ));
285 | } else {
286 | return Err(CustomResult::error(
287 | Some(format!("无法获取可执行文件的父目录")),
288 | None,
289 | ));
290 | }
291 | }
292 |
293 | #[tauri::command]
294 | pub async fn get_app_version(app_handle: tauri::AppHandle) -> Result {
295 | let package_info = app_handle.package_info();
296 | let version = package_info.version.to_string();
297 |
298 | Ok(CustomResult::success(
299 | None,
300 | Some(json!({"version": version})),
301 | ))
302 | }
303 |
304 | fn encode_audio_to_base64(file_path: &str) -> Result {
305 | let audio_bytes = std::fs::read(file_path)
306 | .map_err(|e| CustomResult::error(Some(format!("读取音频文件失败:{}", e)), None))?;
307 |
308 | let encoded = general_purpose::STANDARD.encode(audio_bytes);
309 |
310 | Ok(encoded)
311 | }
312 |
--------------------------------------------------------------------------------
/src-tauri/src/utils/custom_result.rs:
--------------------------------------------------------------------------------
1 | use serde_json::{json, Value};
2 |
3 | #[derive(serde::Serialize)]
4 | pub struct CustomResult {
5 | pub code: i32,
6 | pub msg: String,
7 | pub data: Value,
8 | }
9 |
10 | impl CustomResult {
11 | pub fn new(code: i32, msg: String, data: Value) -> Self {
12 | Self { code, msg, data }
13 | }
14 |
15 | pub fn success(msg: Option, data: Option) -> Self {
16 | Self::new(
17 | 200,
18 | msg.unwrap_or("Success".to_string()),
19 | data.unwrap_or(json!(null)),
20 | )
21 | }
22 |
23 | pub fn error(msg: Option, data: Option) -> Self {
24 | Self::new(
25 | 500,
26 | msg.unwrap_or("error".to_string()),
27 | data.unwrap_or(json!(null)),
28 | )
29 | }
30 |
31 | pub fn to_string(&self) -> String {
32 | serde_json::to_string(self).unwrap()
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src-tauri/src/utils/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod api;
2 | pub mod custom_result;
3 | pub mod sub_marker;
4 | pub mod tts;
5 |
--------------------------------------------------------------------------------
/src-tauri/src/utils/sub_marker.rs:
--------------------------------------------------------------------------------
1 | use std::collections::VecDeque;
2 | use std::fs::File;
3 | use std::io::Write;
4 |
5 | use super::custom_result::CustomResult;
6 |
7 | #[derive(Debug, Clone)]
8 | struct Cue {
9 | index: usize,
10 | start: String,
11 | end: String,
12 | content: String,
13 | }
14 |
15 | pub struct SubMaker {
16 | cues: Vec,
17 | }
18 |
19 | impl SubMaker {
20 | pub fn new() -> Self {
21 | SubMaker { cues: Vec::new() }
22 | }
23 |
24 | pub fn feed(&mut self, msg: &serde_json::Value) -> Result {
25 | if msg["Type"] != "WordBoundary" {
26 | return Err(CustomResult::error(
27 | Some("错误的Message类型,仅支持'WordBoundary'".to_string()),
28 | None,
29 | ));
30 | }
31 |
32 | let offset = msg["Data"]["Offset"].as_u64().unwrap();
33 | let duration = msg["Data"]["Duration"].as_u64().unwrap();
34 | let text = msg["Data"]["text"]["Text"].as_str().unwrap().to_string();
35 |
36 | let start = self.microseconds_to_time(offset);
37 | let end = self.microseconds_to_time(offset + duration);
38 |
39 | self.cues.push(Cue {
40 | index: self.cues.len() + 1,
41 | start,
42 | end,
43 | content: text,
44 | });
45 |
46 | Ok(CustomResult::success(None, None))
47 | }
48 |
49 | pub fn merge_by_number(&mut self, words: i32) -> Result {
50 | if words == 0 || self.cues.is_empty() {
51 | return Ok(CustomResult::success(None, None));
52 | }
53 |
54 | let mut new_cues = Vec::new();
55 | let mut current_cue = self.cues[0].clone();
56 |
57 | for cue in self.cues.iter().skip(1) {
58 | let word_count = current_cue.content.split_whitespace().count();
59 |
60 | if word_count < words.try_into().unwrap() {
61 | current_cue.end = cue.end.clone();
62 | current_cue.content = format!("{} {}", current_cue.content, cue.content);
63 | } else {
64 | new_cues.push(current_cue);
65 | current_cue = cue.clone();
66 | }
67 | }
68 |
69 | new_cues.push(current_cue);
70 | self.cues = new_cues;
71 | self.reset_index();
72 |
73 | Ok(CustomResult::success(None, None))
74 | }
75 |
76 | pub fn merge_by_punctuation(&mut self, all_text: &str) -> Result {
77 | if all_text.is_empty() {
78 | return Err(CustomResult::error(
79 | Some("你选择了标点分句,但参考句子是空的".to_string()),
80 | None,
81 | ));
82 | }
83 |
84 | let mut new_cues: Vec = Vec::new();
85 | let mut current_index = 0;
86 | let mut last_match_end: isize = -1;
87 | let mut match_start_index = 0;
88 | let punctuation_re = regex::Regex::new(r#"[。!??,;,()\[\]()【】{}、\.\?!;:<>《》「」『』“”‘’"…\n]+"#).map_err(|e| CustomResult::error(Some(e.to_string()), None))?;
89 |
90 | for i in 0..self.cues.len() {
91 | let cue = &self.cues[i];
92 | let search_text = &cue.content;
93 |
94 | if let Some(position) = all_text[current_index..].find(search_text) {
95 | let position = current_index + position;
96 | if last_match_end == -1 {
97 | last_match_end = position as isize;
98 | }
99 |
100 | let mut next_position = position + search_text.len();
101 | let mut max_while = 0;
102 | let mut chars = all_text[next_position..].chars();
103 |
104 | // 如果是英文,这里有时会变成空格,需要过滤一下
105 | while let Some(next_char) = chars.next() {
106 | // 如果不是空格 或 超过了最大限制则退出
107 | if next_char != ' ' || max_while == 10 {
108 | break;
109 | }
110 | next_position += next_char.len_utf8();
111 | max_while += 1;
112 | }
113 |
114 | // 判断下一个字符是否是标点
115 | let next_char = all_text[next_position..].chars().next().unwrap_or(' ');
116 | if punctuation_re.is_match(&next_char.to_string()) {
117 | let start = self.cues[match_start_index].start.clone();
118 | let end_pos = next_position;
119 | let extracted_text = &all_text[last_match_end as usize..end_pos];
120 | new_cues.push(Cue {
121 | index: cue.index,
122 | start,
123 | end: cue.end.clone(),
124 | content: extracted_text.to_string(),
125 | });
126 | last_match_end = -1;
127 | match_start_index = i + 1;
128 | }
129 |
130 | current_index = position;
131 | }
132 | }
133 |
134 | self.cues = new_cues;
135 | self.reset_index();
136 |
137 | Ok(CustomResult::success(None, None))
138 | }
139 |
140 | pub fn get_srt(&self) -> String {
141 | self.cues
142 | .iter()
143 | .map(|cue| {
144 | format!(
145 | "{}\n{} --> {}\n{}\n",
146 | cue.index,
147 | cue.start,
148 | cue.end,
149 | cue.content.trim()
150 | )
151 | })
152 | .collect::>()
153 | .join("\n")
154 | }
155 |
156 | fn reset_index(&mut self) {
157 | for (i, cue) in self.cues.iter_mut().enumerate() {
158 | cue.index = i + 1;
159 | }
160 | }
161 |
162 | fn microseconds_to_time(&self, microseconds: u64) -> String {
163 | let milliseconds = (microseconds / 10000) as u64;
164 | let hours = milliseconds / 3600000;
165 | let minutes = (milliseconds % 3600000) / 60000;
166 | let seconds = (milliseconds % 60000) / 1000;
167 | let ms = milliseconds % 1000;
168 | format!("{:02}:{:02}:{:02},{:03}", hours, minutes, seconds, ms)
169 | }
170 | }
171 |
172 | // 写入 SRT 文件
173 | pub fn generate_srt(
174 | messages: &[serde_json::Value],
175 | srt_path: &str,
176 | option: &str,
177 | number: i32,
178 | all_text: Option<&str>,
179 | ) -> Result {
180 | let mut maker = SubMaker::new();
181 |
182 | for msg in messages {
183 | if let Some(meta) = msg.get("Metadata").and_then(|v| v.get(0)) {
184 | if meta["Type"] == "WordBoundary" {
185 | let _ = maker.feed(meta)?;
186 | }
187 | }
188 | }
189 |
190 | match option {
191 | "mergeByPunctuation" => {
192 | let _ = maker.merge_by_punctuation(all_text.unwrap_or(""))?;
193 | }
194 | "mergeByNumber" => {
195 | let _ = maker.merge_by_number(number)?;
196 | }
197 | _ => {}
198 | }
199 |
200 | let srt_content = maker.get_srt();
201 | let mut file =
202 | File::create(srt_path).map_err(|e| CustomResult::error(Some(e.to_string()), None))?;
203 | file.write_all(srt_content.as_bytes())
204 | .map_err(|e| CustomResult::error(Some(e.to_string()), None))?;
205 | Ok(CustomResult::success(None, None))
206 | }
207 |
--------------------------------------------------------------------------------
/src-tauri/src/utils/tts.rs:
--------------------------------------------------------------------------------
1 | //! 本文件内代码参考开源项目:https://github.com/rany2/edge-tts/tree/master
2 |
3 | use crate::utils::custom_result::CustomResult;
4 | use chrono::Utc;
5 | use hex;
6 | use serde_json::json;
7 | use sha2::{Digest, Sha256};
8 |
9 | pub struct TTS {}
10 |
11 | impl TTS {
12 | fn num_to_str(&self, num: &str) -> String {
13 | if !num.contains('e') {
14 | return num.to_string();
15 | }
16 | let mut num_str = num
17 | .trim_matches(|c| c == ' ' || c == '"' || c == '=' || c == '\'')
18 | .to_string();
19 | num_str.retain(|c| c.is_digit(10));
20 | let mut result = String::new();
21 | let mut n = num_str.parse::().unwrap_or(0);
22 | while n > 0 {
23 | let v = n % 10;
24 | n /= 10;
25 | result.insert(0, std::char::from_digit(v as u32, 10).unwrap());
26 | }
27 | result
28 | }
29 |
30 | pub fn convert_to_audio_format_websocket_string(&self, output_format: &str) -> String {
31 | format!(
32 | "X-Timestamp:{}\r\nContent-Type:application/json; charset=utf-8\r\nPath:speech.config\r\n\r\n{{\"context\":{{\"synthesis\":{{\"audio\":{{\"metadataoptions\":{{\"sentenceBoundaryEnabled\":\"false\",\"wordBoundaryEnabled\":\"true\"}},\"outputFormat\":\"{}\"}}}}}}}}",
33 | self.date_to_string(),
34 | output_format
35 | )
36 | }
37 |
38 | fn convert_to_ssml_text(
39 | &self,
40 | voice: &str,
41 | text: &str,
42 | pitch: &str,
43 | rate: &str,
44 | volume: &str,
45 | ) -> String {
46 | format!(
47 | "{}",
48 | voice, pitch, rate, volume, text
49 | )
50 | }
51 |
52 | pub fn convert_to_ssml_websocket_string(
53 | &self,
54 | request_id: &str,
55 | voice: &str,
56 | msg: &str,
57 | pitch: &str,
58 | rate: &str,
59 | volume: &str,
60 | ) -> String {
61 | format!(
62 | "X-RequestId:{}\r\nContent-Type:application/ssml+xml\r\nX-Timestamp:{}Z\r\nPath:ssml\r\n\r\n{}",
63 | request_id,
64 | self.date_to_string(),
65 | self.convert_to_ssml_text(voice, msg, pitch, rate, volume)
66 | )
67 | }
68 |
69 | fn date_to_string(&self) -> String {
70 | let now = Utc::now();
71 | now.format("%a %b %d %Y %H:%M:%S GMT+0000 (Coordinated Universal Time)")
72 | .to_string()
73 | }
74 |
75 | fn get_unix_timestamp(&self) -> f64 {
76 | Utc::now().timestamp() as f64
77 | }
78 |
79 | pub fn generate_sec_ms_gec(&self) -> Result {
80 | let mut ticks = self.get_unix_timestamp();
81 | ticks += 11644473600.0;
82 | ticks = (ticks / 300.0).floor() * 300.0;
83 | let ticks_int = (ticks * 1e7) as i64;
84 | let str_to_hash = format!(
85 | "{}{}",
86 | self.num_to_str(&ticks_int.to_string()),
87 | "6A5AA1D4EAFF4E9FB37E23D68491D6F4"
88 | );
89 | let mut hasher = Sha256::new();
90 | hasher.update(&str_to_hash);
91 | let result = hasher.finalize();
92 | let hex_str = hex::encode(result).to_uppercase();
93 |
94 | Ok(CustomResult::success(None, Some(json!({ "hax": hex_str }))))
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src-tauri/tauri.conf.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.tauri.app/config/2",
3 | "productName": "tts-tauri",
4 | "version": "0.2.0",
5 | "identifier": "com.tts-tauri.app",
6 | "build": {
7 | "beforeDevCommand": "npm run dev",
8 | "devUrl": "http://localhost:1420",
9 | "beforeBuildCommand": "npm run build",
10 | "frontendDist": "../dist"
11 | },
12 | "app": {
13 | "windows": [
14 | {
15 | "title": "tts-tauri-吾爱破解论坛首发",
16 | "width": 1280,
17 | "height": 720,
18 | "minWidth": 1024,
19 | "minHeight": 576
20 | }
21 | ],
22 | "security": {
23 | "csp": null
24 | }
25 | },
26 | "bundle": {
27 | "active": true,
28 | "targets": "all",
29 | "icon": [
30 | "icons/32x32.png",
31 | "icons/128x128.png",
32 | "icons/128x128@2x.png",
33 | "icons/icon.icns",
34 | "icons/icon.ico"
35 | ],
36 | "windows": {
37 | "webviewInstallMode": {
38 | "type": "embedBootstrapper"
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src-tauri/test/output.srt:
--------------------------------------------------------------------------------
1 | 1
2 | 00:00:00,100 --> 00:00:02,112
3 | 点开控制面板中的数据库
4 |
5 | 2
6 | 00:00:02,375 --> 00:00:03,575
7 | 创建一个数据库
8 |
9 | 3
10 | 00:00:03,812 --> 00:00:04,587
11 | 输入密码
12 |
13 | 4
14 | 00:00:04,812 --> 00:00:05,650
15 | 选择版本
16 |
17 | 5
18 | 00:00:05,987 --> 00:00:07,512
19 | 这里我选择5.7
20 |
21 | 6
22 | 00:00:07,725 --> 00:00:11,250
23 | 因为我这个项目用的5版本的Mysql
24 |
25 | 7
26 | 00:00:11,512 --> 00:00:13,100
27 | 选择8可能会出错
28 |
29 | 8
30 | 00:00:13,337 --> 00:00:16,937
31 | 创建完成后就可以看到数据库的连接信息了
32 |
33 | 9
34 | 00:00:17,500 --> 00:00:20,350
35 | 点这个可以打开数据库管理系统
36 |
37 | 10
38 | 00:00:20,600 --> 00:00:21,787
39 | 我把表导入一下
40 |
41 | 11
42 | 00:00:22,362 --> 00:00:23,975
43 | 这样就把表创建好了
44 |
45 | 12
46 | 00:00:24,300 --> 00:00:26,637
47 | 把代码里的连接信息更新完后
48 |
49 | 13
50 | 00:00:26,825 --> 00:00:28,975
51 | 就可以上传api的代码了
52 |
53 | 14
54 | 00:00:29,200 --> 00:00:31,725
55 | 忽略规则文件和数据库文件
56 |
57 | 15
58 | 00:00:32,062 --> 00:00:34,100
59 | 现在就可以正常使用网站了
60 |
61 | 16
62 | 00:00:34,662 --> 00:00:36,937
63 | 最后是虚拟主机注意事项
64 |
65 | 17
66 | 00:00:37,500 --> 00:00:37,750
67 | 1
68 |
69 | 18
70 | 00:00:38,087 --> 00:00:40,112
71 | 免费账号出于安全原因
72 |
73 | 19
74 | 00:00:40,362 --> 00:00:42,537
75 | 会禁用下面的php函数
76 |
77 | 20
78 | 00:00:43,100 --> 00:00:43,375
79 | 2
80 |
81 | 21
82 | 00:00:43,700 --> 00:00:46,225
83 | php内存限制为64兆
84 |
85 | 22
86 | 00:00:46,500 --> 00:00:47,962
87 | 付费用户可更改
88 |
89 | 23
90 | 00:00:48,525 --> 00:00:48,887
91 | 3
92 |
93 | 24
94 | 00:00:49,250 --> 00:00:51,175
95 | 在主机的设置中可以看到
96 |
97 | 25
98 | 00:00:51,437 --> 00:00:53,387
99 | 传出连接为Not allowed
100 |
101 | 26
102 | 00:00:53,612 --> 00:00:57,850
103 | 这表示无法使用php请求外部的api接口
104 |
105 | 27
106 | 00:00:58,425 --> 00:00:58,775
107 | 4
108 |
109 | 28
110 | 00:00:59,125 --> 00:01:01,387
111 | 账户有效期虽然显示一年
112 |
113 | 29
114 | 00:01:01,625 --> 00:01:03,300
115 | 但到期后会自动续
116 |
117 | 30
118 | 00:01:03,862 --> 00:01:04,175
119 | 5
120 |
121 | 31
122 | 00:01:04,512 --> 00:01:07,062
123 | 主机支持1个域名和3个子域
124 |
125 | 32
126 | 00:01:07,375 --> 00:01:09,375
127 | 并且他们是相互独立的
128 |
129 | 33
130 | 00:01:09,737 --> 00:01:11,825
131 | 代表总共能创建4个网站
132 |
133 | 34
134 | 00:01:12,400 --> 00:01:14,100
135 | 关于流量和空间问题
136 |
137 | 35
138 | 00:01:14,412 --> 00:01:16,287
139 | 建议图片托管到图床
140 |
141 | 36
142 | 00:01:16,537 --> 00:01:17,987
143 | 文件则使用网盘
144 |
145 | 37
146 | 00:01:18,212 --> 00:01:20,900
147 | 这样1G空间和5G流量的配额
148 |
149 | 38
150 | 00:01:21,162 --> 00:01:23,112
151 | 一个小型网站完全够用
152 |
153 | 39
154 | 00:01:23,687 --> 00:01:26,750
155 | 关于三六五免费主机就介绍到这里
156 |
157 | 40
158 | 00:01:27,137 --> 00:01:29,987
159 | 后面我也会分享更多可白嫖的资源
160 |
161 | 41
162 | 00:01:30,212 --> 00:01:32,225
163 | 比如更快的php托管
164 |
165 | 42
166 | 00:01:32,500 --> 00:01:35,537
167 | 支持Python和Node js的虚拟主机
168 |
169 | 43
170 | 00:01:35,850 --> 00:01:38,075
171 | 支持自选服务器地区的主机
172 |
173 | 44
174 | 00:01:38,312 --> 00:01:41,000
175 | 你们的一键三连就是我更新的动力
176 |
177 | 45
178 | 00:01:41,275 --> 00:01:42,187
179 | 下期再见
180 |
--------------------------------------------------------------------------------
/src-tauri/test/sub_title_test.rs:
--------------------------------------------------------------------------------
1 | // Prevents additional console window on Windows in release, DO NOT REMOVE!!
2 | // #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
3 | use utils::sub_marker::generate_srt;
4 | pub mod utils;
5 |
6 | use std::fs;
7 | use std::io;
8 | use serde_json::{from_str, Value};
9 |
10 | fn main() -> io::Result<()> {
11 | // tts_tauri_lib::run()
12 | let json_path = "test/复杂文本2.json";
13 | let json_content = fs::read_to_string(json_path)?;
14 | let mut messages: Vec = from_str::>(&json_content)?.to_vec();
15 |
16 | let txt_path = "test/复杂文本2.txt";
17 | let txt_content = fs::read_to_string(txt_path)?;
18 |
19 | let result = generate_srt(&messages, "test/output.srt", "mergeByNumber", 5, Some(txt_content.as_str()));
20 |
21 | match result {
22 | Ok(_) => print!("成功"),
23 | Err(_) => print!("失败")
24 | };
25 |
26 | Ok(())
27 | }
28 |
--------------------------------------------------------------------------------
/src-tauri/test/复杂文本.json:
--------------------------------------------------------------------------------
1 | [{"Metadata":[{"Data":{"Duration":2875000,"Offset":1000000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"如果"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1250000,"Offset":3875000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"您"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1250000,"Offset":5125000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"有"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":5625000,"Offset":6375000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"兴趣"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2000000,"Offset":13875000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"请"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":5375000,"Offset":15875000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"阅读"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":6000000,"Offset":26750000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"谢谢"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3875000,"Offset":38375000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"以下"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1250000,"Offset":42375000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"是"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4375000,"Offset":43875000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"详细"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4750000,"Offset":48250000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"内容"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3750000,"Offset":58625000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"饭量"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1875000,"Offset":62375000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"很"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2000000,"Offset":64250000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"好"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1000000,"Offset":66250000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"的"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3375000,"Offset":67375000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"女孩"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3125000,"Offset":71500000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"笑"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2250000,"Offset":80250000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"从"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3750000,"Offset":82500000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"那时"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3250000,"Offset":86250000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"起"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1500000,"Offset":91625000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"她"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1500000,"Offset":93125000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"就"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2500000,"Offset":94625000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"变得"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1750000,"Offset":97375000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"爱"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2000000,"Offset":99125000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"哭"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3000000,"Offset":102000000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"笑"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1875000,"Offset":110625000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"就"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1500000,"Offset":112500000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"在"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1125000,"Offset":114250000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"那"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1125000,"Offset":115375000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"一"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1750000,"Offset":116500000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"年"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":875000,"Offset":118250000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"的"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2000000,"Offset":119125000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"师"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3125000,"Offset":121125000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"走"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1375000,"Offset":126625000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"我"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3875000,"Offset":128000000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"邀请"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1250000,"Offset":131875000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"她"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2500000,"Offset":133375000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"要不"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3375000,"Offset":135875000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"去"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4125000,"Offset":140125000,"text":{"BoundaryType":"WordBoundary","Length":4,"Text":"Idea"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":5000000,"Offset":144375000,"text":{"BoundaryType":"WordBoundary","Length":6,"Text":"Pocket"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4375000,"Offset":149500000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"玩玩"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2250000,"Offset":159625000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"在"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1625000,"Offset":161875000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"去"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1000000,"Offset":163500000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"的"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4625000,"Offset":164500000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"路上"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1500000,"Offset":171875000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"她"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1250000,"Offset":173375000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"跟"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1375000,"Offset":174750000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"我"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3500000,"Offset":176125000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"说"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1125000,"Offset":179875000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"我"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1250000,"Offset":181000000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"要"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2250000,"Offset":182375000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"拍"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3875000,"Offset":184750000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"AV"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2500000,"Offset":188625000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"了"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3875000,"Offset":192125000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"当天"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2125000,"Offset":196000000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"我们"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2750000,"Offset":198250000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"只是"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1500000,"Offset":201000000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"和"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4875000,"Offset":202625000,"text":{"BoundaryType":"WordBoundary","Length":3,"Text":"制作人"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1625000,"Offset":207750000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"喝"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":875000,"Offset":209375000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"了"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3375000,"Offset":210250000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"茶"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3250000,"Offset":216750000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"然后"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1625000,"Offset":220125000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"约"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1375000,"Offset":221750000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"在"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3625000,"Offset":223250000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"2月"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1500000,"Offset":227125000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"再"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":5000000,"Offset":228625000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"面谈"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2375000,"Offset":239250000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"5个"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1875000,"Offset":241625000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"月"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3125000,"Offset":243500000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"后"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4000000,"Offset":249125000,"text":{"BoundaryType":"WordBoundary","Length":4,"Text":"Idea"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":6500000,"Offset":253250000,"text":{"BoundaryType":"WordBoundary","Length":6,"Text":"Pocket"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3500000,"Offset":260750000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"终于"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3625000,"Offset":264250000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"允许"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1250000,"Offset":267875000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"她"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3625000,"Offset":269375000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"再次"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":5000000,"Offset":273125000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"拍摄"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1375000,"Offset":283875000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"我"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3375000,"Offset":285250000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"不想"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3625000,"Offset":288750000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"歧视"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3500000,"Offset":292625000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"任何"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1125000,"Offset":296250000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"一"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1500000,"Offset":297375000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"位"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":5250000,"Offset":299000000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"粉丝"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1250000,"Offset":307500000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"能"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1250000,"Offset":308750000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"被"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2625000,"Offset":310125000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"他们"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4000000,"Offset":313000000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"亲切"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":875000,"Offset":317000000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"地"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2750000,"Offset":318000000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"称为"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4875000,"Offset":321000000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"社长"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1375000,"Offset":328250000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"我"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3125000,"Offset":329625000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"感到"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2000000,"Offset":333000000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"很"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4875000,"Offset":335000000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"高兴"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1500000,"Offset":345500000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"我"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3375000,"Offset":347125000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"住院"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1000000,"Offset":350500000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"的"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1625000,"Offset":351750000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"第"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3250000,"Offset":353375000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"7个"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3000000,"Offset":356625000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"月"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1625000,"Offset":362250000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"她"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4250000,"Offset":364000000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"收到"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2375000,"Offset":368250000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"了"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4250000,"Offset":371625000,"text":{"BoundaryType":"WordBoundary","Length":5,"Text":"FANZA"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3375000,"Offset":376000000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"成人"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1875000,"Offset":379375000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"奖"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":750000,"Offset":381250000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"的"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":5375000,"Offset":382125000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"提名"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1500000,"Offset":393250000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"我"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1625000,"Offset":394750000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"在"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":8250000,"Offset":396625000,"text":{"BoundaryType":"WordBoundary","Length":6,"Text":"1000多个"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2625000,"Offset":405875000,"text":{"BoundaryType":"WordBoundary","Length":4,"Text":"LINE"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4125000,"Offset":408625000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"好友"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2000000,"Offset":412750000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"里"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3125000,"Offset":415000000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"发出"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":750000,"Offset":418125000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"了"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":5000000,"Offset":419000000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"号召"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3250000,"Offset":429750000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"当然"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2750000,"Offset":433000000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"还有"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4375000,"Offset":435875000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"我们"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":5000000,"Offset":441250000,"text":{"BoundaryType":"WordBoundary","Length":6,"Text":"Miyano"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1875000,"Offset":446250000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"家"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":875000,"Offset":448125000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"的"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3375000,"Offset":449250000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"所有"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":5000000,"Offset":452750000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"成员"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1500000,"Offset":463500000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"她"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1500000,"Offset":465000000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"从"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1125000,"Offset":466625000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"一"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2125000,"Offset":467750000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"名"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3250000,"Offset":470125000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"精英"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4875000,"Offset":473500000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"出道"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2125000,"Offset":480500000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"尝"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1375000,"Offset":482625000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"到"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3750000,"Offset":484250000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"失败"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":750000,"Offset":488000000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"的"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":5250000,"Offset":488875000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"痛苦"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3250000,"Offset":497375000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"现在"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2000000,"Offset":500750000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"是"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3875000,"Offset":502750000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"时候"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3375000,"Offset":506875000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"再次"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4250000,"Offset":510375000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"闪耀"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":875000,"Offset":514625000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"了"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2250000,"Offset":515500000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"吧"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3875000,"Offset":523250000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"竞争"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4625000,"Offset":527125000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"对手"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1625000,"Offset":532000000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"从"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3375000,"Offset":533750000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"出道"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3500000,"Offset":537125000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"起"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1625000,"Offset":541625000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"就"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1125000,"Offset":543250000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"是"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":8750000,"Offset":544500000,"text":{"BoundaryType":"WordBoundary","Length":4,"Text":"光芒四射"}},"Type":"WordBoundary"}]}]
--------------------------------------------------------------------------------
/src-tauri/test/复杂文本.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zs1083339604/tts-tauri/559be104806e6d0cb77e9c34715643aff71cefe5/src-tauri/test/复杂文本.mp3
--------------------------------------------------------------------------------
/src-tauri/test/复杂文本.srt:
--------------------------------------------------------------------------------
1 | 1
2 | 00:00:00,100 --> 00:00:01,200
3 | 如果您有兴趣
4 |
5 | 2
6 | 00:00:01,387 --> 00:00:02,125
7 | 请阅读
8 |
9 | 3
10 | 00:00:02,675 --> 00:00:04,225
11 | 谢谢以下
12 |
13 | 4
14 | 00:00:04,237 --> 00:00:55,325
15 | 是详细内容饭量很好的女孩笑从那时起她就变得爱哭笑就在那一年的师走我邀请她要不去IdeaPocket玩玩在去的路上她跟我说我要拍AV了当天我们只是和制作人喝了茶然后约在2月再面谈5个月后IdeaPocket终于允许她再次拍摄我不想歧视任何一位粉丝能被他们亲切地称为社长我感到很高兴我住院的第7个月她收到了FANZA成人奖的提名我在1000多个LINE好友里发出了号召当然还有我们Miyano家的所有成员她从一名精英出道尝到失败的痛苦现在是时候再次闪耀了吧竞争对手从出道起就是光芒四射
16 |
--------------------------------------------------------------------------------
/src-tauri/test/复杂文本.txt:
--------------------------------------------------------------------------------
1 | 如果您有兴趣,请阅读。谢谢!
2 |
3 | (以下是详细内容)
4 |
5 | 饭量很好的女孩(笑)。
6 | 从那时起,她就变得爱哭(笑)。就在那一年的师走,我邀请她“要不去Idea Pocket玩玩?”
7 | 在去的路上,她跟我说“我要拍AV了”......当天我们只是和制作人喝了茶,然后约在2月再面谈。
8 | 5个月后,Idea Pocket终于允许她再次拍摄。
9 | 我不想歧视任何一位粉丝,能被他们亲切地称为“社长”,我感到很高兴。
10 | 我住院的第7个月,她收到了FANZA成人奖的提名。
11 | 我在1000多个LINE好友里发出了号召。
12 | 当然还有我们Miyano家的所有成员。
13 | 她从一名精英出道,尝到失败的痛苦,现在是时候再次闪耀了吧?竞争对手从出道起就是光芒四射。
--------------------------------------------------------------------------------
/src-tauri/test/复杂文本2.json:
--------------------------------------------------------------------------------
1 | [{"Metadata":[{"Data":{"Duration":2500000,"Offset":1000000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"那么"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2250000,"Offset":3750000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"可以"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2875000,"Offset":6125000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"借助"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4875000,"Offset":9125000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"这个"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":7125000,"Offset":15000000,"text":{"BoundaryType":"WordBoundary","Length":10,"Text":"cloudflare"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1125000,"Offset":22125000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"的"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2125000,"Offset":23375000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"D"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2500000,"Offset":25500000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"1"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3250000,"Offset":31625000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"这个"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1500000,"Offset":35000000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"是"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2500000,"Offset":36500000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"可以"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3125000,"Offset":39125000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"直接"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3750000,"Offset":42375000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"添加"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":5500000,"Offset":46375000,"text":{"BoundaryType":"WordBoundary","Length":3,"Text":"数据库"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1875000,"Offset":51875000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"的"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2750000,"Offset":56250000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"也是"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":5125000,"Offset":59125000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"免费"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1750000,"Offset":64250000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"的"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3375000,"Offset":68250000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"额度"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2625000,"Offset":71875000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"个人"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":5125000,"Offset":74625000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"使用"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2750000,"Offset":80750000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"也是"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4125000,"Offset":83625000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"完全"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4125000,"Offset":87875000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"够用"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1875000,"Offset":92000000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"的"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1750000,"Offset":99500000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"这"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2250000,"Offset":101250000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"三"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1625000,"Offset":103500000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"者"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3625000,"Offset":105375000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"结合"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4750000,"Offset":109125000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"起来"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1500000,"Offset":114875000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"就"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2375000,"Offset":116375000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"可以"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1625000,"Offset":118875000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"做"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2250000,"Offset":120500000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"一个"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4125000,"Offset":123000000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"完全"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3500000,"Offset":127250000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"动态"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":875000,"Offset":130750000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"的"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4250000,"Offset":131875000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"前后"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2125000,"Offset":136250000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"端"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3250000,"Offset":138375000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"分离"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":875000,"Offset":141625000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"的"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4500000,"Offset":142625000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"网站"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3375000,"Offset":152875000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"并且"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2500000,"Offset":156250000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"他们"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1750000,"Offset":158750000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"在"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3500000,"Offset":160500000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"国内"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3375000,"Offset":164250000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"访问"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":875000,"Offset":167625000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"的"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":5375000,"Offset":168625000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"速度"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2875000,"Offset":175000000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"也是"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4000000,"Offset":178000000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"非常"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2750000,"Offset":182000000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"快"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1750000,"Offset":184750000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"的"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2875000,"Offset":192125000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"如果"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1375000,"Offset":195000000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"有"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":5250000,"Offset":196375000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"同学"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2500000,"Offset":201875000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"想"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2625000,"Offset":204625000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"继续"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4875000,"Offset":207375000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"了解"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":6625000,"Offset":213375000,"text":{"BoundaryType":"WordBoundary","Length":10,"Text":"cloudflare"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1125000,"Offset":220000000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"的"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1625000,"Offset":221375000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"D"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2125000,"Offset":223000000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"1"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3250000,"Offset":225250000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"以及"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":6500000,"Offset":228750000,"text":{"BoundaryType":"WordBoundary","Length":7,"Text":"Workers"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2750000,"Offset":237500000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"可以"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3250000,"Offset":240250000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"直接"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1625000,"Offset":243500000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"到"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2875000,"Offset":245125000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"这里"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":875000,"Offset":248000000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"的"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":5125000,"Offset":249000000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"网页"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1500000,"Offset":255125000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"来"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3750000,"Offset":256625000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"查看"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3250000,"Offset":260625000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"官方"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4500000,"Offset":264000000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"文档"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2625000,"Offset":272250000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"关于"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1500000,"Offset":275000000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"我"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":5625000,"Offset":276500000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"后面"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4000000,"Offset":282375000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"是否"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1375000,"Offset":286375000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"会"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1375000,"Offset":288000000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"再"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1375000,"Offset":289375000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"做"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":5125000,"Offset":290875000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"教程"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":5500000,"Offset":298000000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"介绍"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":6750000,"Offset":304500000,"text":{"BoundaryType":"WordBoundary","Length":7,"Text":"Workers"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3125000,"Offset":312250000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"以及"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1625000,"Offset":315500000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"D"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1625000,"Offset":317125000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"1"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3750000,"Offset":318875000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"或者"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3500000,"Offset":322625000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"其他"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1625000,"Offset":326375000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"更"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1875000,"Offset":328000000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"快"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":875000,"Offset":329875000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"的"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4000000,"Offset":330875000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"网站"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3625000,"Offset":335125000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"托管"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4500000,"Offset":338750000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"服务"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1875000,"Offset":347000000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"你们"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":875000,"Offset":348875000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"的"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1250000,"Offset":350000000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"一"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1750000,"Offset":351250000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"键"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2500000,"Offset":353125000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"三"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3250000,"Offset":355625000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"连"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1750000,"Offset":360000000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"就"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1125000,"Offset":361750000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"是"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1375000,"Offset":363125000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"我"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3625000,"Offset":364500000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"更新"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":875000,"Offset":368125000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"的"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4125000,"Offset":369125000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"动力"}},"Type":"WordBoundary"}]}]
--------------------------------------------------------------------------------
/src-tauri/test/复杂文本2.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zs1083339604/tts-tauri/559be104806e6d0cb77e9c34715643aff71cefe5/src-tauri/test/复杂文本2.mp3
--------------------------------------------------------------------------------
/src-tauri/test/复杂文本2.srt:
--------------------------------------------------------------------------------
1 | 1
2 | 00:00:01,000 --> 00:00:28,000
3 | 那么可以借助这个cloudflare的D1
4 |
5 | 2
6 | 00:00:31,625 --> 00:00:53,750
7 | 这个是可以直接添加数据库的
8 |
9 | 3
10 | 00:00:56,250 --> 00:01:06,000
11 | 也是免费的
12 |
13 | 4
14 | 00:01:08,250 --> 00:01:33,875
15 | 额度个人使用也是完全够用的
16 |
17 | 5
18 | 00:01:39,500 --> 00:02:27,125
19 | 这三者结合起来就可以做一个完全动态的前后端分离的网站
20 |
21 | 6
22 | 00:02:32,875 --> 00:03:06,500
23 | 并且他们在国内访问的速度也是非常快的
24 |
25 | 7
26 | 00:03:12,125 --> 00:03:55,250
27 | 如果有同学想继续了解cloudflare的D1以及Workers
28 |
29 | 8
30 | 00:03:57,500 --> 00:04:28,500
31 | 可以直接到这里的网页来查看官方文档
32 |
33 | 9
34 | 00:04:32,250 --> 00:04:56,000
35 | 关于我后面是否会再做教程
36 |
37 | 10
38 | 00:04:58,000 --> 00:05:43,250
39 | 介绍Workers以及D1或者其他更快的网站托管服务
40 |
41 | 11
42 | 00:05:47,000 --> 00:06:13,250
43 | 你们的一键三连就是我更新的动力
44 |
--------------------------------------------------------------------------------
/src-tauri/test/复杂文本2.txt:
--------------------------------------------------------------------------------
1 | 那么可以借助这个cloudflare的D1,这个是可以直接添加数据库的,也是免费的,额度个人使用也是完全够用的。这三者结合起来就可以做一个完全动态的前后端分离的网站。并且他们在国内访问的速度也是非常快的。如果有同学想继续了解cloudflare的D1以及Workers,可以直接到这里的网页来查看官方文档,关于我后面是否会再做教程,介绍Workers以及D1或者其他更快的网站托管服务,你们的一键三连就是我更新的动力。
--------------------------------------------------------------------------------
/src-tauri/test/复杂文本3.json:
--------------------------------------------------------------------------------
1 | [{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":1000000,"Duration":2000000,"text":{"Text":"\u70b9","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":3000000,"Duration":2125000,"text":{"Text":"\u5f00","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":5375000,"Duration":7250000,"text":{"Text":"\u63a7\u5236\u9762\u677f","Length":4,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":12625000,"Duration":1500000,"text":{"Text":"\u4e2d","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":14125000,"Duration":750000,"text":{"Text":"\u7684","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":15000000,"Duration":6125000,"text":{"Text":"\u6570\u636e\u5e93","Length":3,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":23750000,"Duration":4000000,"text":{"Text":"\u521b\u5efa","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":27750000,"Duration":1750000,"text":{"Text":"\u4e00\u4e2a","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":29625000,"Duration":6125000,"text":{"Text":"\u6570\u636e\u5e93","Length":3,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":38125000,"Duration":3375000,"text":{"Text":"\u8f93\u5165","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":41500000,"Duration":4375000,"text":{"Text":"\u5bc6\u7801","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":48125000,"Duration":3375000,"text":{"Text":"\u9009\u62e9","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":51625000,"Duration":4875000,"text":{"Text":"\u7248\u672c","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":59875000,"Duration":2875000,"text":{"Text":"\u8fd9\u91cc","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":62875000,"Duration":1375000,"text":{"Text":"\u6211","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":64250000,"Duration":3875000,"text":{"Text":"\u9009\u62e9","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":68375000,"Duration":6750000,"text":{"Text":"5.7","Length":3,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":77250000,"Duration":2875000,"text":{"Text":"\u56e0\u4e3a","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":80125000,"Duration":1125000,"text":{"Text":"\u6211","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":81375000,"Duration":2250000,"text":{"Text":"\u8fd9\u4e2a","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":83625000,"Duration":5625000,"text":{"Text":"\u9879\u76ee","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":89500000,"Duration":1750000,"text":{"Text":"\u7528","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":91250000,"Duration":1000000,"text":{"Text":"\u7684","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":92500000,"Duration":1500000,"text":{"Text":"5","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":94000000,"Duration":3875000,"text":{"Text":"\u7248\u672c","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":97875000,"Duration":2000000,"text":{"Text":"\u7684","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":100125000,"Duration":12375000,"text":{"Text":"Mysql","Length":5,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":115125000,"Duration":3625000,"text":{"Text":"\u9009\u62e9","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":118875000,"Duration":2375000,"text":{"Text":"8","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":121500000,"Duration":2750000,"text":{"Text":"\u53ef\u80fd","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":124250000,"Duration":1375000,"text":{"Text":"\u4f1a","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":125750000,"Duration":5250000,"text":{"Text":"\u51fa\u9519","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":133375000,"Duration":3875000,"text":{"Text":"\u521b\u5efa","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":137375000,"Duration":3750000,"text":{"Text":"\u5b8c\u6210","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":141125000,"Duration":3125000,"text":{"Text":"\u540e","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":145250000,"Duration":1500000,"text":{"Text":"\u5c31","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":146750000,"Duration":2250000,"text":{"Text":"\u53ef\u4ee5","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":149000000,"Duration":3625000,"text":{"Text":"\u770b\u5230","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":152875000,"Duration":5250000,"text":{"Text":"\u6570\u636e\u5e93","Length":3,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":158125000,"Duration":875000,"text":{"Text":"\u7684","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":159250000,"Duration":3250000,"text":{"Text":"\u8fde\u63a5","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":162625000,"Duration":4750000,"text":{"Text":"\u4fe1\u606f","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":167375000,"Duration":2000000,"text":{"Text":"\u4e86","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":175000000,"Duration":2250000,"text":{"Text":"\u70b9","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":177250000,"Duration":5000000,"text":{"Text":"\u8fd9\u4e2a","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":183250000,"Duration":2625000,"text":{"Text":"\u53ef\u4ee5","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":185875000,"Duration":4250000,"text":{"Text":"\u6253\u5f00","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":190375000,"Duration":13125000,"text":{"Text":"\u6570\u636e\u5e93\u7ba1\u7406\u7cfb\u7edf","Length":7,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":206000000,"Duration":1250000,"text":{"Text":"\u6211","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":207250000,"Duration":1375000,"text":{"Text":"\u628a","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":208625000,"Duration":1875000,"text":{"Text":"\u8868","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":210500000,"Duration":3375000,"text":{"Text":"\u5bfc\u5165","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":214000000,"Duration":3875000,"text":{"Text":"\u4e00\u4e0b","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":223625000,"Duration":3500000,"text":{"Text":"\u8fd9\u6837","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":227125000,"Duration":1125000,"text":{"Text":"\u5c31","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":228250000,"Duration":1375000,"text":{"Text":"\u628a","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":229625000,"Duration":1750000,"text":{"Text":"\u8868","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":231625000,"Duration":3250000,"text":{"Text":"\u521b\u5efa","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":235000000,"Duration":2500000,"text":{"Text":"\u597d","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":237500000,"Duration":2250000,"text":{"Text":"\u4e86","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":243000000,"Duration":1500000,"text":{"Text":"\u628a","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":244625000,"Duration":3500000,"text":{"Text":"\u4ee3\u7801","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":248125000,"Duration":1125000,"text":{"Text":"\u91cc","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":249250000,"Duration":875000,"text":{"Text":"\u7684","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":250375000,"Duration":3375000,"text":{"Text":"\u8fde\u63a5","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":253875000,"Duration":3875000,"text":{"Text":"\u4fe1\u606f","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":257750000,"Duration":3375000,"text":{"Text":"\u66f4\u65b0","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":261125000,"Duration":2250000,"text":{"Text":"\u5b8c","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":263375000,"Duration":3000000,"text":{"Text":"\u540e","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":268250000,"Duration":1500000,"text":{"Text":"\u5c31","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":269750000,"Duration":2250000,"text":{"Text":"\u53ef\u4ee5","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":272000000,"Duration":5125000,"text":{"Text":"\u4e0a\u4f20","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":277375000,"Duration":4875000,"text":{"Text":"api","Length":3,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":282250000,"Duration":1000000,"text":{"Text":"\u7684","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":283375000,"Duration":4250000,"text":{"Text":"\u4ee3\u7801","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":287625000,"Duration":2125000,"text":{"Text":"\u4e86","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":292000000,"Duration":3625000,"text":{"Text":"\u5ffd\u7565","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":295875000,"Duration":3500000,"text":{"Text":"\u89c4\u5219","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":299500000,"Duration":5250000,"text":{"Text":"\u6587\u4ef6","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":305750000,"Duration":1500000,"text":{"Text":"\u548c","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":307375000,"Duration":5125000,"text":{"Text":"\u6570\u636e\u5e93","Length":3,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":312625000,"Duration":4625000,"text":{"Text":"\u6587\u4ef6","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":320625000,"Duration":3625000,"text":{"Text":"\u73b0\u5728","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":324250000,"Duration":1250000,"text":{"Text":"\u5c31","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":325500000,"Duration":2625000,"text":{"Text":"\u53ef\u4ee5","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":328125000,"Duration":3750000,"text":{"Text":"\u6b63\u5e38","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":331875000,"Duration":2500000,"text":{"Text":"\u4f7f\u7528","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":334500000,"Duration":4625000,"text":{"Text":"\u7f51\u7ad9","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":339125000,"Duration":1875000,"text":{"Text":"\u4e86","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":346625000,"Duration":5000000,"text":{"Text":"\u6700\u540e","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":351625000,"Duration":1625000,"text":{"Text":"\u662f","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":353375000,"Duration":3375000,"text":{"Text":"\u865a\u62df","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":356750000,"Duration":4500000,"text":{"Text":"\u4e3b\u673a","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":361500000,"Duration":2625000,"text":{"Text":"\u6ce8\u610f","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":364125000,"Duration":5250000,"text":{"Text":"\u4e8b\u9879","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":375000000,"Duration":2500000,"text":{"Text":"1","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":380875000,"Duration":3625000,"text":{"Text":"\u514d\u8d39","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":384500000,"Duration":4625000,"text":{"Text":"\u8d26\u53f7","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":389375000,"Duration":2875000,"text":{"Text":"\u51fa\u4e8e","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":392375000,"Duration":3750000,"text":{"Text":"\u5b89\u5168","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":396250000,"Duration":4875000,"text":{"Text":"\u539f\u56e0","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":403625000,"Duration":1625000,"text":{"Text":"\u4f1a","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":405375000,"Duration":2875000,"text":{"Text":"\u7981\u7528","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":408500000,"Duration":3625000,"text":{"Text":"\u4e0b\u9762","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":412125000,"Duration":1625000,"text":{"Text":"\u7684","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":414000000,"Duration":5625000,"text":{"Text":"php","Length":3,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":419750000,"Duration":5625000,"text":{"Text":"\u51fd\u6570","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":431000000,"Duration":2750000,"text":{"Text":"2","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":437000000,"Duration":7250000,"text":{"Text":"php","Length":3,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":444500000,"Duration":4250000,"text":{"Text":"\u5185\u5b58","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":448750000,"Duration":3375000,"text":{"Text":"\u9650\u5236","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":452125000,"Duration":2000000,"text":{"Text":"\u4e3a","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":454375000,"Duration":7875000,"text":{"Text":"64\u5146","Length":3,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":465000000,"Duration":3250000,"text":{"Text":"\u4ed8\u8d39","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":468375000,"Duration":4500000,"text":{"Text":"\u7528\u6237","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":473125000,"Duration":1750000,"text":{"Text":"\u53ef","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":474875000,"Duration":4750000,"text":{"Text":"\u66f4\u6539","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":485250000,"Duration":3625000,"text":{"Text":"3","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":492500000,"Duration":2000000,"text":{"Text":"\u5728","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":494625000,"Duration":3250000,"text":{"Text":"\u4e3b\u673a","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":497875000,"Duration":750000,"text":{"Text":"\u7684","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":498750000,"Duration":3375000,"text":{"Text":"\u8bbe\u7f6e","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":502125000,"Duration":2000000,"text":{"Text":"\u4e2d","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":504375000,"Duration":2250000,"text":{"Text":"\u53ef\u4ee5","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":506625000,"Duration":5125000,"text":{"Text":"\u770b\u5230","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":514375000,"Duration":3500000,"text":{"Text":"\u4f20\u51fa","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":518000000,"Duration":3875000,"text":{"Text":"\u8fde\u63a5","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":521875000,"Duration":3375000,"text":{"Text":"\u4e3a","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":526250000,"Duration":2875000,"text":{"Text":"Not","Length":3,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":529250000,"Duration":4625000,"text":{"Text":"allowed","Length":7,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":536125000,"Duration":1625000,"text":{"Text":"\u8fd9","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":537750000,"Duration":4500000,"text":{"Text":"\u8868\u793a","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":542500000,"Duration":3625000,"text":{"Text":"\u65e0\u6cd5","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":546125000,"Duration":4375000,"text":{"Text":"\u4f7f\u7528","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":550750000,"Duration":7125000,"text":{"Text":"php","Length":3,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":558875000,"Duration":4000000,"text":{"Text":"\u8bf7\u6c42","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":563000000,"Duration":3375000,"text":{"Text":"\u5916\u90e8","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":566375000,"Duration":1625000,"text":{"Text":"\u7684","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":568250000,"Duration":4875000,"text":{"Text":"api","Length":3,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":573250000,"Duration":5250000,"text":{"Text":"\u63a5\u53e3","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":584250000,"Duration":3500000,"text":{"Text":"4","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":591250000,"Duration":3375000,"text":{"Text":"\u8d26\u6237","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":594750000,"Duration":7250000,"text":{"Text":"\u6709\u6548\u671f","Length":3,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":602250000,"Duration":3000000,"text":{"Text":"\u867d\u7136","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":605375000,"Duration":3375000,"text":{"Text":"\u663e\u793a","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":608875000,"Duration":5000000,"text":{"Text":"\u4e00\u5e74","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":616250000,"Duration":1500000,"text":{"Text":"\u4f46","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":617875000,"Duration":3875000,"text":{"Text":"\u5230\u671f","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":621750000,"Duration":2750000,"text":{"Text":"\u540e","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":624750000,"Duration":1500000,"text":{"Text":"\u4f1a","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":626375000,"Duration":3375000,"text":{"Text":"\u81ea\u52a8","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":629750000,"Duration":3250000,"text":{"Text":"\u7eed","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":638625000,"Duration":3125000,"text":{"Text":"5","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":645125000,"Duration":4000000,"text":{"Text":"\u4e3b\u673a","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":649250000,"Duration":3375000,"text":{"Text":"\u652f\u6301","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":652875000,"Duration":2000000,"text":{"Text":"1\u4e2a","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":655000000,"Duration":5250000,"text":{"Text":"\u57df\u540d","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":661250000,"Duration":1625000,"text":{"Text":"\u548c","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":663000000,"Duration":3250000,"text":{"Text":"3\u4e2a","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":666250000,"Duration":1875000,"text":{"Text":"\u5b50","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":668125000,"Duration":2500000,"text":{"Text":"\u57df","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":673750000,"Duration":5250000,"text":{"Text":"\u5e76\u4e14","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":680125000,"Duration":2250000,"text":{"Text":"\u4ed6\u4eec","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":682500000,"Duration":1125000,"text":{"Text":"\u662f","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":683875000,"Duration":3750000,"text":{"Text":"\u76f8\u4e92","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":687750000,"Duration":4250000,"text":{"Text":"\u72ec\u7acb","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":692000000,"Duration":1750000,"text":{"Text":"\u7684","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":697375000,"Duration":3750000,"text":{"Text":"\u4ee3\u8868","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":701375000,"Duration":3750000,"text":{"Text":"\u603b\u5171","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":705250000,"Duration":1250000,"text":{"Text":"\u80fd","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":706625000,"Duration":3625000,"text":{"Text":"\u521b\u5efa","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":710500000,"Duration":2875000,"text":{"Text":"4\u4e2a","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":713500000,"Duration":4750000,"text":{"Text":"\u7f51\u7ad9","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":724000000,"Duration":3000000,"text":{"Text":"\u5173\u4e8e","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":727125000,"Duration":3625000,"text":{"Text":"\u6d41\u91cf","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":731000000,"Duration":1000000,"text":{"Text":"\u548c","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":732125000,"Duration":3875000,"text":{"Text":"\u7a7a\u95f4","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":736125000,"Duration":4875000,"text":{"Text":"\u95ee\u9898","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":744125000,"Duration":2750000,"text":{"Text":"\u5efa\u8bae","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":747000000,"Duration":5125000,"text":{"Text":"\u56fe\u7247","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":752375000,"Duration":3625000,"text":{"Text":"\u6258\u7ba1","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":756000000,"Duration":1250000,"text":{"Text":"\u5230","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":757375000,"Duration":5500000,"text":{"Text":"\u56fe\u5e8a","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":765375000,"Duration":4625000,"text":{"Text":"\u6587\u4ef6","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":770125000,"Duration":1375000,"text":{"Text":"\u5219","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":771625000,"Duration":2875000,"text":{"Text":"\u4f7f\u7528","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":774625000,"Duration":5250000,"text":{"Text":"\u7f51\u76d8","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":782125000,"Duration":3250000,"text":{"Text":"\u8fd9\u6837","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":785625000,"Duration":1625000,"text":{"Text":"1","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":787250000,"Duration":1500000,"text":{"Text":"G","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":788875000,"Duration":5000000,"text":{"Text":"\u7a7a\u95f4","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":794125000,"Duration":1500000,"text":{"Text":"\u548c","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":795750000,"Duration":1875000,"text":{"Text":"5","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":797625000,"Duration":1750000,"text":{"Text":"G","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":799500000,"Duration":3375000,"text":{"Text":"\u6d41\u91cf","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":802875000,"Duration":625000,"text":{"Text":"\u7684","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":803625000,"Duration":5375000,"text":{"Text":"\u914d\u989d","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":811625000,"Duration":2125000,"text":{"Text":"\u4e00\u4e2a","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":813875000,"Duration":3625000,"text":{"Text":"\u5c0f\u578b","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":817625000,"Duration":4625000,"text":{"Text":"\u7f51\u7ad9","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":822500000,"Duration":4125000,"text":{"Text":"\u5b8c\u5168","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":826750000,"Duration":4375000,"text":{"Text":"\u591f\u7528","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":836875000,"Duration":4000000,"text":{"Text":"\u5173\u4e8e","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":841125000,"Duration":3750000,"text":{"Text":"\u4e09\u516d","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":844875000,"Duration":1500000,"text":{"Text":"\u4e94","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":846625000,"Duration":3750000,"text":{"Text":"\u514d\u8d39","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":850500000,"Duration":5125000,"text":{"Text":"\u4e3b\u673a","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":856625000,"Duration":1500000,"text":{"Text":"\u5c31","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":858250000,"Duration":3250000,"text":{"Text":"\u4ecb\u7ecd","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":861500000,"Duration":1500000,"text":{"Text":"\u5230","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":863000000,"Duration":4500000,"text":{"Text":"\u8fd9\u91cc","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":871375000,"Duration":4750000,"text":{"Text":"\u540e\u9762","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":876125000,"Duration":1375000,"text":{"Text":"\u6211","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":877500000,"Duration":1250000,"text":{"Text":"\u4e5f","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":878750000,"Duration":1500000,"text":{"Text":"\u4f1a","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":880375000,"Duration":4125000,"text":{"Text":"\u5206\u4eab","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":884750000,"Duration":3375000,"text":{"Text":"\u66f4\u591a","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":888375000,"Duration":1750000,"text":{"Text":"\u53ef","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":890125000,"Duration":3875000,"text":{"Text":"\u767d\u5ad6","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":894000000,"Duration":875000,"text":{"Text":"\u7684","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":895000000,"Duration":4875000,"text":{"Text":"\u8d44\u6e90","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":902125000,"Duration":3500000,"text":{"Text":"\u6bd4\u5982","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":905875000,"Duration":1625000,"text":{"Text":"\u66f4","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":907500000,"Duration":2250000,"text":{"Text":"\u5feb","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":909750000,"Duration":1500000,"text":{"Text":"\u7684","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":911500000,"Duration":5500000,"text":{"Text":"php","Length":3,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":917125000,"Duration":5125000,"text":{"Text":"\u6258\u7ba1","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":925000000,"Duration":4500000,"text":{"Text":"\u652f\u6301","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":929750000,"Duration":5375000,"text":{"Text":"Python","Length":6,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":936125000,"Duration":2000000,"text":{"Text":"\u548c","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":938250000,"Duration":2500000,"text":{"Text":"Node","Length":4,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":940875000,"Duration":5125000,"text":{"Text":"js","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":946000000,"Duration":1000000,"text":{"Text":"\u7684","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":947250000,"Duration":3125000,"text":{"Text":"\u865a\u62df","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":950375000,"Duration":5000000,"text":{"Text":"\u4e3b\u673a","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":958500000,"Duration":4375000,"text":{"Text":"\u652f\u6301","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":963125000,"Duration":3625000,"text":{"Text":"\u81ea\u9009","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":966875000,"Duration":4500000,"text":{"Text":"\u670d\u52a1\u5668","Length":3,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":971500000,"Duration":3000000,"text":{"Text":"\u5730\u533a","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":974500000,"Duration":1000000,"text":{"Text":"\u7684","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":975625000,"Duration":5125000,"text":{"Text":"\u4e3b\u673a","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":983125000,"Duration":2250000,"text":{"Text":"\u4f60\u4eec","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":985375000,"Duration":875000,"text":{"Text":"\u7684","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":986500000,"Duration":1250000,"text":{"Text":"\u4e00","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":987750000,"Duration":1750000,"text":{"Text":"\u952e","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":989625000,"Duration":2625000,"text":{"Text":"\u4e09","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":992250000,"Duration":3500000,"text":{"Text":"\u8fde","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":996750000,"Duration":1625000,"text":{"Text":"\u5c31","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":998375000,"Duration":1250000,"text":{"Text":"\u662f","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":999625000,"Duration":1375000,"text":{"Text":"\u6211","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":1001000000,"Duration":3500000,"text":{"Text":"\u66f4\u65b0","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":1004500000,"Duration":1000000,"text":{"Text":"\u7684","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":1005625000,"Duration":4375000,"text":{"Text":"\u52a8\u529b","Length":2,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":1012750000,"Duration":2250000,"text":{"Text":"\u4e0b","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":1015000000,"Duration":1750000,"text":{"Text":"\u671f","Length":1,"BoundaryType":"WordBoundary"}}}]},{"Metadata":[{"Type":"WordBoundary","Data":{"Offset":1016875000,"Duration":5000000,"text":{"Text":"\u518d\u89c1","Length":2,"BoundaryType":"WordBoundary"}}}]}]
--------------------------------------------------------------------------------
/src-tauri/test/复杂文本3.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zs1083339604/tts-tauri/559be104806e6d0cb77e9c34715643aff71cefe5/src-tauri/test/复杂文本3.mp3
--------------------------------------------------------------------------------
/src-tauri/test/复杂文本3.txt:
--------------------------------------------------------------------------------
1 | 点开控制面板中的数据库,创建一个数据库,输入密码,选择版本,这里我选择5.7,因为我这个项目用的5版本的Mysql,选择8可能会出错,创建完成后就可以看到数据库的连接信息了。点这个可以打开数据库管理系统,我把表导入一下。这样就把表创建好了,把代码里的连接信息更新完后,就可以上传api的代码了,忽略规则文件和数据库文件,现在就可以正常使用网站了。
2 | 最后是虚拟主机注意事项。
3 | 1,免费账号出于安全原因,会禁用下面的php函数。
4 | 2,php内存限制为64兆,付费用户可更改。
5 | 3,在主机的设置中可以看到,传出连接为Not allowed,这表示无法使用php请求外部的api接口。
6 | 4,账户有效期虽然显示一年,但到期后会自动续。
7 | 5,主机支持1个域名和3个子域,并且他们是相互独立的,代表总共能创建4个网站。
8 | 关于流量和空间问题,建议图片托管到图床,文件则使用网盘,这样1G空间和5G流量的配额,一个小型网站完全够用。
9 | 关于三六五免费主机就介绍到这里,后面我也会分享更多可白嫖的资源,比如更快的php托管,支持Python和Node js的虚拟主机,支持自选服务器地区的主机,你们的一键三连就是我更新的动力,下期再见。
--------------------------------------------------------------------------------
/src-tauri/test/英文文本.json:
--------------------------------------------------------------------------------
1 | [{"Metadata":[{"Data":{"Duration":3000000,"Offset":1000000,"text":{"BoundaryType":"WordBoundary","Length":3,"Text":"Got"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2875000,"Offset":4125000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"it"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2125000,"Offset":10625000,"text":{"BoundaryType":"WordBoundary","Length":3,"Text":"You"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1250000,"Offset":12875000,"text":{"BoundaryType":"WordBoundary","Length":4,"Text":"want"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":750000,"Offset":14250000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"to"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4000000,"Offset":15125000,"text":{"BoundaryType":"WordBoundary","Length":7,"Text":"iterate"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1500000,"Offset":19250000,"text":{"BoundaryType":"WordBoundary","Length":7,"Text":"through"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":750000,"Offset":20875000,"text":{"BoundaryType":"WordBoundary","Length":1,"Text":"a"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":5500000,"Offset":21750000,"text":{"BoundaryType":"WordBoundary","Length":3,"Text":"PHP"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4750000,"Offset":27375000,"text":{"BoundaryType":"WordBoundary","Length":5,"Text":"array"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":7750000,"Offset":33875000,"text":{"BoundaryType":"WordBoundary","Length":8,"Text":"identify"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1625000,"Offset":41875000,"text":{"BoundaryType":"WordBoundary","Length":3,"Text":"and"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4750000,"Offset":43625000,"text":{"BoundaryType":"WordBoundary","Length":6,"Text":"remove"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4375000,"Offset":49000000,"text":{"BoundaryType":"WordBoundary","Length":8,"Text":"elements"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1500000,"Offset":53625000,"text":{"BoundaryType":"WordBoundary","Length":5,"Text":"where"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1000000,"Offset":55250000,"text":{"BoundaryType":"WordBoundary","Length":3,"Text":"the"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":5500000,"Offset":56375000,"text":{"BoundaryType":"WordBoundary","Length":5,"Text":"value"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1500000,"Offset":62125000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"is"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1500000,"Offset":63750000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"an"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":3125000,"Offset":66125000,"text":{"BoundaryType":"WordBoundary","Length":5,"Text":"empty"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4750000,"Offset":69375000,"text":{"BoundaryType":"WordBoundary","Length":6,"Text":"string"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4625000,"Offset":77125000,"text":{"BoundaryType":"WordBoundary","Length":9,"Text":"including"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":4750000,"Offset":81875000,"text":{"BoundaryType":"WordBoundary","Length":7,"Text":"strings"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":5375000,"Offset":86750000,"text":{"BoundaryType":"WordBoundary","Length":8,"Text":"composed"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":750000,"Offset":92250000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"of"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":5125000,"Offset":93125000,"text":{"BoundaryType":"WordBoundary","Length":8,"Text":"multiple"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":6625000,"Offset":98375000,"text":{"BoundaryType":"WordBoundary","Length":6,"Text":"spaces"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":1500000,"Offset":105125000,"text":{"BoundaryType":"WordBoundary","Length":2,"Text":"or"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":7000000,"Offset":106750000,"text":{"BoundaryType":"WordBoundary","Length":8,"Text":"newlines"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2000000,"Offset":117500000,"text":{"BoundaryType":"WordBoundary","Length":3,"Text":"and"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":2375000,"Offset":119625000,"text":{"BoundaryType":"WordBoundary","Length":4,"Text":"then"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":6000000,"Offset":122125000,"text":{"BoundaryType":"WordBoundary","Length":8,"Text":"re-index"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":875000,"Offset":128250000,"text":{"BoundaryType":"WordBoundary","Length":3,"Text":"the"}},"Type":"WordBoundary"}]},{"Metadata":[{"Data":{"Duration":5000000,"Offset":129250000,"text":{"BoundaryType":"WordBoundary","Length":5,"Text":"array"}},"Type":"WordBoundary"}]}]
--------------------------------------------------------------------------------
/src-tauri/test/英文文本.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zs1083339604/tts-tauri/559be104806e6d0cb77e9c34715643aff71cefe5/src-tauri/test/英文文本.mp3
--------------------------------------------------------------------------------
/src-tauri/test/英文文本.srt:
--------------------------------------------------------------------------------
1 | 1
2 | 00:00:00,100 --> 00:00:00,700
3 | Got it
4 |
5 | 2
6 | 00:00:01,062 --> 00:00:03,212
7 | You want to iterate through a PHP array
8 |
9 | 3
10 | 00:00:03,387 --> 00:00:07,412
11 | identify and remove elements where the value is an empty string
12 |
13 | 4
14 | 00:00:07,712 --> 00:00:11,375
15 | including strings composed of multiple spaces or newlines
16 |
17 | 5
18 | 00:00:11,750 --> 00:00:12,812
19 | and thenre-index
20 |
21 | 6
22 | 00:00:12,825 --> 00:00:13,425
23 | the array
24 |
--------------------------------------------------------------------------------
/src-tauri/test/英文文本.txt:
--------------------------------------------------------------------------------
1 | Got it! You want to iterate through a PHP array, identify and remove elements where the value is an empty string (including strings composed of multiple spaces or newlines), and then re-index the array.
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
87 |
88 |
89 |
90 |
104 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/src/assets/base.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --ev-c-white: #ffffff;
3 | --ev-c-white-soft: #f8f8f8;
4 | --ev-c-white-mute: #f2f2f2;
5 |
6 | --ev-c-black: #1b1b1f;
7 | --ev-c-black-soft: #222222;
8 | --ev-c-black-mute: #282828;
9 |
10 | --ev-c-gray-1: #515c67;
11 | --ev-c-gray-2: #414853;
12 | --ev-c-gray-3: #32363f;
13 |
14 | --ev-c-text-1: rgba(255, 255, 245, 0.86);
15 | --ev-c-text-2: rgba(235, 235, 245, 0.6);
16 | --ev-c-text-3: rgba(235, 235, 245, 0.38);
17 |
18 | --ev-button-alt-border: transparent;
19 | --ev-button-alt-text: var(--ev-c-text-1);
20 | --ev-button-alt-bg: var(--ev-c-gray-3);
21 | --ev-button-alt-hover-border: transparent;
22 | --ev-button-alt-hover-text: var(--ev-c-text-1);
23 | --ev-button-alt-hover-bg: var(--ev-c-gray-2);
24 | }
25 |
26 | :root {
27 | --color-background: var(--ev-c-black);
28 | --color-background-soft: var(--ev-c-black-soft);
29 | --color-background-mute: var(--ev-c-black-mute);
30 |
31 | --color-text: var(--ev-c-text-1);
32 | }
33 |
34 | *,
35 | *::before,
36 | *::after {
37 | box-sizing: border-box;
38 | margin: 0;
39 | font-weight: normal;
40 | }
41 |
42 | ul {
43 | list-style: none;
44 | }
45 |
46 | body {
47 | height: 100%;;
48 | line-height: 1.6;
49 | font-family:
50 | Inter,
51 | -apple-system,
52 | BlinkMacSystemFont,
53 | 'Segoe UI',
54 | Roboto,
55 | Oxygen,
56 | Ubuntu,
57 | Cantarell,
58 | 'Fira Sans',
59 | 'Droid Sans',
60 | 'Helvetica Neue',
61 | sans-serif;
62 | text-rendering: optimizeLegibility;
63 | -webkit-font-smoothing: antialiased;
64 | -moz-osx-font-smoothing: grayscale;
65 | }
66 |
67 | html{
68 | height: 100%;
69 | }
70 |
71 | #app{
72 | height: 100%;
73 | }
--------------------------------------------------------------------------------
/src/assets/gitee.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zs1083339604/tts-tauri/559be104806e6d0cb77e9c34715643aff71cefe5/src/assets/gitee.png
--------------------------------------------------------------------------------
/src/assets/github.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/vue.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/auto-imports.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* prettier-ignore */
3 | // @ts-nocheck
4 | // noinspection JSUnusedGlobalSymbols
5 | // Generated by unplugin-auto-import
6 | // biome-ignore lint: disable
7 | export {}
8 | declare global {
9 | const EffectScope: typeof import('vue')['EffectScope']
10 | const computed: typeof import('vue')['computed']
11 | const createApp: typeof import('vue')['createApp']
12 | const customRef: typeof import('vue')['customRef']
13 | const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
14 | const defineComponent: typeof import('vue')['defineComponent']
15 | const effectScope: typeof import('vue')['effectScope']
16 | const getCurrentInstance: typeof import('vue')['getCurrentInstance']
17 | const getCurrentScope: typeof import('vue')['getCurrentScope']
18 | const h: typeof import('vue')['h']
19 | const inject: typeof import('vue')['inject']
20 | const isProxy: typeof import('vue')['isProxy']
21 | const isReactive: typeof import('vue')['isReactive']
22 | const isReadonly: typeof import('vue')['isReadonly']
23 | const isRef: typeof import('vue')['isRef']
24 | const markRaw: typeof import('vue')['markRaw']
25 | const nextTick: typeof import('vue')['nextTick']
26 | const onActivated: typeof import('vue')['onActivated']
27 | const onBeforeMount: typeof import('vue')['onBeforeMount']
28 | const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
29 | const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
30 | const onDeactivated: typeof import('vue')['onDeactivated']
31 | const onErrorCaptured: typeof import('vue')['onErrorCaptured']
32 | const onMounted: typeof import('vue')['onMounted']
33 | const onRenderTracked: typeof import('vue')['onRenderTracked']
34 | const onRenderTriggered: typeof import('vue')['onRenderTriggered']
35 | const onScopeDispose: typeof import('vue')['onScopeDispose']
36 | const onServerPrefetch: typeof import('vue')['onServerPrefetch']
37 | const onUnmounted: typeof import('vue')['onUnmounted']
38 | const onUpdated: typeof import('vue')['onUpdated']
39 | const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
40 | const provide: typeof import('vue')['provide']
41 | const reactive: typeof import('vue')['reactive']
42 | const readonly: typeof import('vue')['readonly']
43 | const ref: typeof import('vue')['ref']
44 | const resolveComponent: typeof import('vue')['resolveComponent']
45 | const shallowReactive: typeof import('vue')['shallowReactive']
46 | const shallowReadonly: typeof import('vue')['shallowReadonly']
47 | const shallowRef: typeof import('vue')['shallowRef']
48 | const toRaw: typeof import('vue')['toRaw']
49 | const toRef: typeof import('vue')['toRef']
50 | const toRefs: typeof import('vue')['toRefs']
51 | const toValue: typeof import('vue')['toValue']
52 | const triggerRef: typeof import('vue')['triggerRef']
53 | const unref: typeof import('vue')['unref']
54 | const useAttrs: typeof import('vue')['useAttrs']
55 | const useCssModule: typeof import('vue')['useCssModule']
56 | const useCssVars: typeof import('vue')['useCssVars']
57 | const useId: typeof import('vue')['useId']
58 | const useModel: typeof import('vue')['useModel']
59 | const useSlots: typeof import('vue')['useSlots']
60 | const useTemplateRef: typeof import('vue')['useTemplateRef']
61 | const watch: typeof import('vue')['watch']
62 | const watchEffect: typeof import('vue')['watchEffect']
63 | const watchPostEffect: typeof import('vue')['watchPostEffect']
64 | const watchSyncEffect: typeof import('vue')['watchSyncEffect']
65 | }
66 | // for type re-export
67 | declare global {
68 | // @ts-ignore
69 | export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
70 | import('vue')
71 | }
72 |
--------------------------------------------------------------------------------
/src/components.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | // @ts-nocheck
3 | // Generated by unplugin-vue-components
4 | // Read more: https://github.com/vuejs/core/pull/3399
5 | // biome-ignore lint: disable
6 | export {}
7 |
8 | /* prettier-ignore */
9 | declare module 'vue' {
10 | export interface GlobalComponents {
11 | ElButton: typeof import('element-plus/es')['ElButton']
12 | ElForm: typeof import('element-plus/es')['ElForm']
13 | ElFormItem: typeof import('element-plus/es')['ElFormItem']
14 | ElIcon: typeof import('element-plus/es')['ElIcon']
15 | ElInput: typeof import('element-plus/es')['ElInput']
16 | ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
17 | ElMenu: typeof import('element-plus/es')['ElMenu']
18 | ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
19 | ElOption: typeof import('element-plus/es')['ElOption']
20 | ElRadio: typeof import('element-plus/es')['ElRadio']
21 | ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
22 | ElSelect: typeof import('element-plus/es')['ElSelect']
23 | ElSlider: typeof import('element-plus/es')['ElSlider']
24 | ElSwitch: typeof import('element-plus/es')['ElSwitch']
25 | RouterLink: typeof import('vue-router')['RouterLink']
26 | RouterView: typeof import('vue-router')['RouterView']
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import { createApp } from "vue";
2 | import App from "./App.vue";
3 | import ElementPlus from 'element-plus'
4 | import 'element-plus/dist/index.css'
5 | import { createPinia } from 'pinia'
6 | import router from './router'
7 |
8 | const pinia = createPinia();
9 | const app = createApp(App);
10 | app.use(router);
11 | app.use(ElementPlus);
12 | app.use(pinia);
13 | app.mount('#app');
--------------------------------------------------------------------------------
/src/pages/SetPage.vue:
--------------------------------------------------------------------------------
1 |
45 |
46 |
47 |
48 |
49 |
50 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
72 |
73 |
74 |
75 |
76 | 0.2.0
77 | 2025-05-09 更新
78 |
79 |
80 |
81 | 保存
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/src/pages/TTS.vue:
--------------------------------------------------------------------------------
1 |
238 |
239 |
240 |
321 |
322 |
323 |
324 |
367 |
368 |
--------------------------------------------------------------------------------
/src/router/index.js:
--------------------------------------------------------------------------------
1 | import {createRouter, createWebHistory} from 'vue-router'
2 |
3 | import TTS from '../pages/TTS.vue'
4 | import SetPage from '../pages/SetPage.vue'
5 |
6 | const routes = [
7 | { path: '/', redirect: '/tts'},
8 | { path: '/tts', component: TTS },
9 | { path: '/set', component: SetPage },
10 | ]
11 |
12 | const router = createRouter({
13 | history: createWebHistory(),
14 | routes,
15 | })
16 |
17 | export default router;
--------------------------------------------------------------------------------
/src/store/option.js:
--------------------------------------------------------------------------------
1 | import { defineStore } from "pinia";
2 | import { invoke } from "@tauri-apps/api/core";
3 | import { select, update } from "../utils/sqlite";
4 | import mitter from "../utils/mitt"
5 |
6 | export const useOptionStore = defineStore("option", {
7 | actions: {
8 | getExePath(){
9 | return new Promise(async (resolve, reject) => {
10 | try {
11 | const result = await invoke("get_exe_path");
12 | if(result.code == 200){
13 | this.app_exe_path = result.data.path.replaceAll("\\", "/");
14 | if(this.app_exe_path.endsWith("/")){
15 | this.app_exe_path = this.app_exe_path.slice(0, -1);
16 | }
17 |
18 | resolve();
19 | }else{
20 | reject(result.msg);
21 | }
22 | } catch (error) {
23 | reject(error)
24 | }
25 | })
26 | },
27 | getOption(){
28 | return new Promise((resolve, reject) => {
29 | select("option", ["softOption", "ttsOption"], "id = ?", [1]).then((result) => {
30 | if(result.rows[0].ttsOption == ""){
31 | // 使用默认值
32 | this.ttsOption = {
33 | language: "中文(大陆)",
34 | voice: "Microsoft Server Speech Text to Speech Voice (zh-CN, XiaoxiaoNeural)",
35 | pitch: 0,
36 | rate: 0,
37 | volume: 0,
38 | gender_sub_marker: true,
39 | sub_marker_type: "mergeByPunctuation",
40 | merge_by_number_number: 1
41 | }
42 | }else{
43 | this.ttsOption = JSON.parse(result.rows[0].ttsOption);
44 | }
45 |
46 | if(result.rows[0].softOption == ""){
47 | // 使用默认值
48 | this.softOption = {
49 | savePath: this.app_exe_path + "/output",
50 | openFolders: true,
51 | saveTTSOptions: true
52 | }
53 | }else{
54 | this.softOption = JSON.parse(result.rows[0].softOption);
55 | }
56 | resolve();
57 | }).catch((error)=>{
58 | reject(error);
59 | })
60 | })
61 | },
62 | updataTTSOption(data){
63 | return new Promise((resolve, reject) => {
64 | const obj = {...JSON.parse(JSON.stringify(data)), text: ""};
65 | update("option", {ttsOption: JSON.stringify(obj)}, "id = ?", [1]).then((result) => {
66 | // 深拷贝对象,上次写代码直接用toRaw就出Bug了
67 | this.ttsOption = obj;
68 | resolve();
69 | }).catch((error)=>{
70 | reject(error);
71 | })
72 | });
73 | },
74 | updataSoftOption(data){
75 | return new Promise((resolve, reject) => {
76 | const newObjString = JSON.stringify(data);
77 |
78 | update("option", {softOption: newObjString}, "id = ?", [1]).then((result) => {
79 | this.softOption = JSON.parse(newObjString);
80 | resolve();
81 | }).catch((error)=>{
82 | reject(error);
83 | })
84 | });
85 | }
86 | },
87 | state() {
88 | return{
89 | app_exe_path: "",
90 | softOption: null,
91 | ttsOption: null
92 | }
93 | },
94 | })
95 |
--------------------------------------------------------------------------------
/src/store/voices.js:
--------------------------------------------------------------------------------
1 | import { defineStore } from "pinia";
2 | import { invoke } from "@tauri-apps/api/core";
3 | import { select, update } from "../utils/sqlite";
4 | import mitter from "../utils/mitt"
5 |
6 | export const useVoicesStore = defineStore("voices", {
7 | actions: {
8 | getVoicesList(){
9 | return new Promise((resolve, reject) => {
10 | select("option", ["voices"], "id = ?", [1]).then(async (result) => {
11 | if(result.rows[0]["voices"] == ""){
12 | try {
13 | // 从网络更新
14 | const result = await this.getVoicesListRemove();
15 | if(result.code == 200){
16 | // 更新数据
17 | await update("option", {voices: result.data.voices}, "id = ?", [1]);
18 | resolve();
19 | }else{
20 | reject(result.msg);
21 | }
22 |
23 | } catch (error) {
24 | reject(error);
25 | }
26 | }else{
27 | // 已经有数据了
28 | this.voices = JSON.parse(result.rows[0]["voices"]);
29 | resolve();
30 | }
31 | }).catch((error) => {
32 | reject(error);
33 | })
34 | })
35 | },
36 |
37 | async getVoicesListRemove() {
38 | mitter.emit("updataVoices");
39 | try {
40 | const result = await invoke("get_voices_list");
41 |
42 | if(result.code == 200){
43 | this.voices = {};
44 |
45 | // 定义一个映射对象,将 Locale 转换为语言归属地
46 | const localeToLanguage = {
47 | 'af-ZA': '南非语',
48 | 'am-ET': '阿姆哈拉语(埃塞俄比亚)',
49 | 'ar-EG': '阿拉伯语 (埃及)',
50 | 'ar-AE': '阿拉伯语(阿联酋)',
51 | 'ar-BH': '阿拉伯语(巴林)',
52 | 'ar-DZ': '阿拉伯语(阿尔及利亚)',
53 | 'ar-SA': '阿拉伯语(沙特阿拉伯)',
54 | 'ar-IQ': '阿拉伯语(伊拉克)',
55 | 'ar-JO': '阿拉伯语(约旦)',
56 | 'ar-KW': '阿拉伯语(科威特)',
57 | 'ar-LB': '阿拉伯语(黎巴嫩)',
58 | 'ar-LY': '阿拉伯语(利比亚)',
59 | 'ar-MA': '阿拉伯语(摩洛哥)',
60 | 'ar-OM': '阿拉伯语(阿曼)',
61 | 'ar-QA': '阿拉伯语(卡塔尔)',
62 | 'ar-SY': '阿拉伯语(叙利亚)',
63 | 'ar-TN': '阿拉伯语(突尼斯)',
64 | 'az-AZ': '阿塞拜疆语',
65 | 'be-BY': '白俄罗斯语',
66 | 'bg-BG': '保加利亚语',
67 | 'bn-BD': '孟加拉语(孟加拉)',
68 | 'bs-BA': '波斯尼亚语',
69 | 'ca-ES': '加泰罗尼亚语',
70 | 'cs-CZ': '捷克语',
71 | 'cy-GB': '威尔士语',
72 | 'da-DK': '丹麦语',
73 | 'de-DE': '德语(德国)',
74 | 'de-AT': '德语(奥地利)',
75 | 'de-CH': '德语(瑞士)',
76 | 'el-GR': '希腊语',
77 | 'en-US': '英语(美国)',
78 | 'en-GB': '英语(英国)',
79 | 'en-AU': '英语(澳大利亚)',
80 | 'en-CA': '英语(加拿大)',
81 | 'en-IN': '英语(印度)',
82 | 'en-IE': '英语(爱尔兰)',
83 | 'en-NZ': '英语(新西兰)',
84 | 'en-ZA': '英语(南非)',
85 | 'es-ES': '西班牙语(西班牙)',
86 | 'es-MX': '西班牙语(墨西哥)',
87 | 'es-AR': '西班牙语(阿根廷)',
88 | 'es-CO': '西班牙语(哥伦比亚)',
89 | 'es-CL': '西班牙语(智利)',
90 | 'es-PE': '西班牙语(秘鲁)',
91 | 'et-EE': '爱沙尼亚语',
92 | 'eu-ES': '巴斯克语',
93 | 'fa-IR': '波斯语(伊朗)',
94 | 'fi-FI': '芬兰语',
95 | 'fil-PH': '菲律宾语',
96 | 'fr-FR': '法语(法国)',
97 | 'fr-CA': '法语(加拿大)',
98 | 'fr-CH': '法语(瑞士)',
99 | 'fr-BE': '法语(比利时)',
100 | 'gl-ES': '加利西亚语',
101 | 'gu-IN': '古吉拉特语',
102 | 'he-IL': '希伯来语',
103 | 'hi-IN': '印地语',
104 | 'hr-HR': '克罗地亚语',
105 | 'hu-HU': '匈牙利语',
106 | 'hy-AM': '亚美尼亚语',
107 | 'id-ID': '印尼语',
108 | 'is-IS': '冰岛语',
109 | 'it-IT': '意大利语',
110 | 'ja-JP': '日语',
111 | 'jv-ID': '爪哇语',
112 | 'ka-GE': '格鲁吉亚语',
113 | 'kk-KZ': '哈萨克语',
114 | 'km-KH': '高棉语',
115 | 'kn-IN': '卡纳达语',
116 | 'ko-KR': '韩语',
117 | 'lo-LA': '老挝语',
118 | 'lt-LT': '立陶宛语',
119 | 'lv-LV': '拉脱维亚语',
120 | 'mk-MK': '马其顿语',
121 | 'ml-IN': '马拉雅拉姆语',
122 | 'mn-MN': '蒙古语',
123 | 'mr-IN': '马拉地语',
124 | 'ms-MY': '马来语(马来西亚)',
125 | 'ms-SG': '马来语(新加坡)',
126 | 'my-MM': '缅甸语',
127 | 'ne-NP': '尼泊尔语',
128 | 'nl-NL': '荷兰语(荷兰)',
129 | 'nl-BE': '荷兰语(比利时)',
130 | 'no-NO': '挪威语',
131 | 'pa-IN': '旁遮普语',
132 | 'pl-PL': '波兰语',
133 | 'pt-PT': '葡萄牙语(葡萄牙)',
134 | 'pt-BR': '葡萄牙语(巴西)',
135 | 'ro-RO': '罗马尼亚语',
136 | 'ru-RU': '俄语',
137 | 'si-LK': '僧伽罗语',
138 | 'sk-SK': '斯洛伐克语',
139 | 'sl-SI': '斯洛文尼亚语',
140 | 'sq-AL': '阿尔巴尼亚语',
141 | 'sr-RS': '塞尔维亚语',
142 | 'su-ID': '巽他语',
143 | 'sv-SE': '瑞典语',
144 | 'sw-KE': '斯瓦希里语(肯尼亚)',
145 | 'ta-IN': '泰米尔语(印度)',
146 | 'ta-SG': '泰米尔语(新加坡)',
147 | 'te-IN': '泰卢固语',
148 | 'th-TH': '泰语',
149 | 'tr-TR': '土耳其语',
150 | 'uk-UA': '乌克兰语',
151 | 'ur-PK': '乌尔都语',
152 | 'uz-UZ': '乌兹别克语',
153 | 'vi-VN': '越南语',
154 | 'zh-CN': '中文(大陆)',
155 | 'zh-HK': '中文(香港)',
156 | 'zh-TW': '中文(台湾)',
157 | 'zh-SG': '中文(新加坡)',
158 | 'zh-MO': '中文(澳门)',
159 | 'zu-ZA': '祖鲁语',
160 | 'ar-YE': '阿拉伯语(也门)',
161 | 'bn-IN': '孟加拉语(印度)',
162 | 'en-HK': '英语(香港)',
163 | 'en-SG': '英语(新加坡)',
164 | 'en-KE': '英语(肯尼亚)',
165 | 'en-NG': '英语(尼日利亚)',
166 | 'en-PH': '英语(菲律宾)',
167 | 'en-TZ': '英语(坦桑尼亚)',
168 | 'es-BO': '西班牙语(玻利维亚)',
169 | 'es-CR': '西班牙语(哥斯达黎加)',
170 | 'es-CU': '西班牙语(古巴)',
171 | 'es-DO': '西班牙语(多米尼加共和国)',
172 | 'es-EC': '西班牙语(厄瓜多尔)',
173 | 'es-GQ': '西班牙语(赤道几内亚)',
174 | 'es-GT': '西班牙语(危地马拉)',
175 | 'es-HN': '西班牙语(洪都拉斯)',
176 | 'es-NI': '西班牙语(尼加拉瓜)',
177 | 'es-PA': '西班牙语(巴拿马)',
178 | 'es-PR': '西班牙语(波多黎各)',
179 | 'es-PY': '西班牙语(巴拉圭)',
180 | 'es-SV': '西班牙语(萨尔瓦多)',
181 | 'es-US': '西班牙语(美国)',
182 | 'es-UY': '西班牙语(乌拉圭)',
183 | 'es-VE': '西班牙语(委内瑞拉)',
184 | 'ga-IE': '爱尔兰语',
185 | 'iu-Cans-CA': '因纽特语(加拿大)',
186 | 'iu-Latn-CA': '因纽特语(加拿大)',
187 | 'mt-MT': '马耳他语',
188 | 'nb-NO': '挪威语(伯克梅尔)',
189 | 'ps-AF': '普什图语',
190 | 'so-SO': '索马里语',
191 | 'sw-TZ': '斯瓦希里语(坦桑尼亚)',
192 | 'ta-LK': '泰米尔语(斯里兰卡)',
193 | 'ta-MY': '泰米尔语(马来西亚)',
194 | 'ur-IN': '乌尔都语(印度)',
195 | 'zh-CN-liaoning': '中文(辽宁)',
196 | 'zh-CN-shaanxi': '中文(陕西)',
197 | };
198 |
199 | // 映射性别
200 | const genderMap = {
201 | 'Female': '女',
202 | 'Male': '男'
203 | };
204 |
205 | // 遍历 voices 数组
206 | result.data.forEach(voice => {
207 | const locale = voice.Locale;
208 | const language = localeToLanguage[locale] || locale;
209 | voice["Gender"] = genderMap[voice["Gender"]];
210 |
211 | // 如果分类结果中还没有这个语言分类,就创建一个空数组
212 | if (!this.voices[language]) {
213 | this.voices[language] = [];
214 | }
215 |
216 | // 将当前 voice 对象添加到对应的语言分类中
217 | this.voices[language].push({
218 | FriendlyName: voice.FriendlyName,
219 | Gender: voice.Gender,
220 | Name: voice.Name,
221 | simpleName: voice.FriendlyName.split(' ')[1]
222 | });
223 | });
224 | mitter.emit("updataVoicesed");
225 | return {code: 200, msg: "成功", data: { voices: JSON.stringify(this.voices) }};
226 | }else{
227 | mitter.emit("updataVoicesed");
228 | return result;
229 | }
230 | } catch (error) {
231 | mitter.emit("updataVoicesed");
232 | return error;
233 | }
234 | },
235 |
236 | updataVoices(){
237 | return new Promise(async (resolve, reject) => {
238 | try {
239 | const result = await this.getVoicesListRemove();
240 | if(result.code == 200){
241 | // 成功
242 | await update("option", {voices: result.data.voices}, "id = ?", [1]);
243 | resolve();
244 | }else{
245 | reject(result.msg);
246 | }
247 |
248 | } catch (error) {
249 | reject(error);
250 | }
251 | });
252 | }
253 | },
254 | state() {
255 | return{
256 | voices: {}
257 | }
258 | },
259 | })
260 |
--------------------------------------------------------------------------------
/src/utils/function.js:
--------------------------------------------------------------------------------
1 | import { ElMessage } from "element-plus";
2 |
3 | function show_error(error){
4 | let error_str = typeof error == 'string' ? error : "";
5 |
6 | if(error_str == ""){
7 | // error是一个对象,判断是否有msg或message属性
8 | if(error.msg){
9 | error_str = error.msg;
10 | }else if(error.message){
11 | error_str = error.message;
12 | }
13 | }
14 |
15 | ElMessage.error({
16 | dangerouslyUseHTMLString: true,
17 | message: error_str,
18 | });
19 | }
20 |
21 | export {
22 | show_error
23 | }
--------------------------------------------------------------------------------
/src/utils/mitt.js:
--------------------------------------------------------------------------------
1 | import mitt from "mitt";
2 |
3 | const mitter = mitt();
4 |
5 | export default mitter;
--------------------------------------------------------------------------------
/src/utils/sqlite.js:
--------------------------------------------------------------------------------
1 | import Database from '@tauri-apps/plugin-sql';
2 |
3 | let db = null;
4 | let isConnect = false;
5 |
6 | // 基础的数据表
7 | const databseTable = [
8 | {
9 | name: 'option',
10 | sql: `CREATE TABLE option(
11 | id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
12 | voices TEXT DEFAULT '',
13 | ttsOption TEXT DEFAULT '',
14 | softOption TEXT DEFAULT ''
15 | );
16 | `
17 | }
18 | ]
19 |
20 | function connect(){
21 | return new Promise(async (resolve, reject) => {
22 | if(isConnect){
23 | resolve();
24 | }else{
25 | try {
26 | db = await Database.load('sqlite:database.db');
27 | // 初始化数据库
28 | for (let i = 0; i < databseTable.length; i++) {
29 | // 初始化数据库,如果出错,则立即中止,并退出程序
30 | await init(databseTable[i].name, databseTable[i].sql).catch((err) => {
31 | reject(err);
32 | return;
33 | });
34 | }
35 | // 初始化成功,连接成功
36 | isConnect = true;
37 | resolve();
38 |
39 | } catch (error) {
40 | reject(error);
41 | }
42 | }
43 | })
44 | }
45 |
46 | // 数据库初始化
47 | function init(name, sql) {
48 | return new Promise(async function (resolve, reject) {
49 | try {
50 | const result = await db.select("SELECT name FROM sqlite_master WHERE type='table' AND name=$1", [name]);
51 | if(result.length == 0){
52 | // 如果表不存在,则创建表
53 | await db.execute(sql);
54 | if(name == "option"){
55 | // 创建第一条数据,Option表必须有一条数据
56 | await insert("option", ["voices", "ttsOption", "softOption"], ["", "", ""]);
57 | }
58 | }
59 | resolve();
60 | } catch (error) {
61 | reject(error);
62 | }
63 | });
64 | }
65 |
66 |
67 | function disConnect(){
68 | return new Promise(async (resolve, reject) => {
69 | try {
70 | await db.close();
71 |
72 | db = null;
73 | isConnect = false;
74 | resolve();
75 | } catch (error) {
76 | reject(error);
77 | }
78 | })
79 | }
80 |
81 | // 处理条件中的?
82 | function placeholderEscape(whereClause, valuesLength){
83 | let processedWhereClause = whereClause;
84 | let sql = "";
85 | if (whereClause) {
86 | const wherePlaceholders = whereClause.match(/\?/g);
87 | if (wherePlaceholders) {
88 | wherePlaceholders.forEach((_, index) => {
89 | processedWhereClause = processedWhereClause.replace('?', `\$${valuesLength + index + 1}`);
90 | });
91 | }
92 | sql += ` WHERE ${processedWhereClause}`;
93 | }
94 |
95 | return sql;
96 | }
97 |
98 | /**
99 | * 插入数据的通用函数
100 | * @param {string} tableName - 表名
101 | * @param {string[]} columns - 列名数组
102 | * @param {any[]} values - 值数组
103 | * @example insert("fingerprint", ["fingerprint", "last_ip", "last_time"], ["1", "2", "3"]).then((data)=>console.log(data)).catch();
104 | */
105 | function insert(tableName, columns, values){
106 | return new Promise(async (resolve, reject) => {
107 | // 动态生成列名和占位符
108 | const columnNames = columns.join(', ');
109 | // 占位符为 $1, $2, $3...
110 | const placeholders = columns.map((_, index) => `$${index + 1}`).join(', ');
111 |
112 | const sql = `INSERT INTO ${tableName} (${columnNames}) VALUES (${placeholders})`;
113 |
114 | try {
115 | const result = await db.execute(sql, values);
116 | resolve({
117 | sql,
118 | changes: result.rowsAffected,
119 | lastId: result.lastInsertId
120 | })
121 | } catch (error) {
122 | reject(error);
123 | }
124 | })
125 | }
126 |
127 | /**
128 | * 更新数据的通用函数
129 | * @param {string} tableName - 表名
130 | * @param {object} data - 要更新的列和值的对象
131 | * @param {string} whereClause - 可选的 WHERE 条件
132 | * @param {any[]} whereArgs - 可选的 WHERE 条件参数数组
133 | * @example update("fingerprint", {fingerprint: "4", last_ip: "5", last_time: "6"}, "id = ?", [4]).then((data)=>console.log(data)).catch((error)=>console.log(error));
134 | */
135 | function update(tableName, data, whereClause = '', whereArgs = []) {
136 | return new Promise(async (resolve, reject) => {
137 | // 提取列和值
138 | const columns = Object.keys(data);
139 | const values = Object.values(data);
140 | // 动态生成 SET 子句,使用 $1, $2, ... 占位符
141 | const setClause = columns.map((col, index) => `${col} = $${index + 1}`).join(', ');
142 | let sql = `UPDATE ${tableName} SET ${setClause}`;
143 | // 处理 WHERE 子句中的占位符
144 | sql += placeholderEscape(whereClause, values.length);
145 | // 合并更新的值和 WHERE 子句的参数
146 | const allValues = [...values, ...whereArgs];
147 | // 执行 SQL
148 | try {
149 | const result = await db.execute(sql, allValues);
150 | resolve({
151 | sql,
152 | changes: result.rowsAffected
153 | })
154 | } catch (error) {
155 | reject(error);
156 | }
157 | });
158 | }
159 |
160 | /**
161 | * 通用查询函数
162 | * @param {string} tableName - 表名
163 | * @param {string[]} columns - 要查询的列名数组,传 `*` 查询所有列
164 | * @param {string} whereClause - 可选的 WHERE 条件
165 | * @param {any[]} whereArgs - 可选的 WHERE 条件参数数组
166 | * @example select("fingerprint", ['*'], 'id = ? OR id = ?', [1,2]).then((data)=>console.log(data)).catch((error)=>console.log(error));
167 | */
168 | function select(tableName, columns, whereClause = '', whereArgs = []) {
169 | return new Promise(async (resolve, reject) => {
170 | // 动态生成查询语句
171 | const columnList = columns.length > 0 ? columns.join(', ') : '*';
172 | let sql = `SELECT ${columnList} FROM ${tableName}`;
173 | if(whereClause){
174 | sql += placeholderEscape(whereClause, 0);
175 | }
176 |
177 | // 执行查询
178 | try {
179 | const result = await db.select(sql, whereArgs);
180 | resolve({
181 | sql,
182 | rows: result
183 | });
184 | } catch (error) {
185 | reject(error);
186 | }
187 | });
188 | }
189 |
190 | /**
191 | * 通用删除函数
192 | * @param {string} tableName - 表名
193 | * @param {string} whereClause - 可选的 WHERE 条件
194 | * @param {any[]} whereArgs - 可选的 WHERE 条件参数数组
195 | * @example deleteData("fingerprint", "id = ?", [1]).then((data)=>console.log(data)).catch((error)=>console.log(error));
196 | */
197 | function deleteData(tableName, whereClause = '', whereArgs = []) {
198 | return new Promise(async (resolve, reject) => {
199 | // 动态生成删除语句
200 | let sql = `DELETE FROM ${tableName}`;
201 | if (whereClause) {
202 | sql += placeholderEscape(whereClause, 0);
203 | }
204 |
205 | // 执行删除操作
206 | try {
207 | const result = await db.execute(sql, whereArgs);
208 | resolve({
209 | sql,
210 | changes: result.rowsAffected
211 | });
212 | } catch (error) {
213 | reject(error);
214 | }
215 | });
216 | }
217 |
218 | /**
219 | * 自定义查询函数,自己写SQL和条件
220 | * @param {string} sql - SQL语句
221 | * @param {any[]} whereArgs - 可选的 WHERE 条件参数数组
222 | */
223 | function selectCustom(sql, whereArgs) {
224 | return new Promise(async (resolve, reject) => {
225 | // 执行查询
226 | try {
227 | const result = await db.select(sql, whereArgs);
228 | resolve({
229 | sql,
230 | rows: result
231 | });
232 | } catch (error) {
233 | reject(error);
234 | }
235 | });
236 | }
237 |
238 | export {
239 | connect, disConnect, insert, update, select, deleteData, selectCustom
240 | }
--------------------------------------------------------------------------------
/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "vite";
2 | import vue from "@vitejs/plugin-vue";
3 | import AutoImport from 'unplugin-auto-import/vite'
4 | import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
5 | import IconsResolver from 'unplugin-icons/resolver'
6 | import Icons from 'unplugin-icons/vite'
7 | import path from 'path'
8 | import Components from 'unplugin-vue-components/vite'
9 |
10 | const host = process.env.TAURI_DEV_HOST;
11 | const pathSrc = path.resolve(__dirname, 'src')
12 |
13 | // https://vitejs.dev/config/
14 | export default defineConfig(async () => ({
15 | plugins: [vue(),
16 | AutoImport({
17 | // Auto import functions from Vue, e.g. ref, reactive, toRef...
18 | // 自动导入 Vue 相关函数,如:ref, reactive, toRef 等
19 | imports: ['vue'],
20 |
21 | // Auto import functions from Element Plus, e.g. ElMessage, ElMessageBox... (with style)
22 | // 自动导入 Element Plus 相关函数,如:ElMessage, ElMessageBox... (带样式)
23 | resolvers: [
24 | ElementPlusResolver(),
25 |
26 | // Auto import icon components
27 | // 自动导入图标组件
28 | IconsResolver({
29 | prefix: 'Icon',
30 | }),
31 | ],
32 |
33 | dts: path.resolve(pathSrc, 'auto-imports.d.ts'),
34 | }),
35 |
36 | Components({
37 | resolvers: [
38 | // Auto register icon components
39 | // 自动注册图标组件
40 | IconsResolver({
41 | enabledCollections: ['ep'],
42 | }),
43 | // Auto register Element Plus components
44 | // 自动导入 Element Plus 组件
45 | ElementPlusResolver(),
46 | ],
47 |
48 | dts: path.resolve(pathSrc, 'components.d.ts'),
49 | }),
50 |
51 | Icons({
52 | autoInstall: true,
53 | })
54 | ],
55 |
56 | // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
57 | //
58 | // 1. prevent vite from obscuring rust errors
59 | clearScreen: false,
60 | // 2. tauri expects a fixed port, fail if that port is not available
61 | server: {
62 | port: 1420,
63 | strictPort: true,
64 | host: host || false,
65 | hmr: host
66 | ? {
67 | protocol: "ws",
68 | host,
69 | port: 1421,
70 | }
71 | : undefined,
72 | watch: {
73 | // 3. tell vite to ignore watching `src-tauri`
74 | ignored: ["**/src-tauri/**"],
75 | },
76 | },
77 | }));
78 |
--------------------------------------------------------------------------------