Skip to content

Commit

Permalink
VirtualCastのプロファイル実装に伴う仕様変更に対応
Browse files Browse the repository at this point in the history
○○○_config というファイルをすべて、プロファイルごとに変換対象とした
  • Loading branch information
esperecyan committed Jun 5, 2021
1 parent 522a6fb commit 93c2e6e
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 105 deletions.
12 changes: 6 additions & 6 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
VirtualCast/config.yaml
=======================
`config.yaml` (または `config.yml`) を `config.json` に変換後、VirtualCast.exe を起動する[WSH]スクリプトです。
`プロファイル名_config.yaml` (または `プロファイル名_config.yml`) を `プロファイル名_config.json` に変換後、VirtualCast.exe を起動する[WSH]スクリプトです。

[WSH]: https://ja.wikipedia.org/wiki/Windows_Script_Host "Windows Script Hostとは、Microsoft Windowsにおいてテキストファイルに記述したスクリプトを実行するスクリプト実行環境である。"

---
`VirtualCast.exe` があるフォルダに次のような `config.yaml` を置いておくと、
`VirtualCast.exe` があるフォルダに次のような `プロファイル名_config.yaml` を置いておくと、

```yaml
panorama:
Expand All @@ -30,7 +30,7 @@ cue_card:
allow_direct_view: true
```
次のような `config.json` に変換されます。
次のような `プロファイル名_config.json` に変換されます。

