Skip to content

Commit

Permalink
マルチトラック:mainをマージ (#2166)
Browse files Browse the repository at this point in the history
## 内容

いつものアレです。

## 関連 Issue

- ref: #2163 

## スクリーンショット・動画など

(なし)

## その他

(なし)
  • Loading branch information
Hiroshiba authored Jul 10, 2024
2 parents 63dbe09 + 1f39897 commit 5ab9bbe
Show file tree
Hide file tree
Showing 8 changed files with 777 additions and 82 deletions.
27 changes: 23 additions & 4 deletions src/backend/electron/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import path from "path";

import fs from "fs";
import { pathToFileURL } from "url";
import {
app,
protocol,
Expand Down Expand Up @@ -428,8 +429,23 @@ async function createWindow() {
// ソフトウェア起動時はプロトコルを app にする
if (process.env.VITE_DEV_SERVER_URL == undefined) {
protocol.handle("app", (request) => {
const filePath = path.join(__dirname, new URL(request.url).pathname);
return net.fetch(`file://${filePath}`);
// 読み取り先のファイルがインストールディレクトリ内であることを確認する
// ref: https://www.electronjs.org/ja/docs/latest/api/protocol#protocolhandlescheme-handler
const { pathname } = new URL(request.url);
const pathToServe = path.resolve(path.join(__dirname, pathname));
const relativePath = path.relative(__dirname, pathToServe);
const isUnsafe =
path.isAbsolute(relativePath) ||
relativePath.startsWith("..") ||
relativePath === "";
if (isUnsafe) {
log.error(`Bad Request URL: ${request.url}`);
return new Response("bad", {
status: 400,
headers: { "content-type": "text/html" },
});
}
return net.fetch(pathToFileURL(pathToServe).toString());
});
}

Expand Down Expand Up @@ -1029,8 +1045,11 @@ app.on("web-contents-created", (e, contents) => {

// ナビゲーションを無効化
contents.on("will-navigate", (event) => {
log.error(`ナビゲーションは無効化されています。url: ${event.url}`);
event.preventDefault();
// preloadスクリプト変更時のホットリロードを許容する
if (contents.getURL() !== event.url) {
log.error(`ナビゲーションは無効化されています。url: ${event.url}`);
event.preventDefault();
}
});
});

Expand Down
24 changes: 24 additions & 0 deletions src/helpers/fileHelper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { ResultError } from "@/type/result";

/** ファイル書き込み時のエラーメッセージを生成する */
export function generateWriteErrorMessage(writeFileResult: ResultError) {
const code = writeFileResult.code?.toUpperCase();

if (code?.startsWith("ENOSPC")) {
return "空き容量が足りません。";
}

if (code?.startsWith("EACCES")) {
return "ファイルにアクセスする許可がありません。";
}

if (code?.startsWith("EBUSY")) {
return "ファイルが開かれています。";
}

if (code?.startsWith("ENOENT")) {
return "ファイルが見つかりません。";
}

return `何らかの理由で失敗しました。${writeFileResult.message}`;
}
107 changes: 50 additions & 57 deletions src/store/audio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import {
import { AudioQuery, AccentPhrase, Speaker, SpeakerInfo } from "@/openapi";
import { base64ImageToUri, base64ToUri } from "@/helpers/base64Helper";
import { getValueOrThrow, ResultError } from "@/type/result";
import { generateWriteErrorMessage } from "@/helpers/fileHelper";

function generateAudioKey() {
return AudioKey(crypto.randomUUID());
Expand Down Expand Up @@ -166,25 +167,6 @@ export async function writeTextFile(obj: {
});
}

function generateWriteErrorMessage(writeFileResult: ResultError) {
if (!writeFileResult.code) {
return `何らかの理由で失敗しました。${writeFileResult.message}`;
}
const code = writeFileResult.code.toUpperCase();

if (code.startsWith("ENOSPC")) {
return "空き容量が足りません。";
}

if (code.startsWith("EACCES")) {
return "ファイルにアクセスする許可がありません。";
}

if (code.startsWith("EBUSY")) {
return "ファイルが開かれています。";
}
}

// TODO: GETTERに移動する。
export function getCharacterInfo(
state: State,
Expand Down Expand Up @@ -1522,8 +1504,6 @@ export const audioStore = createPartialStore<AudioStoreTypes>({
const labs: string[] = [];
const texts: string[] = [];

let labOffset = 0;

const base64Encoder = (blob: Blob): Promise<string | undefined> => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
Expand All @@ -1544,6 +1524,7 @@ export const audioStore = createPartialStore<AudioStoreTypes>({
const totalCount = state.audioKeys.length;
let finishedCount = 0;

let labOffset = 0;
for (const audioKey of state.audioKeys) {
let fetchAudioResult: FetchAudioResult;
try {
Expand All @@ -1565,21 +1546,21 @@ export const audioStore = createPartialStore<AudioStoreTypes>({
return { result: "WRITE_ERROR", path: filePath };
}
encodedBlobs.push(encodedBlob);

// 大して処理能力を要しないので、生成設定のon/offにかかわらず生成してしまう
const lab = await generateLabFromAudioQuery(audioQuery, labOffset);
if (lab == undefined) {
return { result: "WRITE_ERROR", path: filePath };
}
labs.push(lab);

// 最終音素の終了時刻を取得する
const splitLab = lab.split(" ");
labOffset = Number(splitLab[splitLab.length - 2]);

texts.push(
extractExportText(state.audioItems[audioKey].text, {
enableMemoNotation: state.enableMemoNotation,
enableRubyNotation: state.enableRubyNotation,
}),
);
// 最終音素の終了時刻を取得する
const splitLab = lab.split(" ");
labOffset = Number(splitLab[splitLab.length - 2]);
}

const connectedWav = await dispatch("CONNECT_AUDIO", {
Expand All @@ -1589,40 +1570,48 @@ export const audioStore = createPartialStore<AudioStoreTypes>({
return { result: "ENGINE_ERROR", path: filePath };
}

const writeFileResult = await window.backend.writeFile({
filePath,
buffer: await connectedWav.arrayBuffer(),
});
if (!writeFileResult.ok) {
window.backend.logError(writeFileResult.error);
return { result: "WRITE_ERROR", path: filePath };
}
try {
await window.backend
.writeFile({
filePath,
buffer: await connectedWav.arrayBuffer(),
})
.then(getValueOrThrow);

if (state.savingSetting.exportLab) {
const labResult = await writeTextFile({
// `generateLabFromAudioQuery`で生成される文字列はすべて改行で終わるので、追加で改行を挟む必要はない
text: labs.join(""),
filePath: filePath.replace(/\.wav$/, ".lab"),
});
if (!labResult.ok) {
window.backend.logError(labResult.error);
return { result: "WRITE_ERROR", path: filePath };
if (state.savingSetting.exportLab) {
await writeTextFile({
// `generateLabFromAudioQuery`で生成される文字列はすべて改行で終わるので、追加で改行を挟む必要はない
text: labs.join(""),
filePath: filePath.replace(/\.wav$/, ".lab"),
}).then(getValueOrThrow);
}
}

if (state.savingSetting.exportText) {
const textResult = await writeTextFile({
text: texts.join("\n"),
filePath: filePath.replace(/\.wav$/, ".txt"),
encoding: state.savingSetting.fileEncoding,
});
if (!textResult.ok) {
window.backend.logError(textResult.error);
return { result: "WRITE_ERROR", path: filePath };
if (state.savingSetting.exportText) {
await writeTextFile({
text: texts.join("\n"),
filePath: filePath.replace(/\.wav$/, ".txt"),
encoding: state.savingSetting.fileEncoding,
}).then(getValueOrThrow);
}
}

return { result: "SUCCESS", path: filePath };
return { result: "SUCCESS", path: filePath };
} catch (e) {
window.backend.logError(e);
if (e instanceof ResultError) {
return {
result: "WRITE_ERROR",
path: filePath,
errorMessage: generateWriteErrorMessage(e),
};
}
return {
result: "UNKNOWN_ERROR",
path: filePath,
errorMessage:
(e instanceof Error ? e.message : String(e)) ||
"不明なエラーが発生しました。",
};
}
},
),
},
Expand Down Expand Up @@ -1701,7 +1690,11 @@ export const audioStore = createPartialStore<AudioStoreTypes>({
});
if (!result.ok) {
window.backend.logError(result.error);
return { result: "WRITE_ERROR", path: filePath };
return {
result: "WRITE_ERROR",
path: filePath,
errorMessage: generateWriteErrorMessage(new ResultError(result)),
};
}

return { result: "SUCCESS", path: filePath };
Expand Down
18 changes: 4 additions & 14 deletions src/store/command.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import { toRaw } from "vue";
import { enablePatches, enableMapSet, Immer } from "immer";
// immerの内部関数であるgetPlugin("Patches").applyPatches_はexportされていないので
// ビルド前のsrcからソースコードを読み込んで使う必要がある
import { enablePatches as enablePatchesImpl } from "immer/src/plugins/patches";
import { enableMapSet as enableMapSetImpl } from "immer/src/plugins/mapset";
import { getPlugin } from "immer/src/utils/plugins";

import { Command, CommandStoreState, CommandStoreTypes, State } from "./type";
import { applyPatches } from "@/store/immerPatchUtility";
import {
createPartialStore,
Mutation,
Expand All @@ -15,14 +11,8 @@ import {
} from "@/store/vuex";
import { EditorType } from "@/type/preload";

// ビルド後のモジュールとビルド前のモジュールは別のスコープで変数を持っているので
// enable * も両方叩く必要がある。
enablePatches();
enableMapSet();
enablePatchesImpl();
enableMapSetImpl();
// immerのPatchをmutableに適応する内部関数
const applyPatchesImpl = getPlugin("Patches").applyPatches_;

const immer = new Immer();
immer.setAutoFreeze(false);
Expand Down Expand Up @@ -60,7 +50,7 @@ export const createCommandMutation =
): Mutation<S, M, K> =>
(state: S, payload: M[K]): void => {
const command = recordPatches(payloadRecipe)(state, payload);
applyPatchesImpl(state, command.redoPatches);
applyPatches(state, command.redoPatches);
state.undoCommands[editor].push(command);
state.redoCommands[editor].splice(0);
};
Expand Down Expand Up @@ -112,7 +102,7 @@ export const commandStore = createPartialStore<CommandStoreTypes>({
const command = state.undoCommands[editor].pop();
if (command != null) {
state.redoCommands[editor].push(command);
applyPatchesImpl(state, command.undoPatches);
applyPatches(state, command.undoPatches);
}
},
action({ commit, dispatch }, { editor }: { editor: EditorType }) {
Expand All @@ -130,7 +120,7 @@ export const commandStore = createPartialStore<CommandStoreTypes>({
const command = state.redoCommands[editor].pop();
if (command != null) {
state.undoCommands[editor].push(command);
applyPatchesImpl(state, command.redoPatches);
applyPatches(state, command.redoPatches);
}
},
action({ commit, dispatch }, { editor }: { editor: EditorType }) {
Expand Down
Loading

0 comments on commit 5ab9bbe

Please sign in to comment.