├── .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 | -------------------------------------------------------------------------------- /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 | [![screen](https://raw.githubusercontent.com/bawangxx/xz_voice/main/images/screen.png)](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 | 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 | 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 | 35 | 36 | 112 | 113 | 163 | -------------------------------------------------------------------------------- /src/views/Convert/SelectVoicer.vue: -------------------------------------------------------------------------------- 1 | 28 | 131 | 132 | 144 | -------------------------------------------------------------------------------- /src/views/Convert/SelectMusic.vue: -------------------------------------------------------------------------------- 1 | 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 | 69 | 70 | 330 | 331 | 390 | --------------------------------------------------------------------------------