├── .env
├── .browserslistrc
├── src
├── views
│ ├── Help
│ │ └── index.vue
│ ├── Settings
│ │ └── index.vue
│ └── Convert
│ │ ├── api
│ │ ├── dbtools.js
│ │ └── alibaba.js
│ │ ├── SelectVoicer.vue
│ │ ├── SelectMusic.vue
│ │ └── index.vue
├── appsrc
│ ├── music.db
│ └── voicer.db
├── assets
│ ├── logo.png
│ └── global.css
├── TestCode
│ ├── music.db
│ ├── voicer.db
│ ├── demo5.js
│ ├── demo6.js
│ ├── demo4.js
│ ├── voicer.json
│ └── music.json
├── plugins
│ └── element.js
├── store
│ └── index.js
├── daili
│ ├── config.js
│ └── nsh
│ │ └── installer.nsh
├── main.js
├── router
│ └── index.js
├── components
│ └── DevDialog
│ │ └── DevDialog.vue
├── utils
│ └── utils.js
├── background.js
└── App.vue
├── public
├── icon.png
├── music.db
├── favicon.ico
├── voicer
│ ├── Abby.mp3
│ ├── Aibao.mp3
│ ├── Aida.mp3
│ ├── Aijia.mp3
│ ├── Aimei.mp3
│ ├── Aina.mp3
│ ├── Aiqi.mp3
│ ├── Aiwei.mp3
│ ├── Aixia.mp3
│ ├── Aiya.mp3
│ ├── Aiyu.mp3
│ ├── Aiyue.mp3
│ ├── Andy.mp3
│ ├── Emily.mp3
│ ├── Eric.mp3
│ ├── Harry.mp3
│ ├── Luca.mp3
│ ├── Luna.mp3
│ ├── Lydia.mp3
│ ├── Ruoxi.mp3
│ ├── Sijia.mp3
│ ├── Siqi.mp3
│ ├── Siyue.mp3
│ ├── Wendy.mp3
│ ├── Yina.mp3
│ ├── Aicheng.mp3
│ ├── Aijing.mp3
│ ├── Aishuo.mp3
│ ├── Aitong.mp3
│ ├── Cuijie.mp3
│ ├── Ninger.mp3
│ ├── Olivia.mp3
│ ├── Ruilin.mp3
│ ├── Sicheng.mp3
│ ├── Sijing.mp3
│ ├── Sitong.mp3
│ ├── William.mp3
│ ├── Xiaobei.mp3
│ ├── Xiaomei.mp3
│ ├── Xiaoyue.mp3
│ ├── Xiaoyun.mp3
│ ├── Xiaoze.mp3
│ ├── Qingqing.mp3
│ ├── Shanshan.mp3
│ └── Xiaogang.mp3
├── index.html
└── data.json
├── images
└── screen.png
├── babel.config.js
├── jsconfig.json
├── .gitignore
├── .eslintrc.js
├── README.md
├── vue.config.js
└── package.json
/.env:
--------------------------------------------------------------------------------
1 | GH_TOKEN=d37f4c6e3457329391923251930e1debaa0e06d5
--------------------------------------------------------------------------------
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 | not dead
4 |
--------------------------------------------------------------------------------
/src/views/Help/index.vue:
--------------------------------------------------------------------------------
1 |
2 | 使用帮助
3 |
--------------------------------------------------------------------------------
/public/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/icon.png
--------------------------------------------------------------------------------
/public/music.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/music.db
--------------------------------------------------------------------------------
/images/screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/images/screen.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/src/appsrc/music.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/src/appsrc/music.db
--------------------------------------------------------------------------------
/src/appsrc/voicer.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/src/appsrc/voicer.db
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/src/assets/logo.png
--------------------------------------------------------------------------------
/public/voicer/Abby.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Abby.mp3
--------------------------------------------------------------------------------
/public/voicer/Aibao.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Aibao.mp3
--------------------------------------------------------------------------------
/public/voicer/Aida.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Aida.mp3
--------------------------------------------------------------------------------
/public/voicer/Aijia.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Aijia.mp3
--------------------------------------------------------------------------------
/public/voicer/Aimei.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Aimei.mp3
--------------------------------------------------------------------------------
/public/voicer/Aina.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Aina.mp3
--------------------------------------------------------------------------------
/public/voicer/Aiqi.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Aiqi.mp3
--------------------------------------------------------------------------------
/public/voicer/Aiwei.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Aiwei.mp3
--------------------------------------------------------------------------------
/public/voicer/Aixia.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Aixia.mp3
--------------------------------------------------------------------------------
/public/voicer/Aiya.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Aiya.mp3
--------------------------------------------------------------------------------
/public/voicer/Aiyu.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Aiyu.mp3
--------------------------------------------------------------------------------
/public/voicer/Aiyue.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Aiyue.mp3
--------------------------------------------------------------------------------
/public/voicer/Andy.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Andy.mp3
--------------------------------------------------------------------------------
/public/voicer/Emily.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Emily.mp3
--------------------------------------------------------------------------------
/public/voicer/Eric.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Eric.mp3
--------------------------------------------------------------------------------
/public/voicer/Harry.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Harry.mp3
--------------------------------------------------------------------------------
/public/voicer/Luca.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Luca.mp3
--------------------------------------------------------------------------------
/public/voicer/Luna.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Luna.mp3
--------------------------------------------------------------------------------
/public/voicer/Lydia.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Lydia.mp3
--------------------------------------------------------------------------------
/public/voicer/Ruoxi.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Ruoxi.mp3
--------------------------------------------------------------------------------
/public/voicer/Sijia.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Sijia.mp3
--------------------------------------------------------------------------------
/public/voicer/Siqi.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Siqi.mp3
--------------------------------------------------------------------------------
/public/voicer/Siyue.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Siyue.mp3
--------------------------------------------------------------------------------
/public/voicer/Wendy.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Wendy.mp3
--------------------------------------------------------------------------------
/public/voicer/Yina.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Yina.mp3
--------------------------------------------------------------------------------
/src/TestCode/music.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/src/TestCode/music.db
--------------------------------------------------------------------------------
/src/TestCode/voicer.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/src/TestCode/voicer.db
--------------------------------------------------------------------------------
/public/voicer/Aicheng.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Aicheng.mp3
--------------------------------------------------------------------------------
/public/voicer/Aijing.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Aijing.mp3
--------------------------------------------------------------------------------
/public/voicer/Aishuo.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Aishuo.mp3
--------------------------------------------------------------------------------
/public/voicer/Aitong.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Aitong.mp3
--------------------------------------------------------------------------------
/public/voicer/Cuijie.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Cuijie.mp3
--------------------------------------------------------------------------------
/public/voicer/Ninger.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Ninger.mp3
--------------------------------------------------------------------------------
/public/voicer/Olivia.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Olivia.mp3
--------------------------------------------------------------------------------
/public/voicer/Ruilin.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Ruilin.mp3
--------------------------------------------------------------------------------
/public/voicer/Sicheng.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Sicheng.mp3
--------------------------------------------------------------------------------
/public/voicer/Sijing.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Sijing.mp3
--------------------------------------------------------------------------------
/public/voicer/Sitong.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Sitong.mp3
--------------------------------------------------------------------------------
/public/voicer/William.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/William.mp3
--------------------------------------------------------------------------------
/public/voicer/Xiaobei.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Xiaobei.mp3
--------------------------------------------------------------------------------
/public/voicer/Xiaomei.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Xiaomei.mp3
--------------------------------------------------------------------------------
/public/voicer/Xiaoyue.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Xiaoyue.mp3
--------------------------------------------------------------------------------
/public/voicer/Xiaoyun.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Xiaoyun.mp3
--------------------------------------------------------------------------------
/public/voicer/Xiaoze.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Xiaoze.mp3
--------------------------------------------------------------------------------
/public/voicer/Qingqing.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Qingqing.mp3
--------------------------------------------------------------------------------
/public/voicer/Shanshan.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Shanshan.mp3
--------------------------------------------------------------------------------
/public/voicer/Xiaogang.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bawangxx/XZVoice/HEAD/public/voicer/Xiaogang.mp3
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset',
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/src/assets/global.css:
--------------------------------------------------------------------------------
1 | html,body,#app{
2 | height: 100%;
3 | width: 100%;
4 | margin: 0;
5 | padding: 0;
6 | }
--------------------------------------------------------------------------------
/src/plugins/element.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Element from 'element-ui'
3 | import 'element-ui/lib/theme-chalk/index.css'
4 |
5 | Vue.use(Element)
6 |
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 |
4 | Vue.use(Vuex)
5 |
6 | export default new Vuex.Store({
7 | state: {
8 | },
9 | mutations: {
10 | },
11 | actions: {
12 | },
13 | modules: {
14 | }
15 | })
16 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES6",
4 | "module": "commonjs",
5 | "allowSyntheticDefaultImports": true,
6 | "baseUrl": "./",
7 | "paths": {
8 | "@/*": ["src/*"]
9 | }
10 | },
11 | "exclude": ["node_modules"]
12 | }
13 |
--------------------------------------------------------------------------------
/src/daili/config.js:
--------------------------------------------------------------------------------
1 | const pkg = require("../../package.json");
2 |
3 | const mainConfig = {
4 | softName: "AI配音专家",
5 | softVersion: pkg.version,
6 | userFolder: "xzvoice", // 用户文件夹名
7 | proName: "voice", //项目名称
8 | company: "吾爱破解",
9 | nshPath: "src/daili/nsh/installer.nsh", //自定义nsis脚本路径
10 | };
11 |
12 | module.exports = mainConfig;
13 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 | import router from './router'
4 | import store from './store'
5 | import './plugins/element.js'
6 |
7 | // 导入全局样式
8 | import '@/assets/global.css';
9 |
10 |
11 |
12 | Vue.config.productionTip = false
13 |
14 | new Vue({
15 | router,
16 | store,
17 | render: h => h(App)
18 | }).$mount('#app')
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 | test
5 | *.exe
6 | package-lock.json
7 |
8 | # local env files
9 | .env.local
10 | .env.*.local
11 |
12 | # Log files
13 | npm-debug.log*
14 | yarn-debug.log*
15 | yarn-error.log*
16 | pnpm-debug.log*
17 |
18 | # Editor directories and files
19 | .idea
20 | .vscode
21 | *.suo
22 | *.ntvs*
23 | *.njsproj
24 | *.sln
25 | *.sw?
26 |
27 | #Electron-builder output
28 | /dist_electron
--------------------------------------------------------------------------------
/src/daili/nsh/installer.nsh:
--------------------------------------------------------------------------------
1 | !macro preInit
2 | SetRegView 64
3 | WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\xzsoft\xzvoice"
4 | WriteRegExpandStr HKCU "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\xzsoft\xzvoice"
5 | SetRegView 32
6 | WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\xzsoft\xzvoice"
7 | WriteRegExpandStr HKCU "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\xzsoft\xzvoice"
8 | !macroend
--------------------------------------------------------------------------------
/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import VueRouter from 'vue-router'
3 |
4 | // 导入自定义组件
5 | import Convert from "@/views/Convert";
6 | import Settings from "@/views/Settings";
7 | import Help from "@/views/Help"
8 |
9 | Vue.use(VueRouter)
10 |
11 | const routes = [
12 | //文字转语音转换
13 | { path: "/", name: "Convert", component: Convert },
14 | //高级设置
15 | { path: "/settings", name: "Settings", component: Settings, },
16 | //使用帮助
17 | { path: "/help", name: "Help", component: Help },
18 | ];
19 |
20 | const router = new VueRouter({
21 | routes
22 | })
23 |
24 | export default router
25 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <%= htmlWebpackPlugin.options.title %>
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true
5 | },
6 | 'extends': [
7 | 'plugin:vue/essential',
8 | 'eslint:recommended'
9 | ],
10 | parserOptions: {
11 | parser: 'babel-eslint'
12 | },
13 | rules: {
14 | 'no-console': process.env.NODE_ENV === 'production' ? 'off' : 'off',
15 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'off' : 'off',
16 | 'no-unused-vars': process.env.NODE_ENV === 'production' ? 'off' : 'off',
17 | 'no-unreachable': process.env.NODE_ENV === 'production' ? 'off' : 'off',
18 | 'no-empty': process.env.NODE_ENV === 'production' ? 'off' : 'off',
19 | },
20 | "globals": { "__static": true }, //参考:https://stackoverflow.com/questions/45317154/error-is-not-defined-no-undef/46100803
21 | }
22 |
--------------------------------------------------------------------------------
/public/data.json:
--------------------------------------------------------------------------------
1 | [
2 | {"name": "晶晶", "type": "精品女声"},
3 | {"name": "蓝雨", "type": "精品女声"},
4 | {"name": "小玲", "type": "精品女声"},
5 | {"name": "安宁", "type": "精品女声"},
6 | {"name": "小军", "type": "精品男声"},
7 | {"name": "考拉", "type": "精品男声"},
8 | {"name": "楸木", "type": "精品男声"},
9 | {"name": "晶晶", "type": "精品女声"},
10 | {"name": "蓝雨", "type": "精品女声"},
11 | {"name": "小玲", "type": "精品女声"},
12 | {"name": "安宁", "type": "精品女声"},
13 | {"name": "小军", "type": "精品男声"},
14 | {"name": "考拉", "type": "精品男声"},
15 | {"name": "楸木", "type": "精品男声"},
16 | {"name": "晶晶", "type": "精品女声"},
17 | {"name": "蓝雨", "type": "精品女声"},
18 | {"name": "小玲", "type": "精品女声"},
19 | {"name": "安宁", "type": "精品女声"},
20 | {"name": "小军", "type": "精品男声"},
21 | {"name": "考拉", "type": "精品男声"},
22 | {"name": "楸木", "type": "精品男声"}
23 | ]
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Electron + vue + ElementUI + js开发的文字转语音软件
2 |
3 | ### 爱发电:https://afdian.net/a/bawangxx
4 |
5 | ### 最新版V2已发布,下载地址:https://pan.baidu.com/s/1yw_l8QrH1Xx1dZxPpkdL7w?pwd=8888
6 |
7 | [](https://github.com/bawangxx/xz_voice)
8 |
9 |
10 | ## 使用帮助:
11 |
12 | 采用阿里云语音合成引擎
13 | 官网地址:https://ai.aliyun.com/nls/tts
14 |
15 | ## 一、设置应用秘钥
16 |
17 | ### 1.找到路径:src\views\Convert\api\alibaba.js
18 |
19 | ### 2.修改代码:
20 | ```sh
21 | this.AccessKeyId = '设置成你在阿里云申请的:AccessKeyId';
22 | this.AccessKeySecret = '设置成你在阿里云申请的:AccessKeySecret';
23 | this.appkey = '设置成你在阿里云申请的:appkey';
24 | ```
25 |
26 |
27 | ## 二、设置在线音乐
28 | ### 1.找到路径:src\views\Convert\SelectMusic.vue
29 | ### 2.搜索代码:http://xxx.xxx.com/ 修改为:你在七牛云空间cname的域名
30 | ### 3.将背景音乐包上传到七牛云的空间,设置为公开
31 | ### 4.背景音乐包下载地址:https://bawangxx.lanzous.com/b0c34tv9e 密码:9r9y
32 |
33 |
34 | ## 三、软件打包
35 | 执行:
36 | ```sh
37 | npm i
38 | npm run electron:build
39 | ```
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/src/components/DevDialog/DevDialog.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
11 |
41 |
--------------------------------------------------------------------------------
/src/TestCode/demo5.js:
--------------------------------------------------------------------------------
1 | const { Sequelize, DataTypes, Model } = require("sequelize");
2 | const jsonfile = require("jsonfile");
3 | // import path from "path";
4 | // import { Sequelize, DataTypes, Model } from "sequelize"
5 |
6 |
7 | // 获取音乐列表模型
8 | async function getMusicModel(){
9 | // 链接数据库
10 | const sequelize = new Sequelize({
11 | dialect: "sqlite",
12 | storage: "./music.db",
13 | logging: false
14 | });
15 | // 初始化表模型
16 | const Music = sequelize.define(
17 | "Music",
18 | {
19 | // 音乐名称(示例:元旦)
20 | name: {
21 | type: DataTypes.STRING,
22 | allowNull: false,
23 | },
24 | // 音乐类别(示例:彩铃配音)
25 | category: {
26 | type: DataTypes.STRING,
27 | allowNull: false,
28 | },
29 | },
30 | );
31 | // 同步表模型
32 | await Music.sync();
33 | console.log("同步表模型完毕!");
34 | return Music;
35 | }
36 |
37 |
38 | // 插入数据
39 | async function insertMusic(model) {
40 | const file = "./music.json";
41 | const data = jsonfile.readFileSync(file);
42 | data.forEach( async element => {
43 | // console.log(element)
44 | await model.create(element);
45 | });
46 |
47 | console.log("插入数据完毕!");
48 | }
49 |
50 |
51 | (async () => {
52 |
53 | const music = await getMusicModel();
54 | // pageQuery(voicer); // 分页查询
55 | // whereQuery(voicer); // 条件查询
56 | // selectAall(voicer); // 查询所有
57 | insertMusic(music); // 插入数据
58 | // deleteTable(voicer); //删除表
59 |
60 | })();
61 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | const Daili = require("./src/daili/config");
2 | const nshPath = Daili.nshPath;
3 | const appName = Daili.softName;
4 | const proName = Daili.proName;
5 |
6 |
7 | const ext = process.platform == 'darwin' ? '' : '.exe';
8 | module.exports = {
9 | pluginOptions: {
10 | electronBuilder: {
11 | nodeIntegration: true, //开启渲染进程使用node模块
12 | externals: ["sequelize","keyv"],
13 | experimentalNativeDepCheck: true,
14 | builderOptions: {// elctronbuilder设置
15 | publish: ['github'],
16 | appId: `com.xzsoft.${proName}`,
17 | productName: `${appName}`,
18 | asar: true, // 是否使用asar打包
19 | extraResources: [
20 | { from: "./src/appsrc", to: "./", }, //相当于打包之后应用目录下的resource目录
21 | // { from: "./node_modules/ffmpeg-static/ffmpeg.exe", to: "./", }
22 | { from: `./node_modules/ffmpeg-static/ffmpeg${ext}`, to: "./", }
23 | ],
24 | appx: {
25 | identityName: "117159ADCB705.AI",
26 | publisher: "CN=F28873AD-2D3D-4AE9-9EA0-2A4DBFE7D41B",
27 | publisherDisplayName: "小智软件",
28 | applicationId: `com.xzsoft.${proName}`,
29 | languages: "zh-CN"
30 | },
31 | win: {
32 | target: [
33 | {
34 | target: "nsis", //nsis appx
35 | arch: ["x64"], // "ia32" x64
36 | },
37 | ],
38 | },
39 | nsis: {
40 | include: nshPath, //自定义nsis脚本
41 | oneClick: false, // 是否一键安装
42 | perMachine: true, //安装是否总是针对所有用户
43 | allowElevation: true, // 允许请求提升。 如果为false,则用户必须使用提升的权限重新启动安装程序。
44 | allowToChangeInstallationDirectory: true, // 允许修改安装目录
45 | createDesktopShortcut: true, // 创建桌面图标
46 | createStartMenuShortcut: true, // 创建开始菜单图标
47 | shortcutName: `${appName}`, //将用于所有快捷方式的名称。默认为应用程序名称
48 | uninstallDisplayName: `${appName}`, //卸载程序在控制面板中显示名称。
49 | artifactName: `${appName}-Windows版.exe`
50 | },
51 | mac: {
52 | target: "dmg",
53 | identity: null //构建的时候是否签名,解决未签名的警告
54 | },
55 | dmg: {
56 | title: `${appName}`, //生成DMG的标题,将在挂载时显示(卷名)
57 | artifactName: `${appName}-Mac版.dmg`, //工程文件名
58 | }
59 | },
60 | },
61 | },
62 | };
63 |
--------------------------------------------------------------------------------
/src/TestCode/demo6.js:
--------------------------------------------------------------------------------
1 | const { substr } = require("ffmpeg-static");
2 |
3 | // 按字数切分文本
4 | function splitLongText(text, size) {
5 | //先按标点符号切分
6 | let texts = text.split(/[、,。;?!,!\\?\s]/);
7 | let textPart = "";
8 | let result = [];
9 | let len = 0;
10 | //再按size merge,避免标点符号切分出来的太短
11 | for (let i = 0; i < texts.length; i++) {
12 | console.log('--------111--------')
13 | if (textPart.length + texts[i].length + 1 > size) {
14 | result.push(textPart.toString());
15 | textPart = "";
16 | console.log('--------222--------')
17 | }
18 | textPart = textPart + texts[i];
19 | len += texts[i].length;
20 | if (len < text.length) {
21 | textPart = textPart + text.charAt(len);
22 | len += 1;
23 | console.log('--------333--------')
24 | }
25 | }
26 | // console.log(result)
27 |
28 | if (textPart.length > 0) {
29 | console.log('--------444--------')
30 | result.push(textPart.toString());
31 | }
32 | // console.log(result)
33 | return result;
34 | }
35 |
36 | function getSubString(str, len) {
37 | var strlen = 0;
38 | var s = "";
39 | for (var i = 0; i < str.length; i++) {
40 | if (str.charCodeAt(i) > 128) {
41 | strlen += 2;
42 | } else {
43 | strlen++;
44 | }
45 | s += str.charAt(i);
46 | if (strlen >= len) {
47 | return s;
48 | }
49 | }
50 | return s;
51 | }
52 | // let longText = `123456789`;
53 |
54 |
55 | // console.log(longText.length);
56 |
57 | // const size = 5;
58 |
59 | // const zhengShu = parseInt(longText.length/size);
60 | // const yushu = longText.length % size
61 | // let resArr = [];
62 | // for (let index = 0; index < zhengShu; index++) {
63 |
64 | // const subStr = getSubString(longText,size);
65 | // resArr.push(subStr);
66 | // longText = longText.replace(subStr,'')
67 | // }
68 | // const subStr = getSubString(longText,yushu);
69 | // if(subStr != '') resArr.push(subStr);
70 |
71 |
72 | // console.log(resArr);
73 |
74 |
75 |
76 |
77 | let arr = ['1','2'];
78 | let arr2 = ['3','4'];
79 | arr = arr.concat(arr2)
80 |
81 | console.log(arr);
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "xzvoice",
3 | "version": "1.1.0",
4 | "private": true,
5 | "author": "XZSoft",
6 | "description": "最好用的文字转语音工具!",
7 | "scripts": {
8 | "serve": "vue-cli-service serve",
9 | "build": "vue-cli-service build",
10 | "lint": "vue-cli-service lint",
11 | "electron:build": "vue-cli-service electron:build",
12 | "electron:serve": "vue-cli-service electron:serve",
13 | "postinstall": "electron-builder install-app-deps",
14 | "postuninstall": "electron-builder install-app-deps",
15 | "electron:generate-icons": "electron-icon-builder --input=./public/icon.png --output=build --flatten"
16 | },
17 | "main": "background.js",
18 | "dependencies": {
19 | "aws-sdk": "^2.799.0",
20 | "core-js": "^3.6.5",
21 | "cos-nodejs-sdk-v5": "^2.8.3",
22 | "datauri": "^3.0.0",
23 | "dayjs": "^1.10.3",
24 | "dns": "^0.2.2",
25 | "electron-store": "^7.0.2",
26 | "electron-updater": "^4.3.5",
27 | "element-ui": "^2.4.5",
28 | "ffmpeg-static": "^4.2.7",
29 | "howler": "^2.2.1",
30 | "http2": "^3.3.7",
31 | "keyv": "^4.0.3",
32 | "kitx": "^2.1.0",
33 | "ospath": "^1.2.2",
34 | "pg-hstore": "^2.3.3",
35 | "request": "^2.79.0",
36 | "sequelize": "^6.3.5",
37 | "shelljs": "^0.8.4",
38 | "sqlite3": "^5.0.0",
39 | "vue": "^2.6.11",
40 | "vue-router": "^3.2.0",
41 | "vuex": "^3.4.0",
42 | "xregexp": "^4.3.0"
43 | },
44 | "devDependencies": {
45 | "@vue/cli-plugin-babel": "~4.5.0",
46 | "@vue/cli-plugin-eslint": "~4.5.0",
47 | "@vue/cli-plugin-router": "~4.5.0",
48 | "@vue/cli-plugin-vuex": "~4.5.0",
49 | "@vue/cli-service": "~4.5.0",
50 | "babel-eslint": "^10.1.0",
51 | "bignumber.js": "^9.0.1",
52 | "bytes": "^3.1.0",
53 | "crypto-js": "^4.0.0",
54 | "electron": "^11.3.0",
55 | "electron-devtools-installer": "^3.1.0",
56 | "electron-icon-builder": "^1.0.2",
57 | "eslint": "^6.7.2",
58 | "eslint-plugin-vue": "^6.2.2",
59 | "got": "^11.8.0",
60 | "jsonfile": "^6.1.0",
61 | "less": "^3.0.4",
62 | "less-loader": "^5.0.0",
63 | "node-machine-id": "^1.1.12",
64 | "request-progress": "^3.0.0",
65 | "semver": "^7.3.2",
66 | "vue-cli-plugin-electron-builder": "^2.0.0-rc.5",
67 | "vue-cli-plugin-element": "^1.0.1",
68 | "vue-template-compiler": "^2.6.11"
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/utils/utils.js:
--------------------------------------------------------------------------------
1 | const {app} = require("electron").remote;
2 |
3 | const fse = require("fs-extra");
4 | const jsonfile = require("jsonfile");
5 | const path = require("path");
6 | const os = require("os");
7 | import Daili from '@/daili/config';
8 |
9 | class Utils {
10 | // 用户目录
11 | static userFolder = path.join(os.homedir(), Daili.userFolder);
12 | static createUserFolder() {
13 | if (fse.existsSync(this.userFolder) == false) {
14 | fse.ensureDirSync(this.userFolder);
15 | }
16 | }
17 |
18 | static getFFmpegPath() {
19 | const isBuild = process.env.NODE_ENV === "production"; //是否为生产环境
20 | let ffmpegPath;
21 | const ext = process.platform == 'darwin' ? '' : '.exe';
22 | if (isBuild) {
23 | ffmpegPath = path.join(process.cwd(), "resources", `ffmpeg${ext}`);
24 | if(process.platform == 'darwin'){
25 | ffmpegPath = path.join(path.parse(app.getAppPath()).dir, `ffmpeg${ext}`);
26 | }
27 | } else {
28 | ffmpegPath = path.join(
29 | process.cwd(),
30 | "node_modules",
31 | "ffmpeg-static",
32 | `ffmpeg${ext}`
33 | );
34 | }
35 | return ffmpegPath;
36 | }
37 |
38 | // 自动获取生产或开发环境下的资源目录
39 | static getSrcPath() {
40 | const isBuild = process.env.NODE_ENV === "production"; //是否为生产环境
41 | let resPath = path.join(process.cwd(), "resources"); //打包后应用根目录下resources目录
42 | const srcPath = path.join(process.cwd(), "src", "appsrc"); //项目资源目录,里面存放拷贝到打包后应用根目录的文件
43 | if(process.platform == 'darwin'){
44 | // resPath = path.join(process.cwd(),"Contents", "Resources");
45 | resPath = path.parse(app.getAppPath()).dir;
46 | }
47 | return isBuild ? resPath : srcPath;
48 | }
49 |
50 | // 获取十位时间戳(精确到秒)
51 | static getTimestamp10() {
52 | return Math.round(new Date().getTime() / 1000);
53 | }
54 |
55 | // 保存json到文件
56 | static saveJson(path, section, value) {
57 | /**
58 | * @description:保存对象或数组到json文件
59 | * @param {path} json文件路径
60 | * @param {section} 节点名称
61 | * @param {value} 要保存的数组或者对象
62 | */
63 |
64 | let obj = {};
65 | if (fse.existsSync(path)) {
66 | obj = jsonfile.readFileSync(path);
67 | }
68 | fse.ensureFileSync(path);
69 | obj[section] = value;
70 | jsonfile.writeFileSync(path, obj, { spaces: 2, EOL: "\r\n" });
71 | }
72 |
73 | // 读取Json文件
74 | static readJson(path, section, defaultValue) {
75 | if (fse.existsSync(path)) {
76 | const obj = jsonfile.readFileSync(path);
77 | if (obj[section]) {
78 | return obj[section];
79 | }
80 | }
81 | return defaultValue;
82 | }
83 | }
84 |
85 | export default Utils;
86 |
--------------------------------------------------------------------------------
/src/views/Settings/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 自定义Key
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | 保存
19 | 重置
20 |
21 |
22 |
23 |
24 |
25 |
26 |
64 |
65 |
70 |
--------------------------------------------------------------------------------
/src/views/Convert/api/dbtools.js:
--------------------------------------------------------------------------------
1 | import { Sequelize, DataTypes } from "sequelize";
2 | import path from "path";
3 | import Utils from '@/utils/utils'
4 | const sqlite3 = require("sqlite3").verbose();
5 |
6 | // const isBuild = process.env.NODE_ENV === 'production'; //是否为生产环境
7 | // const resPath = path.join(process.cwd(),'resources');//打包后应用根目录下resources目录
8 | // const srcPath = path.join(process.cwd(),'src','appsrc'); //项目资源目录,里面存放拷贝到打包后应用根目录的文件
9 |
10 | // const voicerDbPath = isBuild ? path.join(resPath,'voicer.db') : path.join(srcPath,'voicer.db');
11 | // const musicDbPath = isBuild ? path.join(resPath,'music.db') : path.join(srcPath,'music.db');
12 |
13 | const voicerDbPath = path.join(Utils.getSrcPath(),'voicer.db');
14 | const musicDbPath = path.join(Utils.getSrcPath(),'music.db');
15 |
16 | class DBTools {
17 | // 获取主播列表模型
18 | static getVoicerModel() {
19 | // 链接数据库
20 | const sequelize = new Sequelize({
21 | dialectModule: sqlite3, //electron必须这样配置,否则报错
22 | dialect: "sqlite",
23 | storage: voicerDbPath,
24 | logging: false,
25 | });
26 | // 初始化表模型
27 | const Voicer = sequelize.define(
28 | "Voicer",
29 | {
30 | // 主播名称(示例:小云)
31 | name: {
32 | type: DataTypes.STRING,
33 | allowNull: false,
34 | },
35 | // 主播别名(示例:xiaoyun)
36 | alias: {
37 | type: DataTypes.STRING,
38 | allowNull: false,
39 | },
40 | // 主播类型(示例:标准女声)
41 | type: {
42 | type: DataTypes.STRING,
43 | allowNull: false,
44 | },
45 | // 适用场景(示例:通用场景)
46 | scene: {
47 | type: DataTypes.STRING,
48 | allowNull: false,
49 | },
50 | },
51 | {
52 | // 这是其他模型参数
53 | }
54 | );
55 | // 同步表模型
56 | // Voicer.sync();
57 | // console.log("同步表模型完毕!");
58 | return Voicer;
59 | }
60 |
61 | // 获取音乐列表模型
62 | static getMusicModel() {
63 | // 链接数据库
64 | const sequelize = new Sequelize({
65 | dialectModule: sqlite3, //electron必须这样配置,否则报错
66 | dialect: "sqlite",
67 | storage: musicDbPath,
68 | logging: false,
69 | });
70 | // 初始化表模型
71 | const Music = sequelize.define("Music", {
72 | // 音乐名称(示例:元旦)
73 | name: {
74 | type: DataTypes.STRING,
75 | allowNull: false,
76 | },
77 | // 音乐类别(示例:彩铃配音)
78 | category: {
79 | type: DataTypes.STRING,
80 | allowNull: false,
81 | },
82 | });
83 | // 同步表模型
84 | // await Music.sync();
85 | // console.log("同步表模型完毕!");
86 | return Music;
87 | }
88 |
89 | // 查询所有
90 | static async selectAall(model) {
91 | const data = await model.findAll();
92 | console.log("-------------------------");
93 | console.log(JSON.stringify(data, null, 2));
94 | console.log("-------------------------");
95 | }
96 | }
97 |
98 | export default DBTools;
99 |
--------------------------------------------------------------------------------
/src/background.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | import { autoUpdater } from "electron-updater"
4 | import path from "path";
5 | import { app, protocol, BrowserWindow, Menu } from "electron";
6 | import { createProtocol } from "vue-cli-plugin-electron-builder/lib";
7 | // import installExtension, { VUEJS_DEVTOOLS } from "electron-devtools-installer";
8 | const isDevelopment = process.env.NODE_ENV !== "production";
9 | const Store = require('electron-store');
10 | Store.initRenderer()
11 |
12 |
13 | let win;
14 |
15 | // ============ 限制软件多开代码--start ====================
16 | const gotTheLock = app.requestSingleInstanceLock();
17 |
18 | if (!gotTheLock) {
19 | app.quit();
20 | } else {
21 | app.on("second-instance", (event, commandLine, workingDirectory) => {
22 | // 当运行第二个实例时,将会聚焦到myWindow这个窗口
23 | if (win) {
24 | if (win.isMinimized()) win.restore();
25 | win.focus();
26 | }
27 | });
28 | // ============ 限制软件多开代码--end ====================
29 |
30 | protocol.registerSchemesAsPrivileged([{ scheme: "app", privileges: { secure: true, standard: true } }]);
31 |
32 | async function createWindow() {
33 | win = new BrowserWindow({
34 | width: 1024,
35 | height: 768,
36 | webPreferences: {
37 | enableRemoteModule: true, //开启远程模块,未来可能删除(添加右键菜单会有警告)
38 | // nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
39 | nodeIntegration: true,
40 | webSecurity: false, //使其可以播放音频
41 | },
42 | icon: path.join(__static, "icon.png"),
43 |
44 | });
45 |
46 |
47 | if (process.env.WEBPACK_DEV_SERVER_URL) {
48 | await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL);
49 | win.setTitle('吾爱破解(作者:bawangxx)')
50 | if (!process.env.IS_TEST) win.webContents.openDevTools();
51 | } else {
52 | //正式环境设置
53 | Menu.setApplicationMenu(null); // 移除顶部菜单
54 | createProtocol("app");
55 | await win.loadURL("app://./index.html");
56 | win.setTitle('吾爱破解(作者:bawangxx)');
57 | autoUpdater.checkForUpdatesAndNotify();
58 | }
59 | }
60 |
61 | app.on("window-all-closed", () => {
62 | app.quit();
63 | });
64 |
65 | app.on("activate", () => {
66 | if (BrowserWindow.getAllWindows().length === 0) createWindow();
67 | });
68 |
69 | app.on("ready", async () => {
70 | // if (isDevelopment && !process.env.IS_TEST) {
71 | // // Install Vue Devtools
72 | // try {
73 | // await installExtension(VUEJS_DEVTOOLS);
74 | // } catch (e) {
75 | // console.error("Vue Devtools failed to install:", e.toString());
76 | // }
77 | // }
78 | console.log(app.getAppPath());
79 | createWindow();
80 | });
81 |
82 | if (isDevelopment) {
83 | if (process.platform === "win32") {
84 | process.on("message", (data) => {
85 | if (data === "graceful-exit") {
86 | app.quit();
87 | }
88 | });
89 | } else {
90 | process.on("SIGTERM", () => {
91 | app.quit();
92 | });
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/TestCode/demo4.js:
--------------------------------------------------------------------------------
1 | const { Sequelize, DataTypes, Model } = require("sequelize");
2 | const jsonfile = require("jsonfile");
3 | // import path from "path";
4 | import { Sequelize, DataTypes, Model } from "sequelize"
5 |
6 |
7 | // 获取主播列表模型
8 | async function getVoicerModel(){
9 | // 链接数据库
10 | const sequelize = new Sequelize({
11 | dialect: "sqlite",
12 | storage: "./voicer.db",
13 | logging: false
14 | });
15 | // 初始化表模型
16 | const Voicer = sequelize.define(
17 | "Voicer",
18 | {
19 | // 主播名称(示例:小云)
20 | name: {
21 | type: DataTypes.STRING,
22 | allowNull: false,
23 | },
24 | // 主播别名(示例:xiaoyun)
25 | alias: {
26 | type: DataTypes.STRING,
27 | allowNull: false,
28 | },
29 | // 主播类型(示例:标准女声)
30 | type: {
31 | type: DataTypes.STRING,
32 | allowNull: false,
33 | },
34 | // 适用场景(示例:通用场景)
35 | scene: {
36 | type: DataTypes.STRING,
37 | allowNull: false,
38 | },
39 | },
40 | {
41 | // 这是其他模型参数
42 | }
43 | );
44 | // 同步表模型
45 | await Voicer.sync();
46 | console.log("同步表模型完毕!");
47 | return Voicer;
48 | }
49 |
50 |
51 |
52 | // 插入数据
53 | async function insertVoicer(model) {
54 | const file = "./voicer.json";
55 | const data = jsonfile.readFileSync(file);
56 | data.forEach( async element => {
57 | // console.log(element)
58 | await model.create(element);
59 | });
60 |
61 | console.log("插入数据完毕!");
62 | }
63 |
64 | // 查询所有
65 | async function selectAall(model) {
66 | const data = await model.findAll();
67 | console.log('-------------------------');
68 | console.log(JSON.stringify(data, null, 2));
69 | console.log('-------------------------');
70 | }
71 |
72 | //查询特定属性
73 | async function selectForProperty() {
74 | console.log("-----------------------");
75 | const voicerlist = await Voicer.findAll({
76 | attributes: ["name", "alias"],
77 | });
78 | console.log(JSON.stringify(voicerlist, null, 2));
79 | console.log("-----------------------");
80 | }
81 |
82 | // 条件查询
83 | async function whereQuery(model) {
84 | const dataList = await model.findAll({
85 | where: {
86 | type: "标准女声",
87 | },
88 | });
89 | console.log(JSON.stringify(dataList,null,2));
90 | }
91 |
92 | // 分页查询
93 | async function pageQuery(model){
94 | const page = 2; //第几页
95 | const pageNum = 2; //每页数量
96 | const dataList = await model.findAll({
97 | where: {
98 | type: "标准女声",
99 | },
100 | offset: (page-1) * pageNum,
101 | limit: pageNum
102 | });
103 | console.log(JSON.stringify(dataList,null,2));
104 | }
105 |
106 | // 删除表
107 | async function deleteTable(model){
108 | await model.drop();
109 | console.log("用户表已删除!");
110 | }
111 |
112 | (async () => {
113 |
114 | const voicer = await getVoicerModel();
115 | pageQuery(voicer); // 分页查询
116 | // whereQuery(voicer); // 条件查询
117 | // selectAall(voicer); // 查询所有
118 | // insertVoicer(voicer); // 插入数据
119 | // deleteTable(voicer); //删除表
120 |
121 | })();
122 |
--------------------------------------------------------------------------------
/src/TestCode/voicer.json:
--------------------------------------------------------------------------------
1 | [
2 | { "name": "小云", "alias": "Xiaoyun", "type": "标准女声", "scene": "通用场景" },
3 | { "name": "小刚", "alias": "Xiaogang", "type": "标准男声", "scene": "通用场景" },
4 | { "name": "若兮", "alias": "Ruoxi", "type": "温柔女声", "scene": "通用场景" },
5 | { "name": "思琪", "alias": "Siqi", "type": "温柔女声", "scene": "通用场景" },
6 | { "name": "思佳", "alias": "Sijia", "type": "标准女声", "scene": "通用场景" },
7 | { "name": "思诚", "alias": "Sicheng", "type": "标准男声", "scene": "通用场景" },
8 | { "name": "艾琪", "alias": "Aiqi", "type": "温柔女声", "scene": "通用场景" },
9 | { "name": "艾佳", "alias": "Aijia", "type": "标准女声", "scene": "通用场景" },
10 | { "name": "艾诚", "alias": "Aicheng", "type": "标准男声", "scene": "通用场景" },
11 | { "name": "艾达", "alias": "Aida", "type": "标准男声", "scene": "通用场景" },
12 | { "name": "宁儿", "alias": "Ninger", "type": "标准女声", "scene": "通用场景" },
13 | { "name": "瑞琳", "alias": "Ruilin", "type": "标准女声", "scene": "通用场景" },
14 | { "name": "思悦", "alias": "Siyue", "type": "温柔女声", "scene": "客服场景" },
15 | { "name": "艾雅", "alias": "Aiya", "type": "严厉女声", "scene": "客服场景" },
16 | { "name": "艾夏", "alias": "Aixia", "type": "亲和女声", "scene": "客服场景" },
17 | { "name": "艾美", "alias": "Aimei", "type": "甜美女声", "scene": "客服场景" },
18 | { "name": "艾雨", "alias": "Aiyu", "type": "自然女声", "scene": "客服场景" },
19 | { "name": "艾悦", "alias": "Aiyue", "type": "温柔女声", "scene": "客服场景" },
20 | { "name": "艾婧", "alias": "Aijing", "type": "严厉女声", "scene": "客服场景" },
21 | { "name": "小美", "alias": "Xiaomei", "type": "甜美女声", "scene": "客服场景" },
22 | { "name": "艾娜", "alias": "Aina", "type": "浙普女声", "scene": "客服场景" },
23 | { "name": "伊娜", "alias": "Yina", "type": "浙普女声", "scene": "客服场景" },
24 | { "name": "思婧", "alias": "Sijing", "type": "严厉女声", "scene": "客服场景" },
25 | { "name": "思彤", "alias": "Sitong", "type": "儿童音", "scene": "童声场景" },
26 | { "name": "小北", "alias": "Xiaobei", "type": "萝莉女声", "scene": "童声场景" },
27 | { "name": "艾彤", "alias": "Aitong", "type": "儿童音", "scene": "童声场景" },
28 | { "name": "艾薇", "alias": "Aiwei", "type": "萝莉女声", "scene": "童声场景" },
29 | { "name": "艾宝", "alias": "Aibao", "type": "萝莉女声", "scene": "童声场景" },
30 | { "name": "Harry", "alias": "Harry", "type": "英音男声", "scene": "英文场景" },
31 | { "name": "Abby", "alias": "Abby", "type": "美音女声", "scene": "英文场景" },
32 | { "name": "Andy", "alias": "Andy", "type": "美音男声", "scene": "英文场景" },
33 | { "name": "Eric", "alias": "Eric", "type": "英音男声", "scene": "英文场景" },
34 | { "name": "Emily", "alias": "Emily", "type": "英音女声", "scene": "英文场景" },
35 | { "name": "Luna", "alias": "Luna", "type": "英音女声", "scene": "英文场景" },
36 | { "name": "Luca", "alias": "Luca", "type": "英音男声", "scene": "英文场景" },
37 | { "name": "Wendy", "alias": "Wendy", "type": "英音女声", "scene": "英文场景" },
38 | { "name": "William", "alias": "William", "type": "英音男声", "scene": "英文场景" },
39 | { "name": "Olivia", "alias": "Olivia", "type": "英音女声", "scene": "英文场景" },
40 | { "name": "姗姗", "alias": "Shanshan", "type": "粤语女声", "scene": "方言场景" },
41 | { "name": "小玥", "alias": "Xiaoyue", "type": "四川话女声", "scene": "方言场景" },
42 | { "name": "Lydia", "alias": "Lydia", "type": "英中双语女声", "scene": "英文场景" },
43 | { "name": "艾硕", "alias": "Aishuo", "type": "自然男声", "scene": "客服场景" },
44 | { "name": "青青", "alias": "Qingqing", "type": "台湾话女声", "scene": "方言场景" },
45 | { "name": "翠姐", "alias": "Cuijie", "type": "东北话女声", "scene": "方言场景" },
46 | { "name": "小泽", "alias": "Xiaoze", "type": "湖南重口音男声", "scene": "方言场景" }
47 | ]
48 |
--------------------------------------------------------------------------------
/src/TestCode/music.json:
--------------------------------------------------------------------------------
1 | [
2 | { "name": "元旦", "category": "全部"},
3 | { "name": "喜气洋洋共贺新年", "category": "全部"},
4 | { "name": "舒缓柔和节日祝福2", "category": "全部"},
5 | { "name": "舒缓柔和节日祝福1", "category": "全部"},
6 | { "name": "舒缓柔和节日祝福", "category": "全部"},
7 | { "name": "经典晚会开场", "category": "全部"},
8 | { "name": "经典萨克斯配乐", "category": "全部"},
9 | { "name": "经典节日祝福配乐1", "category": "全部"},
10 | { "name": "经典节日祝福配乐", "category": "全部"},
11 | { "name": "经典交响乐-纯音乐", "category": "全部"},
12 | { "name": "经典交响乐1-纯音乐", "category": "全部"},
13 | { "name": "金蛇狂舞-纯音乐", "category": "全部"},
14 | { "name": "欢快温馨-纯音乐", "category": "全部"},
15 | { "name": "恭喜发财-纯音乐", "category": "全部"},
16 | { "name": "大型节日晚会配乐2", "category": "全部"},
17 | { "name": "大型节日晚会配乐1", "category": "全部"},
18 | { "name": "大型节日晚会配乐", "category": "全部"},
19 | { "name": "春节序曲-纯音乐", "category": "全部"},
20 | { "name": "大型颁奖晚会配乐", "category": "彩铃配音"},
21 | { "name": "动感大气纯音乐", "category": "彩铃配音"},
22 | { "name": "动感大气纯音乐1", "category": "彩铃配音"},
23 | { "name": "动感大气纯音乐2", "category": "彩铃配音"},
24 | { "name": "激动人心-纯音乐", "category": "彩铃配音"},
25 | { "name": "紧张刺激纯音乐", "category": "彩铃配音"},
26 | { "name": "紧张刺激纯音乐1", "category": "彩铃配音"},
27 | { "name": "紧张刺激纯音乐2", "category": "彩铃配音"},
28 | { "name": "经典欢快抒情纯音乐", "category": "彩铃配音"},
29 | { "name": "经典交响曲配乐", "category": "彩铃配音"},
30 | { "name": "经典交响曲配乐1", "category": "彩铃配音"},
31 | { "name": "经典交响曲配乐2", "category": "彩铃配音"},
32 | { "name": "开场曲大气抒情", "category": "彩铃配音"},
33 | { "name": "气势磅礴大气纯乐", "category": "彩铃配音"},
34 | { "name": "气势磅礴大气纯乐1", "category": "彩铃配音"},
35 | { "name": "气势磅礴大气纯乐2", "category": "彩铃配音"},
36 | { "name": "神话-再入天宫纯音乐", "category": "彩铃配音"},
37 | { "name": "太阳和星星-纯音乐", "category": "彩铃配音"},
38 | { "name": "安静舒缓-纯音乐", "category": "广告促销"},
39 | { "name": "北京北京钢琴曲", "category": "广告促销"},
40 | { "name": "匆匆那年钢琴曲", "category": "广告促销"},
41 | { "name": "欢快吉他弹奏-纯音乐", "category": "广告促销"},
42 | { "name": "缓慢抒情-钢琴曲", "category": "广告促销"},
43 | { "name": "缓慢抒情-钢琴曲1", "category": "广告促销"},
44 | { "name": "老鹰之歌-纯音乐", "category": "广告促销"},
45 | { "name": "梁祝-纯音乐", "category": "广告促销"},
46 | { "name": "美丽的神话钢琴曲", "category": "广告促销"},
47 | { "name": "南山南钢琴曲-纯音乐", "category": "广告促销"},
48 | { "name": "轻快有节奏-钢琴曲", "category": "广告促销"},
49 | { "name": "抒情唯美钢琴+萨克斯", "category": "广告促销"},
50 | { "name": "抒情唯美钢琴曲目1", "category": "广告促销"},
51 | { "name": "抒情唯美钢琴曲目2", "category": "广告促销"},
52 | { "name": "舒缓节奏钢琴曲1", "category": "广告促销"},
53 | { "name": "舒缓节奏钢琴曲2", "category": "广告促销"},
54 | { "name": "因为爱情钢琴曲", "category": "广告促销"},
55 | { "name": "Hiphop动感音乐", "category": "节日祝福"},
56 | { "name": "Time-MKJ", "category": "节日祝福"},
57 | { "name": "动感DJ舞曲配乐", "category": "节日祝福"},
58 | { "name": "抖音经典配乐", "category": "节日祝福"},
59 | { "name": "欢快动感配乐1", "category": "节日祝福"},
60 | { "name": "欢快动感配乐2", "category": "节日祝福"},
61 | { "name": "节奏动感配乐1", "category": "节日祝福"},
62 | { "name": "经典广告促销配乐", "category": "节日祝福"},
63 | { "name": "经典广告促销配乐2", "category": "节日祝福"},
64 | { "name": "经典节奏动感-纯音乐", "category": "节日祝福"},
65 | { "name": "经典萨克斯-纯音乐", "category": "节日祝福"},
66 | { "name": "龙电天下", "category": "节日祝福"},
67 | { "name": "沙漠骆驼", "category": "节日祝福"},
68 | { "name": "抒情经典配乐", "category": "节日祝福"},
69 | { "name": "甩葱歌", "category": "节日祝福"},
70 | { "name": "玩腻", "category": "节日祝福"},
71 | { "name": "愉快的周末-纯音乐", "category": "节日祝福"},
72 | { "name": "最炫民族风", "category": "节日祝福"},
73 | { "name": "抒情感人纯音乐", "category": "抒情唯美"},
74 | { "name": "抒情感人纯音乐1", "category": "抒情唯美"},
75 | { "name": "抒情舒缓大自然", "category": "抒情唯美"},
76 | { "name": "舒缓温馨-纯音乐", "category": "抒情唯美"},
77 | { "name": "唯美欢快钢琴曲", "category": "抒情唯美"},
78 | { "name": "唯美欢快钢琴曲1", "category": "抒情唯美"},
79 | { "name": "唯美欢快钢琴曲2", "category": "抒情唯美"},
80 | { "name": "夜的钢琴曲-纯音乐", "category": "抒情唯美"},
81 | { "name": "缓慢抒情纯音乐2", "category": "抒情唯美"},
82 | { "name": "经典抒情钢琴曲", "category": "抒情唯美"},
83 | { "name": "经典抒情钢琴曲1", "category": "抒情唯美"},
84 | { "name": "柔和抒情纯音乐", "category": "抒情唯美"},
85 | { "name": "未闻花名钢琴曲", "category": "抒情唯美"},
86 | { "name": "温馨感人钢琴曲", "category": "抒情唯美"},
87 | { "name": "温馨感人钢琴曲2", "category": "抒情唯美"}
88 | ]
89 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
20 |
21 |
22 |
23 |
24 | {{softName}} v{{ currentVersion }}
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
112 |
113 |
163 |
--------------------------------------------------------------------------------
/src/views/Convert/SelectVoicer.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | 试听
16 | 使用
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
131 |
132 |
144 |
--------------------------------------------------------------------------------
/src/views/Convert/SelectMusic.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | 试听
16 | 使用
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | 文件路径:
29 |
30 |
31 | 选择文件
32 |
33 |
34 | 使用自定义背景音乐
35 | 不使用背景音乐
36 |
37 | 确定
38 |
39 |
40 |
41 |
42 |
43 |
166 |
167 |
179 |
--------------------------------------------------------------------------------
/src/views/Convert/api/alibaba.js:
--------------------------------------------------------------------------------
1 | const kitx = require("kitx");
2 | const got = require("got");
3 | import Utils from "@/utils/utils";
4 | const path = require("path");
5 | // const request = require("request");
6 | const fs = require("fs");
7 | const stream = require("stream");
8 | const { promisify } = require("util");
9 | const pipeline = promisify(stream.pipeline);
10 | const fse = require('fs-extra');
11 | const Store = require("electron-store");
12 | const store = new Store();
13 |
14 | class AlibabaAPI {
15 |
16 | static AccessKeyId = '';
17 | static AccessKeySecret = '';
18 | static appkey = '';
19 |
20 | // key设置
21 | static setAliKey(){
22 | const keyObj = store.get("set.key");
23 | if(keyObj){
24 | console.log('---------使用自定义key----------')
25 | this.AccessKeyId = keyObj.accessKeyId;
26 | this.AccessKeySecret = keyObj.accessKeySecret;
27 | this.appkey = keyObj.appkey;
28 | }else{
29 | console.log('---------使用内部key----------')
30 | this.AccessKeyId = '设置成你在阿里云申请的:AccessKeyId';
31 | this.AccessKeySecret = '设置成你在阿里云申请的:AccessKeySecret';
32 | this.appkey = '设置成你在阿里云申请的:appkey';
33 |
34 | }
35 | }
36 |
37 | // 获取时间戳
38 | static timestamp() {
39 | const date = new Date();
40 | const YYYY = date.getUTCFullYear();
41 | const MM = kitx.pad2(date.getUTCMonth() + 1);
42 | const DD = kitx.pad2(date.getUTCDate());
43 | const HH = kitx.pad2(date.getUTCHours());
44 | const mm = kitx.pad2(date.getUTCMinutes());
45 | const ss = kitx.pad2(date.getUTCSeconds());
46 | // 删除掉毫秒部分
47 | return `${YYYY}-${MM}-${DD}T${HH}:${mm}:${ss}Z`;
48 | }
49 |
50 | // url编码
51 | static encode(str) {
52 | const result = encodeURIComponent(str);
53 |
54 | return result
55 | .replace(/!/g, "%21")
56 | .replace(/'/g, "%27")
57 | .replace(/\(/g, "%28")
58 | .replace(/\)/g, "%29")
59 | .replace(/\*/g, "%2A");
60 | }
61 |
62 | // 获取Token
63 | static async getToken() {
64 | const token = store.get('token',null);
65 | const appkey = store.get('appkey','');
66 | if (token && this.appkey == appkey) {
67 | const nowTime = Math.round(new Date().getTime() / 1000); //十位时间戳(精确到秒)
68 | if (nowTime < token.ExpireTime) {
69 | console.log('---------本地返回token----------')
70 | return token.Id;
71 | }
72 | }
73 | const Timestamp = this.encode(this.timestamp());
74 | const SignatureNonce = kitx.makeNonce();
75 | //规范化的请求字符串
76 | const query_string = `AccessKeyId=${this.AccessKeyId}&Action=CreateToken&Format=JSON&RegionId=cn-shanghai&SignatureMethod=HMAC-SHA1&SignatureNonce=${SignatureNonce}&SignatureVersion=1.0&Timestamp=${Timestamp}&Version=2019-02-28`;
77 |
78 | //构造待签名字符串
79 | const stringToSign = `GET&${this.encode("/")}&${this.encode(query_string)}`;
80 |
81 | //计算签名
82 | const key = this.AccessKeySecret + "&";
83 | const signature = kitx.sha1(stringToSign, key, "base64");
84 | const Signature = this.encode(signature);
85 |
86 | //调用服务
87 | const full_url = `http://nls-meta.cn-shanghai.aliyuncs.com/?Signature=${Signature}&${query_string}`;
88 | const res = await got(full_url);
89 | if (res.statusCode == 200) {
90 | const data = JSON.parse(res.body);
91 | store.set('token',data.Token);
92 | store.set('appkey',this.appkey);
93 | console.log('---------网络获取token----------')
94 | return data.Token.Id;
95 | }
96 | return null;
97 | }
98 |
99 | // 按字数切分文本
100 | static splitLongText_back(text, size) {
101 | //先按标点符号切分
102 | let texts = text.split(/[、,。;?!,!\\?\s]/);
103 | let textPart = "";
104 | let result = [];
105 | let len = 0;
106 | //再按size merge,避免标点符号切分出来的太短
107 | for (let i = 0; i < texts.length; i++) {
108 | if (textPart.length + texts[i].length + 1 > size) {
109 | result.push(textPart.toString());
110 | textPart = "";
111 | }
112 | textPart = textPart + texts[i];
113 | len += texts[i].length;
114 | if (len < text.length) {
115 | textPart = textPart + text.charAt(len);
116 | len += 1;
117 | }
118 | }
119 |
120 | if (textPart.length > 0) {
121 | result.push(textPart.toString());
122 | }
123 | return result;
124 | }
125 |
126 | // 截取指定长度字符串,中文按2个长度计算
127 | static getSubString(str, len) {
128 | let strlen = 0;
129 | let s = "";
130 | for (let i = 0; i < str.length; i++) {
131 | if (str.charCodeAt(i) > 128) {
132 | strlen += 2;
133 | } else {
134 | strlen++;
135 | }
136 | s += str.charAt(i);
137 | if (strlen >= len) {
138 | return s;
139 | }
140 | }
141 | return s;
142 | }
143 |
144 | // 根据指定长度均分文本
145 | static meanLongText(longText,size){
146 | let strlen = 0;
147 | for (let i = 0; i < longText.length; i++) {
148 | if (longText.charCodeAt(i) > 128) {
149 | strlen += 2;
150 | } else {
151 | strlen++;
152 | }
153 | }
154 |
155 | const zhengShu = parseInt(strlen/size);
156 | const yushu = strlen % size
157 | let resArr = [];
158 | for (let index = 0; index < zhengShu; index++) {
159 | const subStr = this.getSubString(longText,size);
160 | resArr.push(subStr);
161 | longText = longText.replace(subStr,'')
162 | }
163 | const subStr = this.getSubString(longText,yushu);
164 | if(subStr != '') resArr.push(subStr);
165 | return resArr;
166 | }
167 |
168 | // 按字数切分文本
169 | static splitLongText(text, size) {
170 | //先按标点符号切分
171 | let texts = text.split(/[、,。;?!,!\\?\s]/);
172 | let textPart = "";
173 | let result = [];
174 | let len = 0;
175 | //再按size merge,避免标点符号切分出来的太短
176 | for (let i = 0; i < texts.length; i++) {
177 | if (textPart.length + texts[i].length + 1 > size) {
178 | if(textPart != ""){
179 | result.push(textPart.toString());
180 | }
181 | textPart = "";
182 | }
183 | textPart = textPart + texts[i];
184 | len += texts[i].length;
185 | if (len < text.length) {
186 | textPart = textPart + text.charAt(len);
187 | len += 1;
188 | }
189 | }
190 |
191 | if (textPart.length > 0) {
192 | result.push(textPart.toString());
193 | }
194 |
195 | if(textPart.length > 0 && textPart.length > size){
196 | let result = [];
197 | result = result.concat(this.meanLongText(textPart,size));
198 | return result;
199 | }
200 |
201 | return result;
202 | }
203 |
204 | // 循环转换长文本
205 | static async processGETRequest_longText(params) {
206 | const { token, longText, audioSaveFile, format, sampleRate, volume, speech_rate, voice } = params;
207 | let url = "https://nls-gateway.cn-shanghai.aliyuncs.com/stream/v1/tts";
208 | /**
209 | * 设置URL请求参数。
210 | */
211 | url = url + "?appkey=" + this.appkey;
212 | url = url + "&token=" + token;
213 | // url = url + '&text=' + text;
214 | url = url + "&format=" + format;
215 | url = url + "&sample_rate=" + sampleRate;
216 | // voice 发音人,可选,默认是xiaoyun。
217 | url = url + "&voice=" + voice;
218 | // volume 音量,范围是0~100,可选,默认50。
219 | url = url + "&volume=" + volume;
220 | // speech_rate 语速,范围是-500~500,可选,默认是0。
221 | url = url + "&speech_rate=" + speech_rate;
222 | // pitch_rate 语调,范围是-500~500,可选,默认是0。
223 | // url = url + "&pitch_rate=" + 0;
224 |
225 | let textArr = this.splitLongText(longText, 150);
226 | fse.removeSync(audioSaveFile);
227 |
228 | for (let index = 0; index < textArr.length; index++) {
229 | const text = textArr[index];
230 | const textUrlEncode = encodeURIComponent(text).replace(/[!'()*]/g, function(c) {
231 | return "%" + c.charCodeAt(0).toString(16);
232 | });
233 | const rqURL = url + "&text=" + textUrlEncode;
234 | await pipeline(got.stream(rqURL), fs.createWriteStream(audioSaveFile,{ 'flags': 'a' }));
235 | }
236 | }
237 |
238 | }
239 |
240 | export default AlibabaAPI;
241 |
--------------------------------------------------------------------------------
/src/views/Convert/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | 语音类型:
24 | {{ voicer.name }} / {{ voicer.type }}
25 | 背景音乐:
26 | {{ music.name }}
27 |
28 |
29 |
30 | 音量:
31 |
32 |
33 |
34 | 语速:
35 |
36 |
37 |
38 | 背景音量:
39 |
40 |
41 |
42 |
43 | 输出格式:
44 | MP3
45 | WAV
46 |
47 |
48 |
49 | 保存目录:
50 |
51 | 更改目录
52 | 打开目录
53 |
54 |
55 |
56 |
57 |
58 | 试听一下
59 | 开始转换
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
330 |
331 |
390 |
--------------------------------------------------------------------------------