diff --git a/.eslintrc.js b/.eslintrc.js index b3f6f5a712..c21c94b88d 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -42,6 +42,12 @@ module.exports = { ignoreRestSiblings: true, }, ], + "vue/component-tags-order": [ + "error", + { + order: ["template", "script", "style"], + }, + ], }, overrides: [ { diff --git a/.gitattributes b/.gitattributes index 33009b3a71..026a17a838 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,3 @@ src/openapi/**/* linguist-generated=true openapi.json linguist-generated=true +*.woff2 linguist-vendored=true diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9b2df77401..408013bcff 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,8 +22,8 @@ on: env: VOICEVOX_ENGINE_REPO_URL: "https://github.com/VOICEVOX/voicevox_engine" - VOICEVOX_ENGINE_VERSION: 0.13.3 - VOICEVOX_RESOURCE_VERSION: 0.13.3 + VOICEVOX_ENGINE_VERSION: 0.14.0-preview.8 + VOICEVOX_RESOURCE_VERSION: 0.14.0-preview.0 VOICEVOX_EDITOR_VERSION: |- # releaseタグ名か、workflow_dispatchでのバージョン名か、999.999.999が入る ${{ github.event.release.tag_name || github.event.inputs.version || '999.999.999' }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0f098bdaff..1fbbcb38ee 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,7 +4,7 @@ on: push: pull_request: branches: - - '**' + - "**" workflow_dispatch: jobs: @@ -46,7 +46,21 @@ jobs: restore-keys: | ${{ env.cache-version }}-${{ runner.os }}--electron-builder-cache- + - name: Cache node_modules + uses: actions/cache@v3 + id: cache-node-modules + with: + path: node_modules + key: ${{ env.cache-version }}-${{ runner.os }}--node-modules-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ env.cache-version }}-${{ runner.os }}--node-modules- + - run: npm ci + if: steps.cache-node-modules.outputs.cache-hit != 'true' + + - name: Disallowed licenses check + run: npm run license:generate -- -o voicevox_licenses.json + - run: npm run typecheck - run: npm run lint - run: npm run markdownlint diff --git a/build/generateLicenses.js b/build/generateLicenses.js index f9909c0e11..26049ef020 100644 --- a/build/generateLicenses.js +++ b/build/generateLicenses.js @@ -7,15 +7,17 @@ const argv = yargs(hideBin(process.argv)) .option("output_path", { alias: "o", demandOption: true, - type: "string" + type: "string", }) .help() .parse(); -const { execSync } = require("child_process"); +const { execFileSync } = require("child_process"); const fs = require("fs"); const tmp = require("tmp"); +const isWindows = process.platform === "win32"; + const customFormat = { name: "", version: "", @@ -24,29 +26,50 @@ const customFormat = { copyright: "", licenseFile: "none", licenseText: "none", - licenseModified: "no" + licenseModified: "no", }; const customFormatFile = tmp.fileSync(); fs.writeFileSync(customFormatFile.name, JSON.stringify(customFormat)); +const disallowedLicenses = [ + "GPL", + "GPL-2.0", + "GPL-3.0", + "AGPL", + "NGPL", +]; + +// On Windows, npm's global packages can be called with the extension `.cmd` or `.ps1`. +// On Linux (bash), they can be called without extensions. +const extension = isWindows ? ".cmd" : ""; + // https://github.com/davglass/license-checker // npm install -g license-checker -const licenseJson = execSync( - `license-checker --production --excludePrivatePackages --json --customPath ${customFormatFile.name}`, +const licenseJson = execFileSync( + `license-checker${extension}`, + [ + "--production", + "--excludePrivatePackages", + "--json", + `--customPath=${customFormatFile.name}`, + `--failOn=${disallowedLicenses.join(";")}`, + ], { - encoding: "utf-8" + encoding: "utf-8", } ); const checkerLicenses = JSON.parse(licenseJson); -const licenses = Object.entries(checkerLicenses).map(([packageName, license]) => ({ - name: license.name, - version: license.version, - license: license.licenses, - text: license.licenseText, -})); +const licenses = Object.entries(checkerLicenses).map( + ([packageName, license]) => ({ + name: license.name, + version: license.version, + license: license.licenses, + text: license.licenseText, + }) +); const outputPath = argv.output_path; fs.writeFileSync(outputPath, JSON.stringify(licenses)); diff --git "a/docs/\343\203\225\343\202\251\343\203\263\343\203\210\343\201\253\343\201\244\343\201\204\343\201\246.md" "b/docs/\343\203\225\343\202\251\343\203\263\343\203\210\343\201\253\343\201\244\343\201\204\343\201\246.md" new file mode 100644 index 0000000000..3b79e7d863 --- /dev/null +++ "b/docs/\343\203\225\343\202\251\343\203\263\343\203\210\343\201\253\343\201\244\343\201\204\343\201\246.md" @@ -0,0 +1,32 @@ +# フォントの作り方 + +VOICEVOX では改変したRounded M+ 1pを使用しています。 +具体的には、 +- ヒント情報の削除 +- ttfからwoff2への変換 +を行っています。 + +## 手順 + +1. [自家製 Rounded M+ とは](http://jikasei.me/font/rounded-mplus/about.html)からRounded M+をダウンロードします。 + +2. [ttfautohint](https://freetype.org/ttfautohint/)をインストールします。 +> **Note** +> [ttfautohint-py](https://pypi.org/project/ttfautohint-py/)を使用しました。 + +3. [woff2](https://github.com/google/woff2)をビルドします。 + +4. `rounded-mplus-20150529.7z`から`rounded-mplus-1p-(ウェイト).ttf`を全て`src/fonts`に解凍します。 +5. ttfautohintを使用して、Rounded M+のヒント情報を削除します。名前は`Unhinted Rounded M+ 1p`とします。 +6. woff2を使用して、ttfからwoff2へ変換します。 + +[#1103](https://github.com/VOICEVOX/voicevox/pull/1103)の作成には以下のスクリプトを使用しました(PowerShell 7.3.1) + +```pwsh +# cwd:src/fonts +foreach ($f in gci("./*.ttf")){ + py -m ttfautohint -dF " Unhinted" $f.name "unhinted-$($f.name)" + woff2_compress.exe "unhinted-$($f.name)" +} +``` + diff --git "a/docs/\347\264\260\343\201\213\343\201\204\350\250\255\350\250\210\346\226\271\351\207\235.md" "b/docs/\347\264\260\343\201\213\343\201\204\350\250\255\350\250\210\346\226\271\351\207\235.md" index 1939bdb97a..0e8d453615 100644 --- "a/docs/\347\264\260\343\201\213\343\201\204\350\250\255\350\250\210\346\226\271\351\207\235.md" +++ "b/docs/\347\264\260\343\201\213\343\201\204\350\250\255\350\250\210\346\226\271\351\207\235.md" @@ -8,13 +8,19 @@ EngineId はエンジンが持つ ID で、世界で唯一かつ不変です。 SpeakerId は話者が持つ ID で、世界で唯一かつ不変。エンジン間でも同じ ID を持ちます。 -StyleId はスタイルごとの ID で、話者ごとに唯一であれば良いです。 +StyleId はスタイルごとの ID で、エンジンごとに唯一であれば良いです。 声を一意に決めるには、(EngineId, SpeakerId, StyleId)の3組が揃っている必要がある、という仕様を目指しています。 現状は、音声合成APIに SpeakerId 引数が無いため、(EngineId, StyleId)の2組で一意に声が決まっています。 +現状は StyleId はエンジンごとに唯一である必要がありますが、話者ごとに唯一であれば良いという仕様を目指しています。 VOICEVOX は歴史的経緯により、 SpeakerId と StyleId が混同していることがあります。 特に型が整数値になっている SpeakerId は StyleId と混同している場合があります。 (エンジン API の SpeakerId 引数に StyleId を渡したりなど。) StyleId は現在整数値型になっていますが、将来的にはUuidにしたいと考えています。 + +## シングルファイルコンポーネント(SFC、`.vue`ファイル)のtemplate、script、styleの順序 + +` - diff --git a/src/components/AudioCell.vue b/src/components/AudioCell.vue index adf5949b09..3782232b48 100644 --- a/src/components/AudioCell.vue +++ b/src/components/AudioCell.vue @@ -275,6 +275,7 @@ export default defineComponent({ await store.dispatch("COMMAND_REGISTER_AUDIO_ITEM", { audioItem, prevAudioKey: props.audioKey, + applyPreset: true, }); moveDownCell(); }; diff --git a/src/components/CharacterPortrait.vue b/src/components/CharacterPortrait.vue index c8651324e2..eaa57159d5 100644 --- a/src/components/CharacterPortrait.vue +++ b/src/components/CharacterPortrait.vue @@ -40,17 +40,23 @@ export default defineComponent({ return store.getters.CHARACTER_INFO(engineId, styleId); }); - const characterName = computed(() => { + const styleInfo = computed(() => { const activeAudioKey = store.getters.ACTIVE_AUDIO_KEY; + const audioItem = activeAudioKey ? store.state.audioItems[activeAudioKey] : undefined; + const styleId = audioItem?.styleId; const style = characterInfo.value?.metas.styles.find( (style) => style.styleId === styleId ); - return style?.styleName - ? `${characterInfo.value?.metas.speakerName} (${style?.styleName})` + return style; + }); + + const characterName = computed(() => { + return styleInfo.value?.styleName + ? `${characterInfo.value?.metas.speakerName} (${styleInfo.value?.styleName})` : characterInfo.value?.metas.speakerName; }); @@ -60,11 +66,14 @@ export default defineComponent({ ? store.state.audioItems[activeAudioKey] : undefined; const engineId = audioItem?.engineId ?? store.state.engineIds[0]; + const engineManifest = store.state.engineManifests[engineId]; const engineInfo = store.state.engineInfos[engineId]; - return engineInfo?.name; + return engineManifest ? engineManifest.brandName : engineInfo.name; }); - const portraitPath = computed(() => characterInfo.value?.portraitPath); + const portraitPath = computed( + () => styleInfo.value?.portraitPath || characterInfo.value?.portraitPath + ); const isInitializingSpeaker = computed(() => { const activeAudioKey = store.getters.ACTIVE_AUDIO_KEY; diff --git a/src/components/EngineManageDialog.vue b/src/components/EngineManageDialog.vue index 9b588a70ef..792b9f99cb 100644 --- a/src/components/EngineManageDialog.vue +++ b/src/components/EngineManageDialog.vue @@ -90,7 +90,9 @@ engineInfos[id].name }} {{ - engineInfos[id].uuid + engineManifests[id] != undefined + ? engineManifests[id].brandName + : engineInfos[id].uuid }} @@ -317,7 +319,7 @@ text-color="display" class="text-no-wrap text-bold q-mr-sm" @click="restartSelectedEngine" - :disable="uiLocked || engineStates[selectedId] !== 'READY'" + :disable="uiLocked || engineStates[selectedId] === 'STARTING'" >再起動 diff --git a/src/components/HelpDialog.vue b/src/components/HelpDialog.vue index a44497447c..daefe711a5 100644 --- a/src/components/HelpDialog.vue +++ b/src/components/HelpDialog.vue @@ -235,6 +235,10 @@ export default defineComponent({ (m) => m.uuid )) { const manifest = store.state.engineManifests[id]; + if (!manifest) { + store.dispatch("LOG_WARN", `manifest not found: ${id}`); + continue; + } data.push( { diff --git a/src/components/HelpPolicy.vue b/src/components/HelpPolicy.vue index aba4053e85..8c0af4c28d 100644 --- a/src/components/HelpPolicy.vue +++ b/src/components/HelpPolicy.vue @@ -4,30 +4,20 @@ - diff --git a/src/components/HowToUse.vue b/src/components/HowToUse.vue index c86ece8450..7ce460c2dc 100644 --- a/src/components/HowToUse.vue +++ b/src/components/HowToUse.vue @@ -4,22 +4,16 @@ - diff --git a/src/components/MenuItem.vue b/src/components/MenuItem.vue index eac85626e2..0e2c2abeca 100644 --- a/src/components/MenuItem.vue +++ b/src/components/MenuItem.vue @@ -60,14 +60,6 @@ - - + + diff --git a/src/components/OssCommunityInfo.vue b/src/components/OssCommunityInfo.vue index 081f9fd1c4..e33e2df2ec 100644 --- a/src/components/OssCommunityInfo.vue +++ b/src/components/OssCommunityInfo.vue @@ -4,24 +4,18 @@ - diff --git a/src/components/QAndA.vue b/src/components/QAndA.vue index 589b3c4678..ca5338248d 100644 --- a/src/components/QAndA.vue +++ b/src/components/QAndA.vue @@ -4,26 +4,18 @@ - diff --git a/src/electron/preload.ts b/src/electron/preload.ts index bb3fd80b57..09cc49793d 100644 --- a/src/electron/preload.ts +++ b/src/electron/preload.ts @@ -174,10 +174,17 @@ const api: Sandbox = { }, logError: (...params) => { + console.error(...params); return ipcRenderer.invoke("LOG_ERROR", ...params); }, + logWarn: (...params) => { + console.warn(...params); + return ipcRenderer.invoke("LOG_WARN", ...params); + }, + logInfo: (...params) => { + console.info(...params); return ipcRenderer.invoke("LOG_INFO", ...params); }, @@ -185,10 +192,6 @@ const api: Sandbox = { return ipcRendererInvoke("ENGINE_INFOS"); }, - restartEngineAll: () => { - return ipcRendererInvoke("RESTART_ENGINE_ALL"); - }, - restartEngine: (engineId: string) => { return ipcRendererInvoke("RESTART_ENGINE", { engineId }); }, diff --git a/src/fonts/rounded-mplus-1p-black.ttf b/src/fonts/rounded-mplus-1p-black.ttf deleted file mode 100644 index e4cee9de3d..0000000000 Binary files a/src/fonts/rounded-mplus-1p-black.ttf and /dev/null differ diff --git a/src/fonts/rounded-mplus-1p-bold.ttf b/src/fonts/rounded-mplus-1p-bold.ttf deleted file mode 100644 index 58edddb840..0000000000 Binary files a/src/fonts/rounded-mplus-1p-bold.ttf and /dev/null differ diff --git a/src/fonts/rounded-mplus-1p-heavy.ttf b/src/fonts/rounded-mplus-1p-heavy.ttf deleted file mode 100644 index eb532c47e6..0000000000 Binary files a/src/fonts/rounded-mplus-1p-heavy.ttf and /dev/null differ diff --git a/src/fonts/rounded-mplus-1p-light.ttf b/src/fonts/rounded-mplus-1p-light.ttf deleted file mode 100644 index 33b05b5bcc..0000000000 Binary files a/src/fonts/rounded-mplus-1p-light.ttf and /dev/null differ diff --git a/src/fonts/rounded-mplus-1p-medium.ttf b/src/fonts/rounded-mplus-1p-medium.ttf deleted file mode 100644 index 212e07c2d1..0000000000 Binary files a/src/fonts/rounded-mplus-1p-medium.ttf and /dev/null differ diff --git a/src/fonts/rounded-mplus-1p-regular.ttf b/src/fonts/rounded-mplus-1p-regular.ttf deleted file mode 100644 index ab40d0d4e2..0000000000 Binary files a/src/fonts/rounded-mplus-1p-regular.ttf and /dev/null differ diff --git a/src/fonts/rounded-mplus-1p-thin.ttf b/src/fonts/rounded-mplus-1p-thin.ttf deleted file mode 100644 index 15eb6fb69f..0000000000 Binary files a/src/fonts/rounded-mplus-1p-thin.ttf and /dev/null differ diff --git a/src/fonts/unhinted-rounded-mplus-1p-black.woff2 b/src/fonts/unhinted-rounded-mplus-1p-black.woff2 new file mode 100644 index 0000000000..bb39d4aeab Binary files /dev/null and b/src/fonts/unhinted-rounded-mplus-1p-black.woff2 differ diff --git a/src/fonts/unhinted-rounded-mplus-1p-bold.woff2 b/src/fonts/unhinted-rounded-mplus-1p-bold.woff2 new file mode 100644 index 0000000000..fd2fc9241f Binary files /dev/null and b/src/fonts/unhinted-rounded-mplus-1p-bold.woff2 differ diff --git a/src/fonts/unhinted-rounded-mplus-1p-heavy.woff2 b/src/fonts/unhinted-rounded-mplus-1p-heavy.woff2 new file mode 100644 index 0000000000..0c51fec417 Binary files /dev/null and b/src/fonts/unhinted-rounded-mplus-1p-heavy.woff2 differ diff --git a/src/fonts/unhinted-rounded-mplus-1p-light.woff2 b/src/fonts/unhinted-rounded-mplus-1p-light.woff2 new file mode 100644 index 0000000000..3f85825263 Binary files /dev/null and b/src/fonts/unhinted-rounded-mplus-1p-light.woff2 differ diff --git a/src/fonts/unhinted-rounded-mplus-1p-medium.woff2 b/src/fonts/unhinted-rounded-mplus-1p-medium.woff2 new file mode 100644 index 0000000000..9e9b7ecc7f Binary files /dev/null and b/src/fonts/unhinted-rounded-mplus-1p-medium.woff2 differ diff --git a/src/fonts/unhinted-rounded-mplus-1p-regular.woff2 b/src/fonts/unhinted-rounded-mplus-1p-regular.woff2 new file mode 100644 index 0000000000..2fcf7c87fe Binary files /dev/null and b/src/fonts/unhinted-rounded-mplus-1p-regular.woff2 differ diff --git a/src/fonts/unhinted-rounded-mplus-1p-thin.woff2 b/src/fonts/unhinted-rounded-mplus-1p-thin.woff2 new file mode 100644 index 0000000000..61a87f67cf Binary files /dev/null and b/src/fonts/unhinted-rounded-mplus-1p-thin.woff2 differ diff --git a/src/openapi/apis/DefaultApi.ts b/src/openapi/apis/DefaultApi.ts index d4eac3a3e2..1e2688cf60 100644 --- a/src/openapi/apis/DefaultApi.ts +++ b/src/openapi/apis/DefaultApi.ts @@ -1,10 +1,10 @@ /* tslint:disable */ /* eslint-disable */ /** - * VOICEVOX ENGINE + * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.7 + * The version of the OpenAPI document: 0.14.0-preview.8 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -101,6 +101,7 @@ export interface ImportUserDictWordsImportUserDictPostRequest { export interface InitializeSpeakerInitializeSpeakerPostRequest { speaker: number; + skipReinit?: boolean; coreVersion?: string; } @@ -400,6 +401,7 @@ export interface DefaultApiInterface { * 指定されたspeaker_idの話者を初期化します。 実行しなくても他のAPIは使用できますが、初回実行時に時間がかかることがあります。 * @summary Initialize Speaker * @param {number} speaker + * @param {boolean} [skipReinit] 既に初期化済みの話者の再初期化をスキップするかどうか * @param {string} [coreVersion] * @param {*} [options] Override http request option. * @throws {RequiredError} @@ -1167,6 +1169,10 @@ export class DefaultApi extends runtime.BaseAPI implements DefaultApiInterface { queryParameters['speaker'] = requestParameters.speaker; } + if (requestParameters.skipReinit !== undefined) { + queryParameters['skip_reinit'] = requestParameters.skipReinit; + } + if (requestParameters.coreVersion !== undefined) { queryParameters['core_version'] = requestParameters.coreVersion; } diff --git a/src/openapi/models/AccentPhrase.ts b/src/openapi/models/AccentPhrase.ts index bffb3efcd5..7eedcd913d 100644 --- a/src/openapi/models/AccentPhrase.ts +++ b/src/openapi/models/AccentPhrase.ts @@ -1,10 +1,10 @@ /* tslint:disable */ /* eslint-disable */ /** - * VOICEVOX ENGINE + * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.7 + * The version of the OpenAPI document: 0.14.0-preview.8 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/src/openapi/models/AudioQuery.ts b/src/openapi/models/AudioQuery.ts index d1fb08611c..01c2bdedcb 100644 --- a/src/openapi/models/AudioQuery.ts +++ b/src/openapi/models/AudioQuery.ts @@ -1,10 +1,10 @@ /* tslint:disable */ /* eslint-disable */ /** - * VOICEVOX ENGINE + * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.7 + * The version of the OpenAPI document: 0.14.0-preview.8 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/src/openapi/models/DownloadableLibrary.ts b/src/openapi/models/DownloadableLibrary.ts index 48c827295b..1596c67ea3 100644 --- a/src/openapi/models/DownloadableLibrary.ts +++ b/src/openapi/models/DownloadableLibrary.ts @@ -1,10 +1,10 @@ /* tslint:disable */ /* eslint-disable */ /** - * VOICEVOX ENGINE + * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.7 + * The version of the OpenAPI document: 0.14.0-preview.8 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/src/openapi/models/EngineManifest.ts b/src/openapi/models/EngineManifest.ts index ed7e4261b8..6284725f39 100644 --- a/src/openapi/models/EngineManifest.ts +++ b/src/openapi/models/EngineManifest.ts @@ -1,10 +1,10 @@ /* tslint:disable */ /* eslint-disable */ /** - * VOICEVOX ENGINE + * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.7 + * The version of the OpenAPI document: 0.14.0-preview.8 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -46,6 +46,12 @@ export interface EngineManifest { * @memberof EngineManifest */ name: string; + /** + * + * @type {string} + * @memberof EngineManifest + */ + brandName: string; /** * * @type {string} @@ -120,6 +126,7 @@ export function EngineManifestFromJSONTyped(json: any, ignoreDiscriminator: bool 'manifestVersion': json['manifest_version'], 'name': json['name'], + 'brandName': json['brand_name'], 'uuid': json['uuid'], 'url': json['url'], 'icon': json['icon'], @@ -144,6 +151,7 @@ export function EngineManifestToJSON(value?: EngineManifest | null): any { 'manifest_version': value.manifestVersion, 'name': value.name, + 'brand_name': value.brandName, 'uuid': value.uuid, 'url': value.url, 'icon': value.icon, diff --git a/src/openapi/models/HTTPValidationError.ts b/src/openapi/models/HTTPValidationError.ts index 6d5d327ba8..9753e3ac64 100644 --- a/src/openapi/models/HTTPValidationError.ts +++ b/src/openapi/models/HTTPValidationError.ts @@ -1,10 +1,10 @@ /* tslint:disable */ /* eslint-disable */ /** - * VOICEVOX ENGINE + * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.7 + * The version of the OpenAPI document: 0.14.0-preview.8 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/src/openapi/models/LicenseInfo.ts b/src/openapi/models/LicenseInfo.ts index 7d29c80131..67eb067e8e 100644 --- a/src/openapi/models/LicenseInfo.ts +++ b/src/openapi/models/LicenseInfo.ts @@ -1,10 +1,10 @@ /* tslint:disable */ /* eslint-disable */ /** - * VOICEVOX ENGINE + * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.7 + * The version of the OpenAPI document: 0.14.0-preview.8 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/src/openapi/models/Mora.ts b/src/openapi/models/Mora.ts index 122f5ccfcb..50bb037ab5 100644 --- a/src/openapi/models/Mora.ts +++ b/src/openapi/models/Mora.ts @@ -1,10 +1,10 @@ /* tslint:disable */ /* eslint-disable */ /** - * VOICEVOX ENGINE + * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.7 + * The version of the OpenAPI document: 0.14.0-preview.8 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/src/openapi/models/ParseKanaBadRequest.ts b/src/openapi/models/ParseKanaBadRequest.ts index ad4059e252..85a3ac2109 100644 --- a/src/openapi/models/ParseKanaBadRequest.ts +++ b/src/openapi/models/ParseKanaBadRequest.ts @@ -1,10 +1,10 @@ /* tslint:disable */ /* eslint-disable */ /** - * VOICEVOX ENGINE + * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.7 + * The version of the OpenAPI document: 0.14.0-preview.8 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/src/openapi/models/Preset.ts b/src/openapi/models/Preset.ts index bace2ba04d..45a82791b5 100644 --- a/src/openapi/models/Preset.ts +++ b/src/openapi/models/Preset.ts @@ -1,10 +1,10 @@ /* tslint:disable */ /* eslint-disable */ /** - * VOICEVOX ENGINE + * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.7 + * The version of the OpenAPI document: 0.14.0-preview.8 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/src/openapi/models/Speaker.ts b/src/openapi/models/Speaker.ts index 0a81f2a330..c0f6371e5f 100644 --- a/src/openapi/models/Speaker.ts +++ b/src/openapi/models/Speaker.ts @@ -1,10 +1,10 @@ /* tslint:disable */ /* eslint-disable */ /** - * VOICEVOX ENGINE + * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.7 + * The version of the OpenAPI document: 0.14.0-preview.8 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/src/openapi/models/SpeakerInfo.ts b/src/openapi/models/SpeakerInfo.ts index 601177c728..b876dbe388 100644 --- a/src/openapi/models/SpeakerInfo.ts +++ b/src/openapi/models/SpeakerInfo.ts @@ -1,10 +1,10 @@ /* tslint:disable */ /* eslint-disable */ /** - * VOICEVOX ENGINE + * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.7 + * The version of the OpenAPI document: 0.14.0-preview.8 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/src/openapi/models/SpeakerStyle.ts b/src/openapi/models/SpeakerStyle.ts index 900df07aa8..f275bcb5cf 100644 --- a/src/openapi/models/SpeakerStyle.ts +++ b/src/openapi/models/SpeakerStyle.ts @@ -1,10 +1,10 @@ /* tslint:disable */ /* eslint-disable */ /** - * VOICEVOX ENGINE + * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.7 + * The version of the OpenAPI document: 0.14.0-preview.8 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/src/openapi/models/StyleInfo.ts b/src/openapi/models/StyleInfo.ts index 2a13a30b60..fe68c1c355 100644 --- a/src/openapi/models/StyleInfo.ts +++ b/src/openapi/models/StyleInfo.ts @@ -1,10 +1,10 @@ /* tslint:disable */ /* eslint-disable */ /** - * VOICEVOX ENGINE + * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.7 + * The version of the OpenAPI document: 0.14.0-preview.8 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/src/openapi/models/SupportedDevicesInfo.ts b/src/openapi/models/SupportedDevicesInfo.ts index d6a70d9266..2cc7b0aad0 100644 --- a/src/openapi/models/SupportedDevicesInfo.ts +++ b/src/openapi/models/SupportedDevicesInfo.ts @@ -1,10 +1,10 @@ /* tslint:disable */ /* eslint-disable */ /** - * VOICEVOX ENGINE + * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.7 + * The version of the OpenAPI document: 0.14.0-preview.8 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/src/openapi/models/SupportedFeatures.ts b/src/openapi/models/SupportedFeatures.ts index 1e1a2430fe..34998efba3 100644 --- a/src/openapi/models/SupportedFeatures.ts +++ b/src/openapi/models/SupportedFeatures.ts @@ -1,10 +1,10 @@ /* tslint:disable */ /* eslint-disable */ /** - * VOICEVOX ENGINE + * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.7 + * The version of the OpenAPI document: 0.14.0-preview.8 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/src/openapi/models/UpdateInfo.ts b/src/openapi/models/UpdateInfo.ts index e22262405c..10ccbfb484 100644 --- a/src/openapi/models/UpdateInfo.ts +++ b/src/openapi/models/UpdateInfo.ts @@ -1,10 +1,10 @@ /* tslint:disable */ /* eslint-disable */ /** - * VOICEVOX ENGINE + * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.7 + * The version of the OpenAPI document: 0.14.0-preview.8 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/src/openapi/models/UserDictWord.ts b/src/openapi/models/UserDictWord.ts index e31b9f1fb6..ac723d3eca 100644 --- a/src/openapi/models/UserDictWord.ts +++ b/src/openapi/models/UserDictWord.ts @@ -1,10 +1,10 @@ /* tslint:disable */ /* eslint-disable */ /** - * VOICEVOX ENGINE + * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.7 + * The version of the OpenAPI document: 0.14.0-preview.8 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/src/openapi/models/ValidationError.ts b/src/openapi/models/ValidationError.ts index 160b3d83b2..9b971bc813 100644 --- a/src/openapi/models/ValidationError.ts +++ b/src/openapi/models/ValidationError.ts @@ -1,10 +1,10 @@ /* tslint:disable */ /* eslint-disable */ /** - * VOICEVOX ENGINE + * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.7 + * The version of the OpenAPI document: 0.14.0-preview.8 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/src/openapi/models/WordTypes.ts b/src/openapi/models/WordTypes.ts index 2f0878fbea..89e97a7400 100644 --- a/src/openapi/models/WordTypes.ts +++ b/src/openapi/models/WordTypes.ts @@ -1,10 +1,10 @@ /* tslint:disable */ /* eslint-disable */ /** - * VOICEVOX ENGINE + * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.7 + * The version of the OpenAPI document: 0.14.0-preview.8 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -13,7 +13,9 @@ */ /** - * fastapiでword_type引数を検証する時に使用するクラス + * + fastapiでword_type引数を検証する時に使用するクラス + * @export * @enum {string} */ diff --git a/src/openapi/runtime.ts b/src/openapi/runtime.ts index 59315186ea..acc5b242c9 100644 --- a/src/openapi/runtime.ts +++ b/src/openapi/runtime.ts @@ -1,10 +1,10 @@ /* tslint:disable */ /* eslint-disable */ /** - * VOICEVOX ENGINE + * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.7 + * The version of the OpenAPI document: 0.14.0-preview.8 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/src/store/audio.ts b/src/store/audio.ts index a8541ffad3..7c1259f447 100644 --- a/src/store/audio.ts +++ b/src/store/audio.ts @@ -257,6 +257,8 @@ export const audioStore = createPartialStore({ styleId: style.id, engineId, iconPath: base64ImageToUri(styleInfo.icon), + portraitPath: + styleInfo.portrait && base64ImageToUri(styleInfo.portrait), voiceSamplePaths: voiceSamples, }; }); @@ -281,7 +283,7 @@ export const audioStore = createPartialStore({ metas: { speakerUuid: speaker.speakerUuid, speakerName: speaker.name, - styles: styles, + styles, policy: speakerInfo.policy, }, }; @@ -1810,25 +1812,34 @@ export const audioCommandStore = transformCommandStore( audioItem: AudioItem; audioKey: string; prevAudioKey: string | undefined; + applyPreset: boolean; } ) { audioStore.mutations.INSERT_AUDIO_ITEM(draft, payload); - audioStore.mutations.APPLY_AUDIO_PRESET(draft, { - audioKey: payload.audioKey, - }); + if (payload.applyPreset) { + audioStore.mutations.APPLY_AUDIO_PRESET(draft, { + audioKey: payload.audioKey, + }); + } }, async action( { dispatch, commit }, { audioItem, prevAudioKey, - }: { audioItem: AudioItem; prevAudioKey: string | undefined } + applyPreset, + }: { + audioItem: AudioItem; + prevAudioKey: string | undefined; + applyPreset: boolean; + } ) { const audioKey = await dispatch("GENERATE_AUDIO_KEY"); commit("COMMAND_REGISTER_AUDIO_ITEM", { audioItem, audioKey, prevAudioKey, + applyPreset, }); return audioKey; }, diff --git a/src/store/index.ts b/src/store/index.ts index f612f77ba4..ffcde99ca7 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -267,6 +267,12 @@ export const indexStore = createPartialStore({ }, }, + LOG_WARN: { + action(_, ...params: unknown[]) { + window.electron.logWarn(...params); + }, + }, + LOG_INFO: { action(_, ...params: unknown[]) { window.electron.logInfo(...params); diff --git a/src/store/type.ts b/src/store/type.ts index 2dfba00586..698700fec3 100644 --- a/src/store/type.ts +++ b/src/store/type.ts @@ -456,10 +456,12 @@ export type AudioCommandStoreTypes = { audioItem: AudioItem; audioKey: string; prevAudioKey: string | undefined; + applyPreset: boolean; }; action(payload: { audioItem: AudioItem; prevAudioKey: string | undefined; + applyPreset: boolean; }): Promise; }; @@ -861,6 +863,10 @@ export type IndexStoreTypes = { action(...payload: unknown[]): void; }; + LOG_WARN: { + action(...payload: unknown[]): void; + }; + LOG_INFO: { action(...payload: unknown[]): void; }; diff --git a/src/store/ui.ts b/src/store/ui.ts index d2697e5c77..c1870b42ea 100644 --- a/src/store/ui.ts +++ b/src/store/ui.ts @@ -97,7 +97,9 @@ export const uiStore = createPartialStore({ state.uiLockCount--; } else { // eslint-disable-next-line no-console - console.warn("UNLOCK_UI is called when state.uiLockCount == 0"); + window.electron.logWarn( + "UNLOCK_UI is called when state.uiLockCount == 0" + ); } }, action({ commit }) { diff --git a/src/styles/_index.scss b/src/styles/_index.scss index 4ee95fa00a..8de858bebb 100644 --- a/src/styles/_index.scss +++ b/src/styles/_index.scss @@ -13,7 +13,7 @@ body:not(#dummy) { } body[data-editor-font="default"] { - font-family: "Rounded M+ 1p", sans-serif; + font-family: "Unhinted Rounded M+ 1p", sans-serif; } img { diff --git a/src/styles/fonts.scss b/src/styles/fonts.scss index c4148ab05c..2911455b92 100644 --- a/src/styles/fonts.scss +++ b/src/styles/fonts.scss @@ -1,13 +1,13 @@ @font-face { - font-family: "Rounded M+ 1p"; - src: url("../fonts/rounded-mplus-1p-regular.ttf"); + font-family: "Unhinted Rounded M+ 1p"; + src: url("../fonts/unhinted-rounded-mplus-1p-regular.woff2"); font-weight: normal; } @font-face { - font-family: "Rounded M+ 1p"; - src: url("../fonts/rounded-mplus-1p-bold.ttf"); + font-family: "Unhinted Rounded M+ 1p"; + src: url("../fonts/unhinted-rounded-mplus-1p-bold.woff2"); font-weight: bold; } diff --git a/src/type/ipc.ts b/src/type/ipc.ts index a8f70fddac..bd91d47ab7 100644 --- a/src/type/ipc.ts +++ b/src/type/ipc.ts @@ -178,6 +178,11 @@ export type IpcIHData = { return: void; }; + LOG_WARN: { + args: [...params: unknown[]]; + return: void; + }; + LOG_INFO: { args: [...params: unknown[]]; return: void; diff --git a/src/type/preload.ts b/src/type/preload.ts index 15836dd4f5..38b9768284 100644 --- a/src/type/preload.ts +++ b/src/type/preload.ts @@ -1,26 +1,108 @@ import { IpcRenderer, IpcRendererEvent } from "electron"; import { IpcSOData } from "./ipc"; - -export interface ElectronStoreType { - useGpu: boolean; - inheritAudioInfo: boolean; - activePointScrollMode: ActivePointScrollMode; - savingSetting: SavingSetting; - presets: PresetConfig; - hotkeySettings: HotkeySetting[]; - toolbarSetting: ToolbarSetting; - userCharacterOrder: string[]; - defaultStyleIds: DefaultStyleId[]; - currentTheme: string; - editorFont: EditorFontType; - experimentalSetting: ExperimentalSetting; - acceptRetrieveTelemetry: AcceptRetrieveTelemetryStatus; - acceptTerms: AcceptTermsStatus; - splitTextWhenPaste: SplitTextWhenPasteType; - splitterPosition: SplitterPosition; - confirmedTips: ConfirmedTips; - engineDirs: string[]; -} +import { z } from "zod"; + +export const isMac = process.platform === "darwin"; +// ホットキーを追加したときは設定のマイグレーションが必要 +export const defaultHotkeySettings: HotkeySetting[] = [ + { + action: "音声書き出し", + combination: !isMac ? "Ctrl E" : "Meta E", + }, + { + action: "一つだけ書き出し", + combination: "E", + }, + { + action: "音声を繋げて書き出し", + combination: "", + }, + { + action: "再生/停止", + combination: "Space", + }, + { + action: "連続再生/停止", + combination: "Shift Space", + }, + { + action: "アクセント欄を表示", + combination: "1", + }, + { + action: "イントネーション欄を表示", + combination: "2", + }, + { + action: "長さ欄を表示", + combination: "3", + }, + { + action: "テキスト欄を追加", + combination: "Shift Enter", + }, + { + action: "テキスト欄を複製", + combination: !isMac ? "Ctrl D" : "Meta D", + }, + { + action: "テキスト欄を削除", + combination: "Shift Delete", + }, + { + action: "テキスト欄からフォーカスを外す", + combination: "Escape", + }, + { + action: "テキスト欄にフォーカスを戻す", + combination: "Enter", + }, + { + action: "元に戻す", + combination: !isMac ? "Ctrl Z" : "Meta Z", + }, + { + action: "やり直す", + combination: !isMac ? "Ctrl Y" : "Shift Meta Z", + }, + { + action: "新規プロジェクト", + combination: !isMac ? "Ctrl N" : "Meta N", + }, + { + action: "プロジェクトを名前を付けて保存", + combination: !isMac ? "Ctrl Shift S" : "Shift Meta S", + }, + { + action: "プロジェクトを上書き保存", + combination: !isMac ? "Ctrl S" : "Meta S", + }, + { + action: "プロジェクト読み込み", + combination: !isMac ? "Ctrl O" : "Meta O", + }, + { + action: "テキスト読み込む", + combination: "", + }, + { + action: "全体のイントネーションをリセット", + combination: !isMac ? "Ctrl G" : "Meta G", + }, + { + action: "選択中のアクセント句のイントネーションをリセット", + combination: "R", + }, +]; + +export const defaultToolbarButtonSetting: ToolbarSetting = [ + "PLAY_CONTINUOUSLY", + "STOP", + "EXPORT_AUDIO_ONE", + "EMPTY", + "UNDO", + "REDO", +]; export interface Sandbox { getAppInfos(): Promise; @@ -81,9 +163,9 @@ export interface Sandbox { minimizeWindow(): void; maximizeWindow(): void; logError(...params: unknown[]): void; + logWarn(...params: unknown[]): void; logInfo(...params: unknown[]): void; engineInfos(): Promise; - restartEngineAll(): Promise; restartEngine(engineId: string): Promise; openEngineDirectory(engineId: string): void; hotkeySettings(newData?: HotkeySetting): Promise; @@ -115,6 +197,7 @@ export type StyleInfo = { styleName?: string; styleId: number; iconPath: string; + portraitPath: string | undefined; engineId: string; voiceSamplePaths: string[]; }; @@ -181,11 +264,6 @@ export type DefaultStyleId = { defaultStyleId: number; }; -export type HotkeySetting = { - action: HotkeyAction; - combination: HotkeyCombo; -}; - export type EngineInfo = { uuid: string; host: string; @@ -223,50 +301,64 @@ export type PresetConfig = { items: Record; keys: string[]; }; -export type HotkeyAction = - | "音声書き出し" - | "一つだけ書き出し" - | "音声を繋げて書き出し" - | "再生/停止" - | "連続再生/停止" - | "アクセント欄を表示" - | "イントネーション欄を表示" - | "長さ欄を表示" - | "テキスト欄を追加" - | "テキスト欄を削除" - | "テキスト欄からフォーカスを外す" - | "テキスト欄にフォーカスを戻す" - | "元に戻す" - | "やり直す" - | "新規プロジェクト" - | "プロジェクトを名前を付けて保存" - | "プロジェクトを上書き保存" - | "プロジェクト読み込み" - | "テキスト読み込む" - | "全体のイントネーションをリセット" - | "選択中のアクセント句のイントネーションをリセット"; + +export const hotkeyActionSchema = z.enum([ + "音声書き出し", + "一つだけ書き出し", + "音声を繋げて書き出し", + "再生/停止", + "連続再生/停止", + "アクセント欄を表示", + "イントネーション欄を表示", + "長さ欄を表示", + "テキスト欄を追加", + "テキスト欄を複製", + "テキスト欄を削除", + "テキスト欄からフォーカスを外す", + "テキスト欄にフォーカスを戻す", + "元に戻す", + "やり直す", + "新規プロジェクト", + "プロジェクトを名前を付けて保存", + "プロジェクトを上書き保存", + "プロジェクト読み込み", + "テキスト読み込む", + "全体のイントネーションをリセット", + "選択中のアクセント句のイントネーションをリセット", +]); + +export type HotkeyAction = z.infer; export type HotkeyCombo = string; +export const hotkeySettingSchema = z.object({ + action: hotkeyActionSchema, + combination: z.string(), +}); +export type HotkeySetting = z.infer; + export type HotkeyReturnType = | void | boolean | Promise | Promise; -export type ToolbarButtonTagType = - | "PLAY_CONTINUOUSLY" - | "STOP" - | "EXPORT_AUDIO_ONE" - | "EXPORT_AUDIO_ALL" - | "EXPORT_AUDIO_CONNECT_ALL" - | "SAVE_PROJECT" - | "UNDO" - | "REDO" - | "IMPORT_TEXT" - | "EMPTY"; - -export type ToolbarSetting = ToolbarButtonTagType[]; +export const toolbarButtonTagSchema = z.enum([ + "PLAY_CONTINUOUSLY", + "STOP", + "EXPORT_AUDIO_ONE", + "EXPORT_AUDIO_ALL", + "EXPORT_AUDIO_CONNECT_ALL", + "SAVE_PROJECT", + "UNDO", + "REDO", + "IMPORT_TEXT", + "EMPTY", +]); +export type ToolbarButtonTagType = z.infer; + +export const toolbarSettingSchema = toolbarButtonTagSchema; +export type ToolbarSetting = z.infer[]; export type MoraDataType = | "consonant" @@ -309,15 +401,106 @@ export type ExperimentalSetting = { enableMorphing: boolean; }; -export type SplitterPosition = { - portraitPaneWidth: number | undefined; - audioInfoPaneWidth: number | undefined; - audioDetailPaneHeight: number | undefined; -}; +export const splitterPositionSchema = z.object({ + portraitPaneWidth: z.number().optional(), + audioInfoPaneWidth: z.number().optional(), + audioDetailPaneHeight: z.number().optional(), +}); +export type SplitterPosition = z.infer; export type ConfirmedTips = { tweakableSliderByScroll: boolean; }; +export const electronStoreSchema = z + .object({ + useGpu: z.boolean().default(false), + inheritAudioInfo: z.boolean().default(true), + activePointScrollMode: z + .enum(["CONTINUOUSLY", "PAGE", "OFF"]) + .default("OFF"), + savingSetting: z + .object({ + fileEncoding: z.enum(["UTF-8", "Shift_JIS"]).default("UTF-8"), + fileNamePattern: z.string().default(""), + fixedExportEnabled: z.boolean().default(false), + avoidOverwrite: z.boolean().default(false), + fixedExportDir: z.string().default(""), + exportLab: z.boolean().default(false), + exportText: z.boolean().default(false), + outputStereo: z.boolean().default(false), + outputSamplingRate: z + .union([z.number(), z.literal("engineDefault")]) + .default("engineDefault"), + audioOutputDevice: z.string().default(""), + }) + .passthrough() // 別のブランチでの開発中の設定項目があるコンフィグで死ぬのを防ぐ + .default({}), + hotkeySettings: hotkeySettingSchema.array().default(defaultHotkeySettings), + toolbarSetting: toolbarSettingSchema + .array() + .default(defaultToolbarButtonSetting), + userCharacterOrder: z.string().array().default([]), + defaultStyleIds: z + .object({ speakerUuid: z.string(), defaultStyleId: z.number() }) + .array() + .default([]), + presets: z + .object({ + items: z + .record( + z.string().uuid(), + z.object({ + name: z.string(), + speedScale: z.number(), + pitchScale: z.number(), + intonationScale: z.number(), + volumeScale: z.number(), + prePhonemeLength: z.number(), + postPhonemeLength: z.number(), + morphingInfo: z + .object({ + rate: z.number(), + targetEngineId: z.string().uuid(), + targetSpeakerId: z.string().uuid(), + targetStyleId: z.number(), + }) + .optional(), + }) + ) + .default({}), + keys: z.string().uuid().array().default([]), + }) + .default({}), + currentTheme: z.string().default("Default"), + editorFont: z.enum(["default", "os"]).default("default"), + experimentalSetting: z + .object({ + enablePreset: z.boolean().default(false), + enableInterrogativeUpspeak: z.boolean().default(false), + enableMorphing: z.boolean().default(false), + }) + .passthrough() + .default({}), + acceptRetrieveTelemetry: z + .enum(["Unconfirmed", "Accepted", "Refused"]) + .default("Unconfirmed"), + acceptTerms: z + .enum(["Unconfirmed", "Accepted", "Rejected"]) + .default("Unconfirmed"), + splitTextWhenPaste: z + .enum(["PERIOD_AND_NEW_LINE", "NEW_LINE", "OFF"]) + .default("PERIOD_AND_NEW_LINE"), + splitterPosition: splitterPositionSchema.default({}), + confirmedTips: z + .object({ + tweakableSliderByScroll: z.boolean().default(false), + }) + .passthrough() + .default({}), + engineDirs: z.string().array().default([]), + }) + .passthrough(); // release-0.14直前で消す +export type ElectronStoreType = z.infer; // workaround. SystemError(https://nodejs.org/api/errors.html#class-systemerror)が2022/05/19時点ではNodeJSの型定義に記述されていないためこれを追加しています。 export class SystemError extends Error { diff --git a/src/views/EditorHome.vue b/src/views/EditorHome.vue index bf4509c5c8..94cb47df54 100644 --- a/src/views/EditorHome.vue +++ b/src/views/EditorHome.vue @@ -201,6 +201,7 @@ import { SplitterPosition, } from "@/type/preload"; import { parseCombo, setHotkeyFunctions } from "@/store/setting"; +import cloneDeep from "clone-deep"; export default defineComponent({ name: "EditorHome", @@ -247,6 +248,17 @@ export default defineComponent({ return false; // this is the same with event.preventDefault() }, ], + [ + // FIXME: テキスト欄にフォーカスがある状態でも実行できるようにする + // https://github.com/VOICEVOX/voicevox/pull/1096#issuecomment-1378651920 + "テキスト欄を複製", + () => { + if (activeAudioKey.value != undefined) { + duplicateAudioItem(); + } + return false; + }, + ], ]); setHotkeyFunctions(hotkeyMap); @@ -416,6 +428,22 @@ export default defineComponent({ const newAudioKey = await store.dispatch("COMMAND_REGISTER_AUDIO_ITEM", { audioItem, prevAudioKey: activeAudioKey.value, + applyPreset: true, + }); + audioCellRefs[newAudioKey].focusTextField(); + }; + const duplicateAudioItem = async () => { + const prevAudioKey = activeAudioKey.value; + + // audioItemが選択されていない状態で押されたら何もしない + if (prevAudioKey == undefined) return; + + const prevAudioItem = store.state.audioItems[prevAudioKey]; + + const newAudioKey = await store.dispatch("COMMAND_REGISTER_AUDIO_ITEM", { + audioItem: cloneDeep(prevAudioItem), + prevAudioKey: activeAudioKey.value, + applyPreset: false, }); audioCellRefs[newAudioKey].focusTextField(); }; diff --git a/tests/unit/store/Vuex.spec.ts b/tests/unit/store/Vuex.spec.ts index d3f0251c51..45dda25715 100644 --- a/tests/unit/store/Vuex.spec.ts +++ b/tests/unit/store/Vuex.spec.ts @@ -91,6 +91,7 @@ describe("store/vuex.js test", () => { "88022f86-c823-436e-85a3-500c629749c4": { manifestVersion: "0.13.0", name: "DUMMY VOICEVOX ENGINE", + brandName: "DUMMY VOICEVOX", uuid: "c7b58856-bd56-4aa1-afb7-b8415f824b06", url: "https://github.com/VOICEVOX/voicevox_engine", icon: "engine_manifest_assets/icon.png",