```json
{
Expand Down Expand Up @@ -67,10 +67,10 @@ allow_direct_view: true

1. [バーチャルキャストを起動.js.cmd]を好きなフォルダに保存します。
2. `バーチャルキャストを起動.js.cmd` をダブルクリックして実行します。
3. `config.json` の内容をもとに `config.yaml` が作成された後、バーチャルキャストが起動します。
4. `config.yaml` が存在する場合、変換して `config.json` に上書き保存され、その後バーチャルキャストが起動します。
3. `default_config.json` の内容をもとに `default_config.yaml` が作成された後、バーチャルキャストが起動します。
4. `default_config.yaml` が存在する場合、変換して `default_config.json` に上書き保存され、その後バーチャルキャストが起動します。
5. `VirtualCast.exe` を直接起動する代わりに、常に `バーチャルキャストを起動.js.cmd` からバーチャルキャストを起動するようにしておくと、
`config.json` の更新を意識せずにすむため便利です。
`default_config.json` の更新を意識せずにすむため便利です。

[バーチャルキャストを起動.js.cmd]: https://esperecyan.github.io/virtualcast-config/%E3%83%90%E3%83%BC%E3%83%81%E3%83%A3%E3%83%AB%E3%82%AD%E3%83%A3%E3%82%B9%E3%83%88%E3%82%92%E8%B5%B7%E5%8B%95.js.cmd

Expand Down
215 changes: 116 additions & 99 deletions バーチャルキャストを起動.js.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ REM JScript9.dll
EXIT %errorlevel% */

/**
* @fileconfig.yaml」(または config.yml) を「config.json」に変換後、VirtualCast.exe を起動します。
* @fileプロファイル名_config.yaml」(または プロファイル名_config.yml) を「プロファイル名_config.json」に変換後、VirtualCast.exe を起動します。
* @version 2.0.0
* @license MPL-2.0
* @author 100の人
Expand All @@ -26,18 +26,6 @@ var EXE_URL = 'steam://rungameid/947890';
*/
var CONFIG_FOLDER_PATH = Shell.ExpandEnvironmentStrings('%USERPROFILE%\\Documents\\My Games\\VirtualCast');

/**
* 出力先ファイルパス。
* @constant {string}
*/
var OUTPUT_FILE_NAME = 'config.json';

/**
* 入力元ファイル名。出力先ファイルをもとに作成する場合は、最初のファイル名を使用。
* @constant {string}
*/
var INPUT_FILE_NAMES = ['config.yaml', 'config.yml'];

/**
* [UTF-8 復号する | Encoding Standard ― 符号化法 標準(日本語訳)]{@link https://triple-underscore.github.io/Encoding-ja.html#utf-8-decode}
* @constant {number}
Expand Down Expand Up @@ -143,127 +131,142 @@ function isValidConfig(config, filename)

var folder = FileSystemObject.GetFolder(CONFIG_FOLDER_PATH);

var outputFile, inputFile;
var profileNameFilesPairs = { };
var files = new Enumerator(folder.files);
for (; !files.atEnd(); files.moveNext()) {
var file = files.item();
if (file.Name === OUTPUT_FILE_NAME) {
outputFile = file;
} else if (INPUT_FILE_NAMES.includes(file.Name)) {
if (inputFile) {
var result = /(.+)_config\.(json|yaml|yml)$/.exec(file.Name);
if (!result) {
continue;
}
var profileName = result[1];
var extension = result[2];

if (!(profileName in profileNameFilesPairs)) {
profileNameFilesPairs[profileName] = { };
}

if (extension === 'json') {
profileNameFilesPairs[profileName].output = file;
} else {
if (profileNameFilesPairs[profileName].input) {
// ファイル名が「.yaml」「.yml」の違いしかないファイルがあれば
Shell.Popup(
'「' + inputFile.Name + '」「' + file.Name + '」のいずれも存在しています。どちらか一つである必要があります。',
'「' + profileName + '_config.yaml」「' + profileName + '_config.yml」のいずれも存在しています。どちらか一つである必要があります。',
0,
WSH.ScriptName,
vbOKOnly + vbCritical
);
return;
} else {
inputFile = file;
}
profileNameFilesPairs[profileName].input = file;
}
}

if (inputFile) {
// config.yaml → config.json
if ((outputFile || folder).Attributes & ReadOnly) {
Shell.Popup(
outputFile
? '「' + outputFile.Name + '」を上書きする権限がありません。'
: '「' + folder.Name + '」フォルダにファイルを作成する権限がないため、「' + OUTPUT_FILE_NAME + '」を作成できません。',
0,
WSH.ScriptName,
vbOKOnly + vbCritical
);
return;
}
if (Object.keys(profileNameFilesPairs).length === 0) {
Shell.Popup(CONFIG_FOLDER_PATH + ' に、「_config」を含むファイルは見つかりません。', 0, WSH.ScriptName, vbOKOnly + vbCritical);
return;
}

var yaml = getFileContents(inputFile.Path);

var configs;
try {
configs = jsyaml.safeLoadAll(yaml, null, {filename: inputFile.Path});
} catch (exception) {
if (exception.name === 'YAMLException') {
var errorMessage = '「' + inputFile.Name + '」は壊れています。以下のエラーが発生しました。';
if (outputFile) {
errorMessage += '「' + inputFile.Name + '」を削除、または名前の変更を行えば、'
+ '次回起動時に「' + outputFile.name + '」の内容をもとに「' + INPUT_FILE_NAMES[0] + '」を作成します。';
}
for (var profileName in profileNameFilesPairs) {
var files = profileNameFilesPairs[profileName];
if (files.input) {
// config.yaml → config.json
var outputFileName = profileName + '_config.json';
if ((files.output || folder).Attributes & ReadOnly) {
Shell.Popup(
errorMessage + '\n\n' + exception.name + ': ' + exception.message,
files.output
? '「' + files.output.Name + '」を上書きする権限がありません。'
: '「' + folder.Name + '」フォルダにファイルを作成する権限がないため、「' + outputFileName + '」を作成できません。',
0,
WSH.ScriptName,
vbOKOnly + vbCritical
);
return;
} else {
throw exception;
}
}

var config = configs[0];
var argument = getArgument('--esperecyan-document-index');
if (argument) {
var index = Number.parseInt(argument);
if (configs.length <= index) {
var yaml = getFileContents(files.input);

var configs;
try {
configs = jsyaml.safeLoadAll(yaml, null, {filename: files.input.Path});
} catch (exception) {
if (exception.name === 'YAMLException') {
var errorMessage = '「' + files.input.Name + '」は壊れています。以下のエラーが発生しました。';
if (files.output) {
errorMessage += '「' + files.input.Name + '」を削除、または名前の変更を行えば、'
+ '次回起動時に「' + files.output.Name + '」の内容をもとに「' + profileName + '_config.yaml」を作成します。';
}
Shell.Popup(
errorMessage + '\n\n' + exception.name + ': ' + exception.message,
0,
WSH.ScriptName,
vbOKOnly + vbCritical
);
return;
} else {
throw exception;
}
}

var config = configs[0];
var argument = getArgument('--esperecyan-document-index');
if (argument) {
var index = Number.parseInt(argument);
if (configs.length <= index) {
Shell.Popup(
files.input.Name + 'には' + configs.length + '個のYAMLドキュメントが含まれているので、'
+ '--esperecyan-document-index には0~' + (configs.length - 1) + 'を指定する必要があります。',
0,
WSH.ScriptName,
vbOKOnly + vbCritical
);
return;
}
config = configs[index];
}

if (!isValidConfig(config, files.input.Name)) {
return;
}

putFileContents(folder.Path + '\\' + profileName + '_config.json', JSON.stringify(config, null, '\t').replace(/\n/g, '\r\n'));
} else {
// config.json → config.yaml
if (folder.Attributes & ReadOnly) {
Shell.Popup(
inputFile.Name + 'には' + configs.length + '個のYAMLドキュメントが含まれているので、'
+ '--esperecyan-document-index には0~' + (configs.length - 1) + 'を指定する必要があります。',
'「' + folder.Name + '」フォルダにファイルを作成する権限がないため、「' + profileName + '_config.yaml」を作成できません。',
0,
WSH.ScriptName,
vbOKOnly + vbCritical
);
return;
}
config = configs[index];
}

if (!isValidConfig(config, inputFile.Name)) {
return;
}
var json = getFileContents(files.output.Path);

putFileContents(folder.Path + '\\' + OUTPUT_FILE_NAME, JSON.stringify(config, null, '\t').replace(/\n/g, '\r\n'));
} else if (outputFile) {
// config.json → config.yaml
if (folder.Attributes & ReadOnly) {
Shell.Popup(
'「' + folder.Name + '」フォルダにファイルを作成する権限がないため、「' + INPUT_FILE_NAMES[0] + '」を作成できません。',
0,
WSH.ScriptName,
vbOKOnly + vbCritical
);
return;
}
var configJSON;
try {
configJSON = JSON.parse(json);
} catch (exception) {
Shell.Popup(
'「' + files.output.Name + '」は壊れています。以下のエラーが発生しました。\n\n' + exception.name + ': ' + exception.message,
0,
WSH.ScriptName,
vbOKOnly + vbCritical
);
return;
}

var json = getFileContents(outputFile.Path);
if (!isValidConfig(configJSON, files.output.Name)) {
return;
}

var configJSON;
try {
configJSON = JSON.parse(json);
} catch (exception) {
Shell.Popup(
'「' + outputFile.Name + '」は壊れています。以下のエラーが発生しました。\n\n' + exception.name + ': ' + exception.message,
0,
WSH.ScriptName,
vbOKOnly + vbCritical
putFileContents(
profileName + '_config.yaml',
jsyaml.safeDump(configJSON, {indent: 4, lineWidth: -1}).replace(/\n/g, '\r\n')
);
return;
}

if (!isValidConfig(configJSON, outputFile.Name)) {
return;
}

putFileContents(
INPUT_FILE_NAMES[0],
jsyaml.safeDump(configJSON, {indent: 4, lineWidth: -1}).replace(/\n/g, '\r\n')
);
} else {
Shell.Popup([OUTPUT_FILE_NAME].concat(INPUT_FILE_NAMES).map(function (name) {
return '「' + name + '」';
}) + 'のいずれも見つかりません。', 0, WSH.ScriptName, vbOKOnly + vbCritical);
return;
}

Shell.Run('explorer ' + EXE_URL);
Expand Down Expand Up @@ -3020,6 +3023,20 @@ if (!String.prototype.startsWith) {
};
}

/**
* @see [String.prototype.endsWith() - JavaScript | MDN]{@link
* https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith#Polyfill}
* @license CC0-1.0 AND MIT (いずれであるか不明、おそらくCC0-1.0)
*/
if (!String.prototype.endsWith) {
String.prototype.endsWith = function(search, this_len) {
if (this_len === undefined || this_len > this.length) {
this_len = this.length;
}
return this.substring(this_len - search.length, this_len) === search;
};
}

if (!Number.parseInt) {
Number.parseInt = parseInt;
}
Expand Down

0 comments on commit 93c2e6e

Please sign in to comment.