From 6f7e3c33cfb73c4f3209f9e33f0deb0393534ed4 Mon Sep 17 00:00:00 2001
From: pasta04 <aldente04@gmail.com>
Date: Sat, 11 Jul 2020 17:01:09 +0900
Subject: [PATCH] =?UTF-8?q?[update]=20=E6=9C=80=E5=89=8D=E9=9D=A2=E8=A1=A8?=
 =?UTF-8?q?=E7=A4=BA=E3=82=92=E8=BF=BD=E5=8A=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 dist/index.js     | 26 ++++++++++++++++++++++++++
 dist/index.js.map |  2 +-
 package.json      |  2 +-
 src/main/main.ts  | 35 ++++++++++++++++++++++++++++++++++-
 4 files changed, 62 insertions(+), 3 deletions(-)

diff --git a/dist/index.js b/dist/index.js
index 14ab47d..7c997b2 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -571,6 +571,25 @@ else {
     //     app.quit();
     //   }
     // });
+    // 右クリックメニュー
+    var mainContextMenu_1 = new electron_1.Menu();
+    mainContextMenu_1.append(new electron_1.MenuItem({
+        label: '最前面表示',
+        type: 'checkbox',
+        checked: false,
+        click: function (e) {
+            globalThis.electron.mainWindow.setAlwaysOnTop(e.checked);
+        },
+    }));
+    var chatContextMenu_1 = new electron_1.Menu();
+    chatContextMenu_1.append(new electron_1.MenuItem({
+        label: '最前面表示',
+        type: 'checkbox',
+        checked: false,
+        click: function (e) {
+            globalThis.electron.chatWindow.setAlwaysOnTop(e.checked);
+        },
+    }));
     // Electronの初期化完了後に実行
     app.on('ready', function () {
         var windowState = electron_window_state_1.default({
@@ -670,6 +689,13 @@ else {
             });
         });
         createChatWindow();
+        // 右クリックメニュー開く
+        globalThis.electron.mainWindow.webContents.on('context-menu', function (e, params) {
+            mainContextMenu_1.popup({ window: globalThis.electron.mainWindow, x: params.x, y: params.y });
+        });
+        globalThis.electron.chatWindow.webContents.on('context-menu', function (e, params) {
+            chatContextMenu_1.popup({ window: globalThis.electron.chatWindow, x: params.x, y: params.y });
+        });
     });
     // 音声再生できるようにする
     app.commandLine.appendSwitch('--autoplay-policy', 'no-user-gesture-required');
diff --git a/dist/index.js.map b/dist/index.js.map
index 829b92f..ec1707d 100644
--- a/dist/index.js.map
+++ b/dist/index.js.map
@@ -1 +1 @@
-{"version":3,"file":"index.js","sources":["webpack:///webpack/bootstrap","webpack:///./src/main/ReadIcons.ts","webpack:///./src/main/bouyomi-chan/index.ts","webpack:///./src/main/const.ts","webpack:///./src/main/getRes.ts","webpack:///./src/main/main.ts","webpack:///./src/main/niconama/index.ts","webpack:///./src/main/readBBS/Read5ch.ts","webpack:///./src/main/readBBS/readSitaraba.ts","webpack:///./src/main/startServer.ts","webpack:///./src/main/util.ts","webpack:///./src/main/youtube-chat/index.ts","webpack:///./src/main/youtube-chat/live-chat.ts","webpack:///./src/main/youtube-chat/parser.ts"],"sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"./src/main/main.ts\");\n","\"use strict\";\r\nvar __importDefault = (this && this.__importDefault) || function (mod) {\r\n    return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\n/**\r\n * アイコン表示に関するモジュール\r\n * シングルトン\r\n */\r\nvar fs_1 = __importDefault(require(\"fs\"));\r\nvar path_1 = __importDefault(require(\"path\"));\r\nvar electron_log_1 = __importDefault(require(\"electron-log\"));\r\nvar randomIconList;\r\nvar idIconList;\r\n/**\r\n * コンストラクタ\r\n * ・ランダムフォルダからアイコン名を取得してリスト化\r\n * ・IDフォルダからもリスト化、空の対応マップ作製\r\n * ・コテハン対応ファイルを読みこんでmapに格納\r\n */\r\nvar ReadIcons = /** @class */ (function () {\r\n    function ReadIcons() {\r\n        /**\r\n         * アイコンランダム表示機能(デフォルト)\r\n         * 起動時に作成したアイコンリストからランダムで1つ取得\r\n         */\r\n        this.getRandomIcons = function () {\r\n            var iconPath = '';\r\n            try {\r\n                var dirName = './img/random/';\r\n                // リストからランダム取得\r\n                //  const size = randomIconList.size;\r\n                var num = Math.floor(randomIconList.length * Math.random());\r\n                iconPath = dirName + randomIconList[num];\r\n            }\r\n            catch (e) {\r\n                electron_log_1.default.error(e);\r\n            }\r\n            return iconPath;\r\n        };\r\n        //画像ディレクトリ\r\n        var randomDir = path_1.default.resolve(__dirname, \"../public/img/random/\");\r\n        console.debug('[ReadIcons]loadRandomDir = ' + randomDir);\r\n        //  ランダムアイコン取得\r\n        randomIconList = readDir(randomDir);\r\n        //ID用アイコンディレクトリ\r\n        var idDir = path_1.default.resolve(__dirname, \"../public/img/id/\");\r\n        console.debug('[ReadIcons]loadIDDir = ' + idDir);\r\n        //  ランダムアイコン取得\r\n        idIconList = readDir(idDir);\r\n    }\r\n    return ReadIcons;\r\n}());\r\nvar readDir = function (imgDir) {\r\n    var iconFileList = [];\r\n    //  指定したディレクトリのアイコン取得\r\n    var files = fs_1.default.readdirSync(imgDir, { withFileTypes: true });\r\n    //pngファイルのみ返却リストに格納する\r\n    files.forEach(function (file) {\r\n        // asar圧縮するとfileが文字列になる。開発環境だとfileオブジェクトになる\r\n        var target = typeof file.name !== 'string' ? file : file.name;\r\n        var regx = /.*\\.png$/.test(target);\r\n        if (regx) {\r\n            iconFileList.push(target);\r\n        }\r\n    });\r\n    // console.log('[ReadIcons.readDir]end');\r\n    // console.log(JSON.stringify(iconFileList));\r\n    return iconFileList;\r\n};\r\n/**\r\n * IDによるアイコン固定機能(オプションでON,OFF可能)\r\n * 初出のIDならばランダムでアイコンを取得し\r\n * IDとファイル名のセットでマップに格納\r\n * @param string // ID\r\n * @return string filename\r\n */\r\n/**\r\n * コテハンリスト機能(オプションでON,OFF可能)\r\n * koteフォルダの下にkotehan.jsonを作って\r\n * 名前とアイコンファイル名の対応をマップにして返すだけ\r\n */\r\nexports.default = ReadIcons;\r\n","\"use strict\";\r\nvar __importDefault = (this && this.__importDefault) || function (mod) {\r\n    return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar net_1 = __importDefault(require(\"net\"));\r\nvar BouyomiChan = /** @class */ (function () {\r\n    function BouyomiChan(options) {\r\n        /**\r\n         * 棒読みちゃんのホスト\r\n         */\r\n        this.host = 'localhost';\r\n        /**\r\n         * 棒読みちゃんのポート番号\r\n         */\r\n        this.port = 50001;\r\n        /**\r\n         * 速度(-1:棒読みちゃん画面上の設定)\r\n         */\r\n        this.speed = -1;\r\n        /**\r\n         * 音程(-1:棒読みちゃん画面上の設定)\r\n         */\r\n        this.tone = -1;\r\n        /**\r\n         * 音量(-1:棒読みちゃん画面上の設定)\r\n         */\r\n        this.volume = -1;\r\n        /**\r\n         * 声質( 0:棒読みちゃん画面上の設定、1:女性1、2:女性2、3:男性1、4:男性2、5:中性、6:ロボット、7:機械1、8:機械2、10001~:SAPI5)\r\n         */\r\n        this.type = 0;\r\n        if (!options)\r\n            return;\r\n        if (options.host)\r\n            this.host = options.host;\r\n        if (options.port)\r\n            this.port = options.port;\r\n        if (options.speed)\r\n            this.speed = options.speed;\r\n        if (options.tone)\r\n            this.tone = options.tone;\r\n        if (options.volume)\r\n            this.volume = options.volume;\r\n        if (options.type)\r\n            this.type = options.type;\r\n    }\r\n    /**\r\n     * @param message 棒読みちゃんに読み上げてもらう文章\r\n     */\r\n    BouyomiChan.prototype.speak = function (message) {\r\n        /** 棒読みちゃんに送信する設定のバイト長 */\r\n        var SETTINGS_BYTES_LENGTH = 15;\r\n        var messageByteLength = Buffer.byteLength(message);\r\n        var bufferLength = SETTINGS_BYTES_LENGTH + messageByteLength;\r\n        var buff = Buffer.alloc(bufferLength);\r\n        /** メッセージ読み上げコマンド */\r\n        var COMMAND_TO_SPEAK = 1;\r\n        var len = buff.writeUInt16LE(COMMAND_TO_SPEAK);\r\n        len = buff.writeInt16LE(this.speed, len);\r\n        len = buff.writeInt16LE(this.tone, len);\r\n        len = buff.writeInt16LE(this.volume, len);\r\n        len = buff.writeUInt16LE(this.type, len);\r\n        /** 文字コード(0:UTF-8, 1:Unicode, 2:Shift-JIS) */\r\n        var ENCODING = 0;\r\n        len = buff.writeUInt8(ENCODING, len);\r\n        len = buff.writeUInt32LE(messageByteLength, len);\r\n        len = buff.write(message, len);\r\n        var client = net_1.default.createConnection(this.port, this.host);\r\n        client.write(buff);\r\n        client.end();\r\n    };\r\n    return BouyomiChan;\r\n}());\r\nexports.default = BouyomiChan;\r\n","\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.electronEvent = {\r\n    /** サーバー起動 */\r\n    'start-server': 'start-server',\r\n    /** サーバー停止 */\r\n    'stop-server': 'stop-server',\r\n    /** Config適用 */\r\n    'apply-config': 'apply-config',\r\n    /** アラート表示 */\r\n    'show-alert': 'show-alert',\r\n    /** 棒読み再生 */\r\n    'play-tamiyasu': 'play-tamiyasu',\r\n    /** レス着信音再生 */\r\n    'play-sound-start': 'play-sound-start',\r\n    'play-sound-end': 'play-sound-end',\r\n    'wait-yomiko-time': 'wait-yomiko-time',\r\n    'speaking-end': 'speaking-end',\r\n    /** コメント表示 */\r\n    'show-comment': 'show-comment',\r\n    /** コメント欄初期化 */\r\n    'clear-comment': 'clear-comment',\r\n    /** サーバー起動の返信 */\r\n    'start-server-reply': 'start-server-reply',\r\n    /** ステータス更新 */\r\n    UPDATE_STATUS: 'UPDATE_STATUS',\r\n};\r\n","\"use strict\";\r\nvar __assign = (this && this.__assign) || function () {\r\n    __assign = Object.assign || function(t) {\r\n        for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n            s = arguments[i];\r\n            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))\r\n                t[p] = s[p];\r\n        }\r\n        return t;\r\n    };\r\n    return __assign.apply(this, arguments);\r\n};\r\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\r\n    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n    return new (P || (P = Promise))(function (resolve, reject) {\r\n        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n        function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n        step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n    });\r\n};\r\nvar __generator = (this && this.__generator) || function (thisArg, body) {\r\n    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n    return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n    function verb(n) { return function (v) { return step([n, v]); }; }\r\n    function step(op) {\r\n        if (f) throw new TypeError(\"Generator is already executing.\");\r\n        while (_) try {\r\n            if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n            if (y = 0, t) op = [op[0] & 2, t.value];\r\n            switch (op[0]) {\r\n                case 0: case 1: t = op; break;\r\n                case 4: _.label++; return { value: op[1], done: false };\r\n                case 5: _.label++; y = op[1]; op = [0]; continue;\r\n                case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n                default:\r\n                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n                    if (t[2]) _.ops.pop();\r\n                    _.trys.pop(); continue;\r\n            }\r\n            op = body.call(thisArg, _);\r\n        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n    }\r\n};\r\nvar __importDefault = (this && this.__importDefault) || function (mod) {\r\n    return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar express_1 = __importDefault(require(\"express\"));\r\nvar body_parser_1 = __importDefault(require(\"body-parser\")); // jsonパーサ\r\nvar router = express_1.default.Router();\r\nvar electron_log_1 = __importDefault(require(\"electron-log\"));\r\nvar ReadIcons_1 = __importDefault(require(\"./ReadIcons\")); //アイコンファイル名取得\r\nvar readIcons = new ReadIcons_1.default();\r\nvar startServer_1 = require(\"./startServer\");\r\nvar readSitaraba_1 = __importDefault(require(\"./readBBS/readSitaraba\")); // したらば読み込み用モジュール\r\nvar Read5ch_1 = __importDefault(require(\"./readBBS/Read5ch\")); // 5ch互換板読み込み用モジュール\r\nvar sitaraba = new readSitaraba_1.default();\r\nvar read5ch = new Read5ch_1.default();\r\n// 掲示板読み込みモジュール、一度決定したら使いまわすためにグローバル宣言\r\nvar bbsModule = null;\r\n// リクエストのbodyをパース下りエンコードしたりするためのやつ\r\nrouter.use(body_parser_1.default.urlencoded({ extended: true }));\r\nrouter.use(body_parser_1.default.json());\r\n/**\r\n * ブラウザからの初期処理リクエスト\r\n */\r\nrouter.get('/', function (req, res, next) { return __awaiter(void 0, void 0, void 0, function () {\r\n    var threadUrl, resNum, result, doms;\r\n    return __generator(this, function (_a) {\r\n        switch (_a.label) {\r\n            case 0:\r\n                threadUrl = globalThis.config.url;\r\n                resNum = globalThis.config.resNumber ? Number(globalThis.config.resNumber) : NaN;\r\n                res.header('Content-Type', 'application/json; charset=UTF-8');\r\n                return [4 /*yield*/, exports.getRes(threadUrl, resNum)];\r\n            case 1:\r\n                result = _a.sent();\r\n                result.shift();\r\n                doms = result.map(function (item) { return startServer_1.createDom(item, 'server'); });\r\n                res.send(JSON.stringify(doms));\r\n                return [2 /*return*/];\r\n        }\r\n    });\r\n}); });\r\n/**\r\n * 掲示板のレスを取得する\r\n * @param threadUrl スレのURL\r\n * @param resNum この番号以降を取得する。指定しない場合は最新1件を取得。\r\n */\r\nexports.getRes = function (threadUrl, resNum) { return __awaiter(void 0, void 0, void 0, function () {\r\n    var response, e_1;\r\n    return __generator(this, function (_a) {\r\n        switch (_a.label) {\r\n            case 0:\r\n                _a.trys.push([0, 2, , 3]);\r\n                // リクエストURLを解析し、使用するモジュールを変更する\r\n                bbsModule = analysBBSName(threadUrl);\r\n                return [4 /*yield*/, bbsModule.read(threadUrl, resNum)];\r\n            case 1:\r\n                response = _a.sent();\r\n                globalThis.electron.threadConnectionError = 0;\r\n                console.log(\"[getRes.js] fetch \" + threadUrl + \" resNum = \" + resNum + \", result = \" + response.length);\r\n                return [2 /*return*/, response.map(function (res) {\r\n                        return __assign(__assign({}, res), { imgUrl: readIcons.getRandomIcons() });\r\n                    })];\r\n            case 2:\r\n                e_1 = _a.sent();\r\n                electron_log_1.default.error(e_1);\r\n                // エラー回数が規定回数以上かチェックして、超えてたら通知する\r\n                if (globalThis.config.notifyThreadConnectionErrorLimit > 0) {\r\n                    globalThis.electron.threadConnectionError += 1;\r\n                    if (globalThis.electron.threadConnectionError >= globalThis.config.notifyThreadConnectionErrorLimit) {\r\n                        electron_log_1.default.info('[getRes] エラー回数超過');\r\n                        globalThis.electron.threadConnectionError = 0;\r\n                        return [2 /*return*/, [\r\n                                {\r\n                                    name: 'unacastより',\r\n                                    imgUrl: './img/unacast.png',\r\n                                    text: '掲示板が規定回数通信エラーになりました。設定を見直すか、掲示板URLを変更してください。',\r\n                                },\r\n                            ]];\r\n                    }\r\n                }\r\n                return [2 /*return*/, []];\r\n            case 3: return [2 /*return*/];\r\n        }\r\n    });\r\n}); };\r\n/*\r\n * URLをみてどこのBBSか判定して使用するモジュールを返却する\r\n */\r\nvar analysBBSName = function (threadUrl) {\r\n    // したらばドメイン名\r\n    var sitarabaDomain = 'jbbs.shitaraba.net';\r\n    // こんな感じで必要に応じて増やしていけばいいんじゃね?\r\n    // const dokkanoBBS = 'dokka.bbs.com';\r\n    if (threadUrl.indexOf(sitarabaDomain) !== -1) {\r\n        // URLにしたらばドメイン名が入ってればしたらば\r\n        return sitaraba;\r\n    }\r\n    // どこにも該当しなかったらとりあえず5chで\r\n    // この辺も対応ドメインリストとか作ってちゃんと判定したほうがよさそう\r\n    return read5ch;\r\n};\r\nexports.default = router;\r\n","\"use strict\";\r\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\r\n    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n    return new (P || (P = Promise))(function (resolve, reject) {\r\n        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n        function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n        step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n    });\r\n};\r\nvar __generator = (this && this.__generator) || function (thisArg, body) {\r\n    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n    return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n    function verb(n) { return function (v) { return step([n, v]); }; }\r\n    function step(op) {\r\n        if (f) throw new TypeError(\"Generator is already executing.\");\r\n        while (_) try {\r\n            if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n            if (y = 0, t) op = [op[0] & 2, t.value];\r\n            switch (op[0]) {\r\n                case 0: case 1: t = op; break;\r\n                case 4: _.label++; return { value: op[1], done: false };\r\n                case 5: _.label++; y = op[1]; op = [0]; continue;\r\n                case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n                default:\r\n                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n                    if (t[2]) _.ops.pop();\r\n                    _.trys.pop(); continue;\r\n            }\r\n            op = body.call(thisArg, _);\r\n        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n    }\r\n};\r\nvar __importDefault = (this && this.__importDefault) || function (mod) {\r\n    return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n};\r\nvar __importStar = (this && this.__importStar) || function (mod) {\r\n    if (mod && mod.__esModule) return mod;\r\n    var result = {};\r\n    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];\r\n    result[\"default\"] = mod;\r\n    return result;\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\n// Electronのモジュール\r\nvar path_1 = __importDefault(require(\"path\"));\r\nvar electron_1 = __importStar(require(\"electron\"));\r\nvar electron_log_1 = __importDefault(require(\"electron-log\"));\r\nvar util_1 = require(\"./util\");\r\nvar electron_window_state_1 = __importDefault(require(\"electron-window-state\"));\r\nconsole.trace = function () {\r\n    //\r\n};\r\nprocess.on('uncaughtException', function (err) {\r\n    electron_log_1.default.error(err);\r\n});\r\n// アプリケーションをコントロールするモジュール\r\nvar app = electron_1.default.app;\r\n// 多重起動防止\r\nif (!app.requestSingleInstanceLock()) {\r\n    electron_log_1.default.error('[app] It is terminated for multiple launches.');\r\n    app.quit();\r\n}\r\nelse {\r\n    electron_log_1.default.info('[app] started');\r\n    app.allowRendererProcessReuse = true;\r\n    var iconPath_1 = path_1.default.resolve(__dirname, '../icon.png');\r\n    // サーバー起動モジュール\r\n    // eslint-disable-next-line @typescript-eslint/no-var-requires\r\n    var ss = require('./startServer');\r\n    console.trace(ss);\r\n    // メインウィンドウはGCされないようにグローバル宣言\r\n    globalThis.electron = {\r\n        mainWindow: null,\r\n        chatWindow: null,\r\n        seList: [],\r\n        twitchChat: null,\r\n        youtubeChat: null,\r\n        niconicoChat: null,\r\n        threadConnectionError: 0,\r\n        threadNumber: 0,\r\n        commentQueueList: [],\r\n    };\r\n    globalThis.config = {};\r\n    // 全てのウィンドウが閉じたら終了\r\n    // app.on('window-all-closed', () => {\r\n    //   if (process.platform != 'darwin') {\r\n    //     app.quit();\r\n    //   }\r\n    // });\r\n    // Electronの初期化完了後に実行\r\n    app.on('ready', function () {\r\n        var windowState = electron_window_state_1.default({\r\n            defaultWidth: 700,\r\n            defaultHeight: 720,\r\n            file: 'mainWindow.json',\r\n        });\r\n        // ウィンドウサイズを(フレームサイズを含まない)設定\r\n        var mainWin = new electron_1.default.BrowserWindow({\r\n            // 前回起動時のを復元\r\n            x: windowState.x,\r\n            y: windowState.y,\r\n            width: windowState.width,\r\n            height: windowState.height,\r\n            useContentSize: true,\r\n            icon: iconPath_1,\r\n            webPreferences: {\r\n                nodeIntegration: true,\r\n            },\r\n            skipTaskbar: true,\r\n        });\r\n        globalThis.electron.mainWindow = mainWin;\r\n        windowState.manage(mainWin);\r\n        mainWin.setTitle('unacast');\r\n        mainWin.setMenu(null);\r\n        // レンダラーで使用するhtmlファイルを指定する\r\n        mainWin.loadURL(path_1.default.resolve(__dirname, '../src/html/index.html'));\r\n        // ウィンドウが閉じられたらアプリも終了\r\n        mainWin.on('close', function (event) {\r\n            // 確認ダイアログではいをクリックしたら閉じる\r\n            event.preventDefault();\r\n            electron_1.dialog\r\n                .showMessageBox(mainWin, {\r\n                type: 'question',\r\n                buttons: ['Yes', 'No'],\r\n                // title: '',\r\n                message: '終了しますか?',\r\n            })\r\n                .then(function (value) {\r\n                if (value.response === 0) {\r\n                    app.exit();\r\n                }\r\n            });\r\n        });\r\n        mainWin.on('closed', function () {\r\n            electron_log_1.default.info('[app] close');\r\n            app.exit();\r\n        });\r\n        // 開発者ツールを開く\r\n        // mainWin.webContents.openDevTools();\r\n        // タスクトレイの設定\r\n        var tray = null;\r\n        app.whenReady().then(function () {\r\n            tray = new electron_1.Tray(iconPath_1);\r\n            var contextMenu = electron_1.Menu.buildFromTemplate([\r\n                {\r\n                    label: '設定',\r\n                    click: function () {\r\n                        globalThis.electron.mainWindow.focus();\r\n                    },\r\n                },\r\n                {\r\n                    label: 'コメント',\r\n                    click: function () {\r\n                        globalThis.electron.chatWindow.focus();\r\n                    },\r\n                },\r\n                {\r\n                    label: '終了',\r\n                    click: function () {\r\n                        globalThis.electron.mainWindow.close();\r\n                    },\r\n                },\r\n            ]);\r\n            tray.setToolTip('∈(゚◎゚)∋ウナー');\r\n            tray.setContextMenu(contextMenu);\r\n            // タスクトレイクリック時の挙動\r\n            var isDoubleClicked = false;\r\n            tray.on('click', function (event) { return __awaiter(void 0, void 0, void 0, function () {\r\n                return __generator(this, function (_a) {\r\n                    switch (_a.label) {\r\n                        case 0:\r\n                            isDoubleClicked = false;\r\n                            return [4 /*yield*/, util_1.sleep(200)];\r\n                        case 1:\r\n                            _a.sent();\r\n                            if (isDoubleClicked)\r\n                                return [2 /*return*/];\r\n                            globalThis.electron.chatWindow.focus();\r\n                            return [2 /*return*/];\r\n                    }\r\n                });\r\n            }); });\r\n            tray.on('double-click', function (event) {\r\n                isDoubleClicked = true;\r\n                globalThis.electron.mainWindow.focus();\r\n            });\r\n        });\r\n        createChatWindow();\r\n    });\r\n    // 音声再生できるようにする\r\n    app.commandLine.appendSwitch('--autoplay-policy', 'no-user-gesture-required');\r\n}\r\nvar createChatWindow = function () {\r\n    var windowState = electron_window_state_1.default({\r\n        defaultWidth: 400,\r\n        defaultHeight: 720,\r\n        file: 'chatWindow.json',\r\n    });\r\n    var iconPath = path_1.default.resolve(__dirname, '../icon.png');\r\n    var chatWindow = new electron_1.default.BrowserWindow({\r\n        x: windowState.x,\r\n        y: windowState.y,\r\n        width: windowState.width,\r\n        height: windowState.height,\r\n        useContentSize: true,\r\n        icon: iconPath,\r\n        webPreferences: {\r\n            nodeIntegration: true,\r\n        },\r\n        // タスクバーに表示しない\r\n        skipTaskbar: true,\r\n        // 閉じれなくする\r\n        closable: false,\r\n    });\r\n    windowState.manage(chatWindow);\r\n    chatWindow.setTitle('unacast');\r\n    chatWindow.setMenu(null);\r\n    // レンダラーで使用するhtmlファイルを指定する\r\n    chatWindow.loadURL(path_1.default.resolve(__dirname, '../src/html/chat.html'));\r\n    globalThis.electron.chatWindow = chatWindow;\r\n    // chatWindow.webContents.openDevTools();\r\n};\r\n","\"use strict\";\r\nvar __extends = (this && this.__extends) || (function () {\r\n    var extendStatics = function (d, b) {\r\n        extendStatics = Object.setPrototypeOf ||\r\n            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };\r\n        return extendStatics(d, b);\r\n    };\r\n    return function (d, b) {\r\n        extendStatics(d, b);\r\n        function __() { this.constructor = d; }\r\n        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n    };\r\n})();\r\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\r\n    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n    return new (P || (P = Promise))(function (resolve, reject) {\r\n        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n        function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n        step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n    });\r\n};\r\nvar __generator = (this && this.__generator) || function (thisArg, body) {\r\n    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n    return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n    function verb(n) { return function (v) { return step([n, v]); }; }\r\n    function step(op) {\r\n        if (f) throw new TypeError(\"Generator is already executing.\");\r\n        while (_) try {\r\n            if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n            if (y = 0, t) op = [op[0] & 2, t.value];\r\n            switch (op[0]) {\r\n                case 0: case 1: t = op; break;\r\n                case 4: _.label++; return { value: op[1], done: false };\r\n                case 5: _.label++; y = op[1]; op = [0]; continue;\r\n                case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n                default:\r\n                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n                    if (t[2]) _.ops.pop();\r\n                    _.trys.pop(); continue;\r\n            }\r\n            op = body.call(thisArg, _);\r\n        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n    }\r\n};\r\nvar __importDefault = (this && this.__importDefault) || function (mod) {\r\n    return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\n/**\r\n * ニコ生コメント\r\n */\r\nvar events_1 = require(\"events\");\r\nvar axios_1 = __importDefault(require(\"axios\"));\r\nvar cheerio_1 = __importDefault(require(\"cheerio\"));\r\nvar electron_log_1 = __importDefault(require(\"electron-log\"));\r\nvar util_1 = require(\"../util\");\r\nvar ws_1 = __importDefault(require(\"ws\"));\r\nvar NiconamaComment = /** @class */ (function (_super) {\r\n    __extends(NiconamaComment, _super);\r\n    function NiconamaComment(options) {\r\n        var _this = _super.call(this) || this;\r\n        /** 配信開始待ちのインターバル(ms) */\r\n        _this.waitBroadcastPollingInterval = 5000;\r\n        /** 初期処理のコメントを受信し終わった */\r\n        _this.isFirstCommentReceived = false;\r\n        /** 最新のコメント番号 */\r\n        _this.latestNo = NaN;\r\n        /** コメント取得のWebSocket */\r\n        _this.commentSocket = null;\r\n        /** ニコ生の配信開始待ち */\r\n        _this.pollingStartBroadcast = function () { return __awaiter(_this, void 0, void 0, function () {\r\n            var url, res, $, embeddedData, e_1;\r\n            var _a;\r\n            return __generator(this, function (_b) {\r\n                switch (_b.label) {\r\n                    case 0:\r\n                        url = \"https://live2.nicovideo.jp/watch/\" + this.communityId;\r\n                        electron_log_1.default.info(\"[pollingStartBroadcast] \" + url);\r\n                        _b.label = 1;\r\n                    case 1:\r\n                        _b.trys.push([1, 6, , 8]);\r\n                        return [4 /*yield*/, axios_1.default.get(url)];\r\n                    case 2:\r\n                        res = _b.sent();\r\n                        $ = cheerio_1.default.load(res.data);\r\n                        embeddedData = JSON.parse((_a = $('#embedded-data').attr('data-props')) !== null && _a !== void 0 ? _a : '');\r\n                        if (!(embeddedData.program.status === 'ENDED' || embeddedData.program.endTime * 1000 < new Date().getTime())) return [3 /*break*/, 4];\r\n                        return [4 /*yield*/, util_1.sleep(this.waitBroadcastPollingInterval)];\r\n                    case 3:\r\n                        _b.sent();\r\n                        this.pollingStartBroadcast();\r\n                        return [3 /*break*/, 5];\r\n                    case 4:\r\n                        // 始まってる\r\n                        this.emit('start');\r\n                        this.fetchCommentServerThread();\r\n                        _b.label = 5;\r\n                    case 5: return [3 /*break*/, 8];\r\n                    case 6:\r\n                        e_1 = _b.sent();\r\n                        this.emit('error', new Error(\"connection error to \" + url));\r\n                        return [4 /*yield*/, util_1.sleep(this.waitBroadcastPollingInterval * 2)];\r\n                    case 7:\r\n                        _b.sent();\r\n                        this.pollingStartBroadcast();\r\n                        return [3 /*break*/, 8];\r\n                    case 8: return [2 /*return*/];\r\n                }\r\n            });\r\n        }); };\r\n        /** ニコ生のコメントを取得 */\r\n        _this.fetchCommentServerThread = function () { return __awaiter(_this, void 0, void 0, function () {\r\n            var url, res, $, embeddedData, broadcastId, audienceToken, frontendId, threadWssUrl, tWs;\r\n            var _this = this;\r\n            var _a;\r\n            return __generator(this, function (_b) {\r\n                switch (_b.label) {\r\n                    case 0:\r\n                        electron_log_1.default.info(\"[fetchCommentServerThread]\");\r\n                        url = \"https://live2.nicovideo.jp/watch/\" + this.communityId;\r\n                        return [4 /*yield*/, axios_1.default.get(url)];\r\n                    case 1:\r\n                        res = _b.sent();\r\n                        $ = cheerio_1.default.load(res.data);\r\n                        embeddedData = JSON.parse((_a = $('#embedded-data').attr('data-props')) !== null && _a !== void 0 ? _a : '');\r\n                        broadcastId = embeddedData.program.broadcastId || embeddedData.program.reliveProgramId;\r\n                        audienceToken = embeddedData.player.audienceToken;\r\n                        frontendId = embeddedData.site.frontendId;\r\n                        threadWssUrl = \"wss://a.live2.nicovideo.jp/unama/wsapi/v2/watch/\" + broadcastId + \"?audience_token=\" + audienceToken + \"&frontend_id=\" + frontendId;\r\n                        electron_log_1.default.info(threadWssUrl);\r\n                        tWs = new ws_1.default(threadWssUrl);\r\n                        tWs.onmessage = function (event) {\r\n                            var obj = JSON.parse(event.data.toString());\r\n                            // log.info(JSON.stringify(obj, null, '  '));\r\n                            electron_log_1.default.info(\"[fetchCommentServerThread]WS - type: \" + obj.type);\r\n                            switch (obj.type) {\r\n                                case 'serverTime': {\r\n                                    // currentMs\r\n                                    break;\r\n                                }\r\n                                case 'seat': {\r\n                                    // keepIntervalSec\r\n                                    break;\r\n                                }\r\n                                case 'stream': {\r\n                                    // hlsのURLとか\r\n                                    break;\r\n                                }\r\n                                case 'room': {\r\n                                    var data = obj.data;\r\n                                    _this.fetchComment(data.messageServer.uri, data.threadId);\r\n                                    break;\r\n                                }\r\n                                case 'statistics': {\r\n                                    // 視聴者数とか\r\n                                    break;\r\n                                }\r\n                                case 'schedule': {\r\n                                    // 開始、終了時刻\r\n                                    break;\r\n                                }\r\n                                case 'akashic': {\r\n                                    var data = obj.data;\r\n                                    break;\r\n                                }\r\n                                case 'ping': {\r\n                                    break;\r\n                                }\r\n                                // 切断。枠が終了した時もここ。\r\n                                case 'disconnect': {\r\n                                    var data = obj.data;\r\n                                    _this.stop();\r\n                                    _this.start();\r\n                                    break;\r\n                                }\r\n                            }\r\n                        };\r\n                        tWs.on('open', function () {\r\n                            tWs.send(JSON.stringify({\r\n                                type: 'startWatching',\r\n                                data: { stream: { quality: 'high', protocol: 'hls', latency: 'low', chasePlay: false }, room: { protocol: 'webSocket', commentable: true }, reconnect: false },\r\n                            }));\r\n                            tWs.send(JSON.stringify({ type: 'getAkashic', data: { chasePlay: false } }));\r\n                        });\r\n                        return [2 /*return*/];\r\n                }\r\n            });\r\n        }); };\r\n        /**\r\n         *\r\n         * @param wsUrl コメントサーバのWebSocket URL\r\n         * @param threadId threadID\r\n         */\r\n        _this.fetchComment = function (wsUrl, threadId) { return __awaiter(_this, void 0, void 0, function () {\r\n            var ws;\r\n            var _this = this;\r\n            return __generator(this, function (_a) {\r\n                electron_log_1.default.info(\"[fetchComment] threadId = \" + threadId);\r\n                ws = new ws_1.default(wsUrl, 'niconama', {\r\n                    headers: {\r\n                        'Sec-WebSocket-Extensions': 'permessage-deflate; client_max_window_bits',\r\n                        'Sec-WebSocket-Protocol': 'msg.nicovideo.jp#json',\r\n                    },\r\n                });\r\n                ws.on('message', function (event) {\r\n                    var _a, _b, _c;\r\n                    var obj = JSON.parse(event.toString());\r\n                    // 初回取得時は ping, ping, thread, chat, chat..., ping, pingの順で受け取る\r\n                    // log.info(JSON.stringify(obj, null, '  '));\r\n                    // コメント番号更新\r\n                    if ((_a = obj === null || obj === void 0 ? void 0 : obj.chat) === null || _a === void 0 ? void 0 : _a.no) {\r\n                        _this.latestNo = obj.chat.no;\r\n                    }\r\n                    if (((_b = obj === null || obj === void 0 ? void 0 : obj.ping) === null || _b === void 0 ? void 0 : _b.content) === 'rf:0') {\r\n                        _this.isFirstCommentReceived = true;\r\n                        _this.emit('open', { liveId: '', number: _this.latestNo });\r\n                    }\r\n                    if (!_this.isFirstCommentReceived)\r\n                        return;\r\n                    var chat = obj;\r\n                    var comment = (_c = chat.chat) === null || _c === void 0 ? void 0 : _c.content;\r\n                    if (!comment)\r\n                        return;\r\n                    // /で始まるのはなんかコマンドなので除外する\r\n                    if (comment.match(/^\\/[a-z]+ /))\r\n                        return;\r\n                    electron_log_1.default.info(\"[fetchComment]WS - content: \" + comment);\r\n                    var item = {\r\n                        number: chat.chat.no.toString(),\r\n                        name: '',\r\n                        comment: comment,\r\n                    };\r\n                    _this.emit('comment', item);\r\n                });\r\n                ws.on('error', function (event) {\r\n                    electron_log_1.default.info('[fetchComment]なんかエラーだ');\r\n                    electron_log_1.default.info(event);\r\n                });\r\n                ws.on('open', function () {\r\n                    electron_log_1.default.info('[fetchComment] connected');\r\n                    ws.send(JSON.stringify([\r\n                        { ping: { content: 'rs:0' } },\r\n                        { ping: { content: 'ps:0' } },\r\n                        // eslint-disable-next-line @typescript-eslint/camelcase\r\n                        { thread: { thread: threadId, version: '20061206', user_id: 'guest', res_from: -150, with_global: 1, scores: 1, nicoru: 0 } },\r\n                        { ping: { content: 'pf:0' } },\r\n                        { ping: { content: 'rf:0' } },\r\n                    ]));\r\n                });\r\n                this.commentSocket = ws;\r\n                return [2 /*return*/];\r\n            });\r\n        }); };\r\n        /** コメント取得の停止 */\r\n        _this.stop = function () {\r\n            _this.isFirstCommentReceived = false;\r\n            _this.latestNo = NaN;\r\n            if (_this.commentSocket)\r\n                _this.commentSocket.close();\r\n            _this.emit('end');\r\n        };\r\n        if ('communityId' in options) {\r\n            _this.communityId = options.communityId;\r\n        }\r\n        else {\r\n            throw TypeError('Required channelId.');\r\n        }\r\n        return _this;\r\n    }\r\n    NiconamaComment.prototype.start = function () {\r\n        return __awaiter(this, void 0, void 0, function () {\r\n            return __generator(this, function (_a) {\r\n                if (this.communityId) {\r\n                    this.emit('wait');\r\n                    this.pollingStartBroadcast();\r\n                }\r\n                return [2 /*return*/];\r\n            });\r\n        });\r\n    };\r\n    NiconamaComment.prototype.on = function (event, listener) {\r\n        return _super.prototype.on.call(this, event, listener);\r\n    };\r\n    return NiconamaComment;\r\n}(events_1.EventEmitter));\r\nexports.default = NiconamaComment;\r\n","\"use strict\";\r\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\r\n    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n    return new (P || (P = Promise))(function (resolve, reject) {\r\n        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n        function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n        step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n    });\r\n};\r\nvar __generator = (this && this.__generator) || function (thisArg, body) {\r\n    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n    return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n    function verb(n) { return function (v) { return step([n, v]); }; }\r\n    function step(op) {\r\n        if (f) throw new TypeError(\"Generator is already executing.\");\r\n        while (_) try {\r\n            if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n            if (y = 0, t) op = [op[0] & 2, t.value];\r\n            switch (op[0]) {\r\n                case 0: case 1: t = op; break;\r\n                case 4: _.label++; return { value: op[1], done: false };\r\n                case 5: _.label++; y = op[1]; op = [0]; continue;\r\n                case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n                default:\r\n                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n                    if (t[2]) _.ops.pop();\r\n                    _.trys.pop(); continue;\r\n            }\r\n            op = body.call(thisArg, _);\r\n        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n    }\r\n};\r\nvar __importDefault = (this && this.__importDefault) || function (mod) {\r\n    return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\n/**\r\n * 5ch互換BBS読み込み用モジュール\r\n */\r\nvar axios_1 = __importDefault(require(\"axios\"));\r\nvar https_1 = __importDefault(require(\"https\"));\r\nvar iconv_lite_1 = __importDefault(require(\"iconv-lite\")); // 文字コード変換用パッケージ\r\nvar electron_log_1 = __importDefault(require(\"electron-log\"));\r\n// ステータスコード304 _NotModified\r\nvar NOT_MODIFIED = '304';\r\nvar RANGE_NOT_SATISFIABLE = '416';\r\n// 最終取得スレッド\r\nvar lastThreadUrl = '';\r\n// 最終レス番号\r\nvar lastResNumber = 0;\r\n//最終更新日時\r\nvar lastModified = null;\r\n// 最終バイト数\r\nvar lastByte = 0;\r\n/**\r\n * コンストラクタ\r\n *\r\n */\r\nvar Read5ch = /** @class */ (function () {\r\n    function Read5ch() {\r\n        var _this = this;\r\n        // constructor() {}\r\n        /**\r\n         * レス読み込み\r\n         * 引数で指定した板からレスを読む\r\n         * レス番号を指定していない場合は最新1件取得\r\n         * @param threadUrl スレURL\r\n         * @param resNum レス番号\r\n         */\r\n        this.read = function (threadUrl, resNum) { return __awaiter(_this, void 0, void 0, function () {\r\n            var rep, requestUrl, range, options, instance, responseJson, response, headers, str, error_1;\r\n            return __generator(this, function (_a) {\r\n                switch (_a.label) {\r\n                    case 0:\r\n                        // log.info(`[Read5ch] threadUrl=${threadUrl} resNum=${resNum}`);\r\n                        // 板や最終日レス番号がかわったら最初からとり直す(lastmodifiと rangeのリセット)\r\n                        if (threadUrl != lastThreadUrl || Number.isNaN(resNum) || resNum < lastResNumber) {\r\n                            lastThreadUrl = threadUrl;\r\n                            lastModified = null;\r\n                            lastByte = 0;\r\n                            console.trace('[Read5ch.js]resete!!!!!!!!!!!!!!!!');\r\n                        }\r\n                        else {\r\n                            console.trace('noresete');\r\n                        }\r\n                        rep = /\\/test\\/read.cgi(\\/.+)(\\/.+)\\//;\r\n                        requestUrl = threadUrl.replace(rep, '$1/dat$2.dat');\r\n                        range = lastByte;\r\n                        options = {\r\n                            url: requestUrl,\r\n                            method: 'GET',\r\n                            timeout: 3 * 1000,\r\n                            responseType: 'arraybuffer',\r\n                            headers: {\r\n                                'if-modified-since': lastModified,\r\n                                range: 'bytes=' + range + '-',\r\n                            },\r\n                        };\r\n                        instance = axios_1.default.create({\r\n                            httpsAgent: new https_1.default.Agent({\r\n                                rejectUnauthorized: false,\r\n                            }),\r\n                        });\r\n                        _a.label = 1;\r\n                    case 1:\r\n                        _a.trys.push([1, 3, , 4]);\r\n                        return [4 /*yield*/, instance(options)];\r\n                    case 2:\r\n                        response = _a.sent();\r\n                        headers = response.headers;\r\n                        // LastModifiedとRange更新処理\r\n                        if (headers['last-modified'] != null) {\r\n                            lastModified = headers['last-modified'];\r\n                        }\r\n                        str = iconv_lite_1.default.decode(Buffer.from(response.data), 'Shift_JIS');\r\n                        // レスポンスオブジェクト作成、content-rangeがある場合とない場合で処理を分ける\r\n                        if (headers['content-range'] == null || lastByte == 0) {\r\n                            console.trace('[Read5ch.read]content-range=' + headers['content-range']);\r\n                            responseJson = purseNewResponse(str, resNum);\r\n                        }\r\n                        else {\r\n                            responseJson = purseDiffResponse(str, resNum);\r\n                        }\r\n                        // 取得バイト数表示\r\n                        if (headers['content-length'] != null && responseJson.length > 0) {\r\n                            lastByte = lastByte + parseInt(headers['content-length']) - 1;\r\n                            console.trace('[Read5ch.read]lastByte=' + lastByte);\r\n                        }\r\n                        return [3 /*break*/, 4];\r\n                    case 3:\r\n                        error_1 = _a.sent();\r\n                        responseJson = [];\r\n                        if (error_1.status == NOT_MODIFIED) {\r\n                            electron_log_1.default.error('[Read5ch.js]5ch系BBSレス取得APIリクエストエラー、NOT_MODIFIED');\r\n                        }\r\n                        else if (error_1.status == RANGE_NOT_SATISFIABLE) {\r\n                            electron_log_1.default.error('[Read5ch.js]5ch系BBSレス取得APIリクエストエラー、RANGE_NOT_SATISFIABLE');\r\n                        }\r\n                        else {\r\n                            electron_log_1.default.error('[Read5ch.js]5ch系BBSレス取得APIリクエストエラー、message=' + error_1.message);\r\n                        }\r\n                        throw new Error('connection error');\r\n                    case 4: return [2 /*return*/, responseJson];\r\n                }\r\n            });\r\n        }); };\r\n    }\r\n    return Read5ch;\r\n}());\r\n/**\r\n * 取得したレスポンス(複数)のパース\r\n * 戻りとしてパースしたjsonオブジェクトの配列を返す\r\n * @param res 板から返却されたdat\r\n * @param resNum リクエストされたレス番号\r\n */\r\nvar purseNewResponse = function (res, resNum) {\r\n    // 結果を格納する配列\r\n    var result = [];\r\n    // レス番号\r\n    var num = 0;\r\n    // 新着レスを改行ごとにSplitする\r\n    var resArray = res.split(/\\r\\n|\\r|\\n/);\r\n    // 新着なしなら戻る。\r\n    if (resArray.length === 0) {\r\n        return result;\r\n    }\r\n    // 配列の最後に空の要素が入ることがあるので取り除く\r\n    if (resArray[resArray.length - 1].length === 0) {\r\n        resArray.pop();\r\n    }\r\n    // レス指定なしの場合最後の1件取得\r\n    if (Number.isNaN(resNum)) {\r\n        num = resArray.length - 1;\r\n    }\r\n    else {\r\n        num = resNum - 1;\r\n    }\r\n    // 1行ごとにパースする\r\n    for (; num < resArray.length; num++) {\r\n        // パースメソッド呼び出し\r\n        if (resArray[num].length > 0) {\r\n            result.push(purseResponse(resArray[num], num + 1));\r\n        }\r\n    }\r\n    lastResNumber = num + 1;\r\n    // パースしたオブジェクトの配列を返却\r\n    return result;\r\n};\r\n/**\r\n * 取得したレスポンス(複数)のパース\r\n * 戻りとしてパースしたjsonオブジェクトの配列を返す\r\n * @param res 板から返却されたdat1行分\r\n * @param resNum リクエストされたレス番号\r\n */\r\nvar purseDiffResponse = function (res, resNum) {\r\n    //結果を格納する配列\r\n    var result = [];\r\n    // レス番号\r\n    var num = resNum;\r\n    //新着レスを改行ごとにSplitする\r\n    var resArray = res.split(/\\r\\n|\\r|\\n/);\r\n    // 新着なしなら戻る。\r\n    if (resArray.length === 0) {\r\n        return result;\r\n    }\r\n    else {\r\n        // 配列の最後に空の要素が入ることがあるので取り除く\r\n        if (resArray[resArray.length - 1].length == 0) {\r\n            resArray.pop();\r\n        }\r\n    }\r\n    console.trace('[Read5ch.purseDiffResponse]取得レス番号=' + num);\r\n    //1行ごとにパースする\r\n    resArray.forEach(function (value) {\r\n        //パースメソッド呼び出し\r\n        if (value.length > 0) {\r\n            result.push(purseResponse(value, num));\r\n            num++;\r\n        }\r\n    });\r\n    // パースしたオブジェクトの配列を返却\r\n    return result;\r\n};\r\n/**\r\n * レスポンスのパース\r\n * Jsonオブジェクトを返却する\r\n * @param String // res レスポンス1レス\r\n * @param Integer // num レス番(0スタート)\r\n */\r\nvar purseResponse = function (res, num) {\r\n    //APIの返却値を<>で分割\r\n    //レスの要素\r\n    //0:名前\r\n    //1:メアド\r\n    //2:日付とID (2019/11/03(日) 08:55:00 ID:kanikani)みたいに表示\r\n    //3:本文\r\n    //4:スレタイ (1レス目のみ)\r\n    var splitRes = res.split('<>');\r\n    // 日付とID分離処理、' ID:'で区切る\r\n    var dateId = splitRes[2].split(' ID:');\r\n    var date = dateId[0];\r\n    var id = dateId.length === 2 ? dateId[1] : '';\r\n    var resJson = {\r\n        number: num.toString(),\r\n        name: splitRes[0],\r\n        email: splitRes[1],\r\n        date: date,\r\n        text: splitRes[3],\r\n        // threadTitle: splitRes[4],\r\n        id: id,\r\n        imgUrl: '',\r\n    };\r\n    // オブジェクトを返却\r\n    return resJson;\r\n};\r\nexports.default = Read5ch;\r\n","\"use strict\";\r\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\r\n    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n    return new (P || (P = Promise))(function (resolve, reject) {\r\n        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n        function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n        step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n    });\r\n};\r\nvar __generator = (this && this.__generator) || function (thisArg, body) {\r\n    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n    return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n    function verb(n) { return function (v) { return step([n, v]); }; }\r\n    function step(op) {\r\n        if (f) throw new TypeError(\"Generator is already executing.\");\r\n        while (_) try {\r\n            if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n            if (y = 0, t) op = [op[0] & 2, t.value];\r\n            switch (op[0]) {\r\n                case 0: case 1: t = op; break;\r\n                case 4: _.label++; return { value: op[1], done: false };\r\n                case 5: _.label++; y = op[1]; op = [0]; continue;\r\n                case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n                default:\r\n                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n                    if (t[2]) _.ops.pop();\r\n                    _.trys.pop(); continue;\r\n            }\r\n            op = body.call(thisArg, _);\r\n        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n    }\r\n};\r\nvar __importDefault = (this && this.__importDefault) || function (mod) {\r\n    return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\n/**\r\n * したらば読み込み用モジュール\r\n */\r\nvar axios_1 = __importDefault(require(\"axios\"));\r\nvar https_1 = __importDefault(require(\"https\"));\r\nvar iconv_lite_1 = __importDefault(require(\"iconv-lite\")); // 文字コード変換用パッケージ\r\n/**\r\n * コンストラクタ\r\n */\r\nvar ReadSitaraba = /** @class */ (function () {\r\n    function ReadSitaraba() {\r\n        // constructor() {}\r\n        var _this = this;\r\n        /**\r\n         * レス読み込み\r\n         * @description 引数で指定した板からレスを読む。\r\n         * @description レス番号を指定していない場合は最新1件取得\r\n         * @param threadUrl スレURL\r\n         * @param resNum レス番号\r\n         */\r\n        this.read = function (threadUrl, resNum) { return __awaiter(_this, void 0, void 0, function () {\r\n            var requestUrl, options, instance, response, str, responseJson;\r\n            return __generator(this, function (_a) {\r\n                switch (_a.label) {\r\n                    case 0:\r\n                        requestUrl = threadUrl.replace('read.cgi', 'rawmode.cgi');\r\n                        if (resNum > 0) {\r\n                            // レス番号がある場合レス番号以降を取得\r\n                            requestUrl += resNum + '-';\r\n                        }\r\n                        else {\r\n                            // レス番号がない場合最新の1件取得\r\n                            requestUrl += 'l1';\r\n                        }\r\n                        options = {\r\n                            url: requestUrl,\r\n                            method: 'GET',\r\n                            responseType: 'arraybuffer',\r\n                            timeout: 3 * 1000,\r\n                            headers: {\r\n                                Accept: '*/*',\r\n                            },\r\n                        };\r\n                        instance = axios_1.default.create({\r\n                            httpsAgent: new https_1.default.Agent({\r\n                                rejectUnauthorized: false,\r\n                            }),\r\n                        });\r\n                        return [4 /*yield*/, instance(options)];\r\n                    case 1:\r\n                        response = _a.sent();\r\n                        str = decodeUnicodeStr(iconv_lite_1.default.decode(Buffer.from(response.data), 'EUC-JP'));\r\n                        responseJson = purseNewResponse(str);\r\n                        return [2 /*return*/, responseJson];\r\n                }\r\n            });\r\n        }); };\r\n    }\r\n    return ReadSitaraba;\r\n}());\r\n/**\r\n * 取得したレスポンス(複数)のパース\r\n * @param res\r\n */\r\nvar purseNewResponse = function (res) {\r\n    //結果を格納する配列\r\n    var result = [];\r\n    // 新着レスを改行ごとにSplitする\r\n    var resArray = res.split(/\\r\\n|\\r|\\n/);\r\n    // 1行ごとにパースする\r\n    resArray.forEach(function (value) {\r\n        // パースメソッド呼び出し\r\n        if (value.length > 0) {\r\n            result.push(purseResponse(value));\r\n        }\r\n    });\r\n    return result;\r\n};\r\n/**\r\n * レスポンスのパース\r\n * Jsonオブジェクトを返却する\r\n * @param String // res レスポンス1レス\r\n */\r\nvar purseResponse = function (res) {\r\n    //APIの返却値を<>で分割\r\n    //レスの要素\r\n    //0:レス番号\r\n    //1:名前\r\n    //2:メアド\r\n    //3:日付\r\n    //4:本文\r\n    //5:スレタイ\r\n    //6:ID\r\n    var splitRes = res.split('<>');\r\n    var resJson = {\r\n        number: splitRes[0],\r\n        name: splitRes[1],\r\n        email: splitRes[2],\r\n        date: splitRes[3],\r\n        text: splitRes[4],\r\n        // threadTitle: splitRes[5],\r\n        id: splitRes[6],\r\n        imgUrl: '',\r\n    };\r\n    // オブジェクトを返却\r\n    return resJson;\r\n};\r\n/** したらばだけは全角ダッシュがUnicode文字列として格納されるので変換する */\r\nvar decodeUnicodeStr = function (str) {\r\n    return str.replace(/&#65374;/g, '~');\r\n};\r\nexports.default = ReadSitaraba;\r\n","\"use strict\";\r\nvar __assign = (this && this.__assign) || function () {\r\n    __assign = Object.assign || function(t) {\r\n        for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n            s = arguments[i];\r\n            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))\r\n                t[p] = s[p];\r\n        }\r\n        return t;\r\n    };\r\n    return __assign.apply(this, arguments);\r\n};\r\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\r\n    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n    return new (P || (P = Promise))(function (resolve, reject) {\r\n        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n        function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n        step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n    });\r\n};\r\nvar __generator = (this && this.__generator) || function (thisArg, body) {\r\n    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n    return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n    function verb(n) { return function (v) { return step([n, v]); }; }\r\n    function step(op) {\r\n        if (f) throw new TypeError(\"Generator is already executing.\");\r\n        while (_) try {\r\n            if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n            if (y = 0, t) op = [op[0] & 2, t.value];\r\n            switch (op[0]) {\r\n                case 0: case 1: t = op; break;\r\n                case 4: _.label++; return { value: op[1], done: false };\r\n                case 5: _.label++; y = op[1]; op = [0]; continue;\r\n                case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n                default:\r\n                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n                    if (t[2]) _.ops.pop();\r\n                    _.trys.pop(); continue;\r\n            }\r\n            op = body.call(thisArg, _);\r\n        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n    }\r\n};\r\nvar __spreadArrays = (this && this.__spreadArrays) || function () {\r\n    for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n    for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n        for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n            r[k] = a[j];\r\n    return r;\r\n};\r\nvar __importDefault = (this && this.__importDefault) || function (mod) {\r\n    return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n};\r\nvar __importStar = (this && this.__importStar) || function (mod) {\r\n    if (mod && mod.__esModule) return mod;\r\n    var result = {};\r\n    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];\r\n    result[\"default\"] = mod;\r\n    return result;\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar path_1 = __importDefault(require(\"path\"));\r\nvar express_1 = __importDefault(require(\"express\"));\r\nvar electron_log_1 = __importDefault(require(\"electron-log\"));\r\nvar dank_twitch_irc_1 = require(\"dank-twitch-irc\");\r\nvar youtube_chat_1 = require(\"./youtube-chat\");\r\nvar electron_1 = require(\"electron\");\r\nvar express_ws_1 = __importDefault(require(\"express-ws\"));\r\nvar util_1 = require(\"./util\");\r\n// レス取得APIをセット\r\nvar getRes_1 = __importStar(require(\"./getRes\"));\r\nvar bouyomi_chan_1 = __importDefault(require(\"./bouyomi-chan\"));\r\nvar child_process_1 = require(\"child_process\");\r\nvar const_1 = require(\"./const\");\r\nvar niconama_1 = __importDefault(require(\"./niconama\"));\r\nvar app;\r\n// サーバーをグローバル変数にセットできるようにする(サーバー停止処理のため)\r\nvar server;\r\n/** 棒読みちゃんインスタンス */\r\nvar bouyomi;\r\n/** スレッド定期取得実行するか */\r\nvar threadIntervalEvent = false;\r\n/** キュー処理実行するか */\r\nvar isExecuteQue = false;\r\n/** 接続中の全WebSocket */\r\nvar aWss;\r\nvar serverId = 0;\r\n/**\r\n * 設定の適用\r\n */\r\nelectron_1.ipcMain.on(const_1.electronEvent['apply-config'], function (event, config) { return __awaiter(void 0, void 0, void 0, function () {\r\n    var isChangedUrl, isChangeSePath, ret;\r\n    return __generator(this, function (_a) {\r\n        switch (_a.label) {\r\n            case 0:\r\n                electron_log_1.default.info('[apply-config] start');\r\n                electron_log_1.default.info(config);\r\n                isChangedUrl = globalThis.config.url !== config.url;\r\n                isChangeSePath = globalThis.config.sePath !== config.sePath;\r\n                globalThis.config = config;\r\n                if (!isChangeSePath) return [3 /*break*/, 2];\r\n                return [4 /*yield*/, exports.findSeList()];\r\n            case 1:\r\n                _a.sent();\r\n                _a.label = 2;\r\n            case 2:\r\n                // initメッセージ\r\n                resetInitMessage();\r\n                if (!isChangedUrl) return [3 /*break*/, 4];\r\n                return [4 /*yield*/, getRes_1.getRes(globalThis.config.url, NaN)];\r\n            case 3:\r\n                ret = _a.sent();\r\n                console.log(ret);\r\n                if (ret.length === 0) {\r\n                    globalThis.electron.mainWindow.webContents.send(const_1.electronEvent['show-alert'], '掲示板URLがおかしそうです');\r\n                    return [2 /*return*/];\r\n                }\r\n                globalThis.electron.threadNumber = Number(ret[ret.length - 1].number);\r\n                electron_log_1.default.info(\"[apply-config] new res num is \" + globalThis.electron.threadNumber);\r\n                // チャットウィンドウとブラウザに、末尾のスレだけ反映する\r\n                sendDom([ret[ret.length - 1]]);\r\n                _a.label = 4;\r\n            case 4: return [2 /*return*/];\r\n        }\r\n    });\r\n}); });\r\n/**\r\n * サーバー起動\r\n */\r\nelectron_1.ipcMain.on(const_1.electronEvent['start-server'], function (event, config) { return __awaiter(void 0, void 0, void 0, function () {\r\n    var expressInstance, nico;\r\n    return __generator(this, function (_a) {\r\n        globalThis.electron.chatWindow.webContents.send(const_1.electronEvent['clear-comment']);\r\n        globalThis.electron.threadNumber = 0;\r\n        globalThis.electron.commentQueueList = [];\r\n        globalThis.electron.threadConnectionError = 0;\r\n        serverId = new Date().getTime();\r\n        expressInstance = express_ws_1.default(express_1.default());\r\n        app = expressInstance.app;\r\n        aWss = expressInstance.getWss();\r\n        app.set('view engine', 'ejs');\r\n        // viewディレクトリの指定\r\n        app.set('views', path_1.default.resolve(__dirname, '../views'));\r\n        // 設定情報をグローバル変数へセットする\r\n        globalThis.config = config;\r\n        console.log('[startServer]設定値 = ');\r\n        console.log(globalThis.config);\r\n        app.get('/', function (req, res, next) {\r\n            res.render('server', config);\r\n            req.connection.end();\r\n        });\r\n        // サーバー設定のIF\r\n        app.get('/config', function (req, res, next) {\r\n            res.send(JSON.stringify(globalThis.config));\r\n        });\r\n        // 静的コンテンツはpublicディレクトリの中身を使用するという宣言\r\n        app.use(express_1.default.static(path_1.default.resolve(__dirname, '../public')));\r\n        // 2ch互換掲示板の取得\r\n        app.use('/getRes', getRes_1.default);\r\n        // SEを取得する\r\n        if (globalThis.config.sePath) {\r\n            exports.findSeList();\r\n        }\r\n        // Twitchに接続\r\n        if (globalThis.config.twitchId) {\r\n            startTwitchChat();\r\n        }\r\n        // Youtubeチャット\r\n        if (globalThis.config.youtubeId) {\r\n            startYoutubeChat();\r\n        }\r\n        // ニコ生\r\n        if (globalThis.config.niconicoId) {\r\n            nico = new niconama_1.default({ communityId: globalThis.config.niconicoId });\r\n            globalThis.electron.niconicoChat = nico;\r\n            nico.on('start', function () {\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'niconico', category: 'status', message: \"connection waiting\" });\r\n            });\r\n            nico.on('wait', function () {\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'niconico', category: 'status', message: \"wait for starting boradcast\" });\r\n            });\r\n            nico.on('open', function (event) {\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, {\r\n                    commentType: 'niconico',\r\n                    category: 'status',\r\n                    message: \"ok No=\" + event.number,\r\n                });\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, {\r\n                    commentType: 'niconico',\r\n                    category: 'liveId',\r\n                    message: \"\" + event.liveId,\r\n                });\r\n            });\r\n            nico.on('comment', function (event) {\r\n                globalThis.electron.commentQueueList.push({ imgUrl: './img/niconico.png', number: event.number, name: event.name, text: event.comment });\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, {\r\n                    commentType: 'niconico',\r\n                    category: 'status',\r\n                    message: \"ok No=\" + event.number,\r\n                });\r\n            });\r\n            // 切断とか枠終了とか\r\n            nico.on('end', function () {\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, {\r\n                    commentType: 'niconico',\r\n                    category: 'status',\r\n                    message: \"disconnect\",\r\n                });\r\n            });\r\n            nico.on('error', function () {\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'niconico', category: 'status', message: \"error\" });\r\n            });\r\n            nico.start();\r\n        }\r\n        // 棒読みちゃん接続\r\n        if (config.typeYomiko === 'bouyomi') {\r\n            if (config.bouyomiPort) {\r\n                bouyomi = new bouyomi_chan_1.default({ port: config.bouyomiPort, volume: config.bouyomiVolume });\r\n            }\r\n        }\r\n        // レス取得定期実行\r\n        threadIntervalEvent = true;\r\n        getResInterval(serverId);\r\n        // キュー処理の開始\r\n        isExecuteQue = true;\r\n        taskScheduler(serverId);\r\n        // WebSocketを立てる\r\n        app.ws('/ws', function (ws, req) {\r\n            ws.on('message', function (message) {\r\n                console.trace('Received: ' + message);\r\n                if (message === 'ping') {\r\n                    ws.send('pong');\r\n                }\r\n            });\r\n            ws.on('close', function () {\r\n                console.log('I lost a client');\r\n            });\r\n        });\r\n        // 指定したポートで待ち受け開始\r\n        server = app.listen(config.port, function () {\r\n            console.log('[startServer] start server on port:' + config.port);\r\n        });\r\n        // 成功メッセージ返却\r\n        event.returnValue = 'success';\r\n        return [2 /*return*/];\r\n    });\r\n}); });\r\nexports.findSeList = function () { return __awaiter(void 0, void 0, void 0, function () {\r\n    var list, e_1;\r\n    return __generator(this, function (_a) {\r\n        switch (_a.label) {\r\n            case 0:\r\n                _a.trys.push([0, 4, , 5]);\r\n                if (!globalThis.config.sePath) return [3 /*break*/, 2];\r\n                return [4 /*yield*/, util_1.readWavFiles(globalThis.config.sePath)];\r\n            case 1:\r\n                list = _a.sent();\r\n                globalThis.electron.seList = list.map(function (file) { return globalThis.config.sePath + \"/\" + file; });\r\n                console.log(\"SE files = \" + globalThis.electron.seList.length);\r\n                return [3 /*break*/, 3];\r\n            case 2:\r\n                globalThis.electron.seList = [];\r\n                _a.label = 3;\r\n            case 3: return [3 /*break*/, 5];\r\n            case 4:\r\n                e_1 = _a.sent();\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent['show-alert'], '着信音のパスがおかしそうです');\r\n                return [3 /*break*/, 5];\r\n            case 5: return [2 /*return*/];\r\n        }\r\n    });\r\n}); };\r\n/**\r\n * Twitchチャットに接続\r\n * @description 再接続処理はライブラリが勝手にやってくれる\r\n */\r\nvar startTwitchChat = function () { return __awaiter(void 0, void 0, void 0, function () {\r\n    var twitchChat;\r\n    return __generator(this, function (_a) {\r\n        try {\r\n            twitchChat = new dank_twitch_irc_1.ChatClient();\r\n            twitchChat.connect();\r\n            twitchChat.join(globalThis.config.twitchId);\r\n            globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'twitch', category: 'status', message: 'wait live' });\r\n            // 接続完了\r\n            twitchChat.on('ready', function () {\r\n                console.log('[Twitch] Successfully connected to chat');\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'twitch', category: 'status', message: 'ok' });\r\n            });\r\n            // チャット受信\r\n            twitchChat.on('PRIVMSG', function (msg) {\r\n                electron_log_1.default.info('[Twitch] comment received');\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'twitch', category: 'status', message: 'ok' });\r\n                // log.info(JSON.stringify(msg, null, '  '));\r\n                var imgUrl = './img/twitch.png';\r\n                var name = util_1.escapeHtml(msg.displayName);\r\n                var text = util_1.escapeHtml(msg.messageText);\r\n                // エモートを画像タグにする\r\n                msg.emotes.map(function (emote) {\r\n                    text = text.replace(emote.code, \"<img src=\\\"https://static-cdn.jtvnw.net/emoticons/v1/\" + emote.id + \"/1.0\\\" />\");\r\n                });\r\n                globalThis.electron.commentQueueList.push({ imgUrl: imgUrl, name: name, text: text });\r\n            });\r\n            globalThis.electron.twitchChat = twitchChat;\r\n            // なんかエラーがあった\r\n            twitchChat.on('error', function (event) {\r\n                electron_log_1.default.error(\"[Twitch] \" + JSON.stringify(event));\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'twitch', category: 'status', message: 'error!' });\r\n            });\r\n            twitchChat.on('close', function (event) {\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'twitch', category: 'status', message: 'connection end' });\r\n            });\r\n        }\r\n        catch (e) {\r\n            electron_log_1.default.error(e);\r\n            globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'twitch', category: 'status', message: 'error!' });\r\n        }\r\n        return [2 /*return*/];\r\n    });\r\n}); };\r\n/** Youtubeチャットに接続 */\r\nvar startYoutubeChat = function () { return __awaiter(void 0, void 0, void 0, function () {\r\n    return __generator(this, function (_a) {\r\n        try {\r\n            electron_log_1.default.info('[Youtube Chat] connect started');\r\n            globalThis.electron.youtubeChat = new youtube_chat_1.LiveChat({ channelId: globalThis.config.youtubeId });\r\n            globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'youtube', category: 'status', message: 'wait live' });\r\n            // 接続開始イベント\r\n            globalThis.electron.youtubeChat.on('start', function (liveId) {\r\n                electron_log_1.default.info(\"[Youtube Chat] connected liveId = \" + liveId);\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'youtube', category: 'liveid', message: liveId });\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'youtube', category: 'status', message: 'ok' });\r\n            });\r\n            // 接続終了イベント\r\n            globalThis.electron.youtubeChat.on('end', function (reason) {\r\n                electron_log_1.default.info('[Youtube Chat] disconnect');\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'youtube', category: 'status', message: 'connection end' });\r\n            });\r\n            // チャット受信\r\n            globalThis.electron.youtubeChat.on('comment', function (comment) {\r\n                var _a, _b;\r\n                electron_log_1.default.info('[Youtube] comment received');\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'youtube', category: 'status', message: 'ok' });\r\n                // log.info(JSON.stringify(comment, null, '  '));\r\n                var imgUrl = (_b = (_a = comment.author.thumbnail) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '';\r\n                var name = util_1.escapeHtml(comment.author.name);\r\n                // 絵文字と結合する\r\n                var text = '';\r\n                for (var _i = 0, _c = comment.message; _i < _c.length; _i++) {\r\n                    var message = _c[_i];\r\n                    var txtItem = message.text;\r\n                    if (txtItem) {\r\n                        text += util_1.escapeHtml(txtItem);\r\n                    }\r\n                    else {\r\n                        var imageItem = message;\r\n                        text += \"<img src=\\\"\" + imageItem.url + \"\\\" width=\\\"\" + 24 + \"\\\" height=\\\"\" + 24 + \"\\\" />\";\r\n                    }\r\n                }\r\n                // const text = escapeHtml((comment.message[0] as any).text);\r\n                globalThis.electron.commentQueueList.push({ imgUrl: imgUrl, name: name, text: text });\r\n            });\r\n            // 何かエラーがあった\r\n            globalThis.electron.youtubeChat.on('error', function (err) {\r\n                electron_log_1.default.error(\"[Youtube Chat] error \" + err.message);\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'youtube', category: 'status', message: \"error! \" + err.message });\r\n            });\r\n            globalThis.electron.youtubeChat.start();\r\n        }\r\n        catch (e) {\r\n            // たぶんここには来ない\r\n            electron_log_1.default.error(e);\r\n        }\r\n        return [2 /*return*/];\r\n    });\r\n}); };\r\n/**\r\n * サーバー停止\r\n */\r\nelectron_1.ipcMain.on(const_1.electronEvent['stop-server'], function (event) {\r\n    console.log('[startServer]server stop');\r\n    server.close();\r\n    aWss.close();\r\n    app = null;\r\n    event.returnValue = 'stop';\r\n    // キュー処理停止\r\n    isExecuteQue = false;\r\n    globalThis.electron.commentQueueList = [];\r\n    // レス取得の停止\r\n    threadIntervalEvent = false;\r\n    globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'bbs', category: 'status', message: \"connection end\" });\r\n    // Twitchチャットの停止\r\n    if (globalThis.electron.twitchChat) {\r\n        globalThis.electron.twitchChat.close();\r\n        globalThis.electron.twitchChat.removeAllListeners();\r\n        globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'twitch', category: 'status', message: \"connection end\" });\r\n    }\r\n    // Youtubeチャットの停止\r\n    if (globalThis.electron.youtubeChat) {\r\n        globalThis.electron.youtubeChat.stop();\r\n        globalThis.electron.youtubeChat.removeAllListeners();\r\n        globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'youtube', category: 'status', message: \"connection end\" });\r\n        globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'youtube', category: 'liveId', message: \"none\" });\r\n    }\r\n    // ニコ生チャットの停止\r\n    if (globalThis.electron.niconicoChat) {\r\n        globalThis.electron.niconicoChat.stop();\r\n        globalThis.electron.niconicoChat.removeAllListeners();\r\n        globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'niconico', category: 'status', message: \"connection end\" });\r\n        globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'niconico', category: 'liveId', message: \"none\" });\r\n    }\r\n});\r\nvar getResInterval = function (exeId) { return __awaiter(void 0, void 0, void 0, function () {\r\n    var resNum, isfirst, result, temp, _loop_1, _i, result_1, item;\r\n    return __generator(this, function (_a) {\r\n        switch (_a.label) {\r\n            case 0:\r\n                isfirst = false;\r\n                if (!globalThis.electron.threadNumber) {\r\n                    // 初回\r\n                    isfirst = true;\r\n                    resNum = globalThis.config.resNumber ? Number(globalThis.config.resNumber) : NaN;\r\n                }\r\n                else {\r\n                    // 2回目以降\r\n                    resNum = globalThis.electron.threadNumber;\r\n                }\r\n                return [4 /*yield*/, getRes_1.getRes(globalThis.config.url, resNum)];\r\n            case 1:\r\n                result = _a.sent();\r\n                // 指定したレス番は除外対象\r\n                if (!isfirst)\r\n                    result.shift();\r\n                if (result.length > 0 && result[result.length - 1].number) {\r\n                    globalThis.electron.threadNumber = Number(result[result.length - 1].number);\r\n                    if (isfirst) {\r\n                        temp = result;\r\n                        if (!globalThis.config.dispSort) {\r\n                            temp = temp.reverse();\r\n                        }\r\n                        sendDomForChatWindow(temp);\r\n                    }\r\n                    else {\r\n                        _loop_1 = function (item) {\r\n                            // リストに同じレス番があったら追加しない\r\n                            if (!globalThis.electron.commentQueueList.find(function (comment) { return comment.number === item.number; })) {\r\n                                globalThis.electron.commentQueueList.push(item);\r\n                            }\r\n                        };\r\n                        for (_i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n                            item = result_1[_i];\r\n                            _loop_1(item);\r\n                        }\r\n                    }\r\n                    globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'bbs', category: 'status', message: \"ok res=\" + globalThis.electron.threadNumber });\r\n                }\r\n                else if (result.length > 0) {\r\n                    globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'bbs', category: 'status', message: 'error!' });\r\n                    // 番号が無くて結果が入ってるのは通信エラーメッセージ\r\n                    sendDomForChatWindow(result);\r\n                }\r\n                return [4 /*yield*/, notifyThreadResLimit()];\r\n            case 2:\r\n                _a.sent();\r\n                if (!(threadIntervalEvent && exeId === serverId)) return [3 /*break*/, 4];\r\n                return [4 /*yield*/, util_1.sleep(globalThis.config.interval * 1000)];\r\n            case 3:\r\n                _a.sent();\r\n                getResInterval(exeId);\r\n                _a.label = 4;\r\n            case 4: return [2 /*return*/];\r\n        }\r\n    });\r\n}); };\r\n/** レス番が上限かチェックして、超えてたら通知する */\r\nvar notifyThreadResLimit = function () { return __awaiter(void 0, void 0, void 0, function () {\r\n    return __generator(this, function (_a) {\r\n        switch (_a.label) {\r\n            case 0:\r\n                if (!(globalThis.config.notifyThreadResLimit > 0 && globalThis.electron.threadNumber >= globalThis.config.notifyThreadResLimit)) return [3 /*break*/, 2];\r\n                globalThis.electron.commentQueueList.push({\r\n                    name: 'unacastより',\r\n                    imgUrl: './img/unacast.png',\r\n                    text: \"\\u30EC\\u30B9\\u304C\" + globalThis.config.notifyThreadResLimit + \"\\u3092\\u8D85\\u3048\\u307E\\u3057\\u305F\\u3002\\u6B21\\u30B9\\u30EC\\u3092\\u7ACB\\u3066\\u3066\\u304F\\u3060\\u3055\\u3044\\u3002\",\r\n                });\r\n                // TODO: 次スレ検索ポーリング処理を走らせる\r\n                // スレ立て中だと思うのでちょっと待つ\r\n                return [4 /*yield*/, util_1.sleep(10 * 1000)];\r\n            case 1:\r\n                // TODO: 次スレ検索ポーリング処理を走らせる\r\n                // スレ立て中だと思うのでちょっと待つ\r\n                _a.sent();\r\n                _a.label = 2;\r\n            case 2: return [2 /*return*/];\r\n        }\r\n    });\r\n}); };\r\n/**\r\n * キューに溜まったコメントを処理する\r\n */\r\nvar taskScheduler = function (exeId) { return __awaiter(void 0, void 0, void 0, function () {\r\n    var temp, comment;\r\n    var _a, _b, _c, _d;\r\n    return __generator(this, function (_e) {\r\n        switch (_e.label) {\r\n            case 0:\r\n                if (!(((_b = (_a = globalThis.electron) === null || _a === void 0 ? void 0 : _a.commentQueueList) === null || _b === void 0 ? void 0 : _b.length) > 0)) return [3 /*break*/, 3];\r\n                electron_log_1.default.info(\"[taskScheduler] \" + ((_d = (_c = globalThis.electron) === null || _c === void 0 ? void 0 : _c.commentQueueList) === null || _d === void 0 ? void 0 : _d.length));\r\n                if (!(globalThis.config.commentProcessType === 0)) return [3 /*break*/, 1];\r\n                temp = __spreadArrays(globalThis.electron.commentQueueList);\r\n                globalThis.electron.commentQueueList = [];\r\n                // 新着が上の場合は逆順にする\r\n                if (!globalThis.config.dispSort) {\r\n                    temp = temp.reverse();\r\n                }\r\n                sendDom(temp);\r\n                return [3 /*break*/, 3];\r\n            case 1:\r\n                comment = globalThis.electron.commentQueueList.shift();\r\n                return [4 /*yield*/, sendDom([comment])];\r\n            case 2:\r\n                _e.sent();\r\n                _e.label = 3;\r\n            case 3:\r\n                if (!(isExecuteQue && exeId === serverId)) return [3 /*break*/, 5];\r\n                return [4 /*yield*/, util_1.sleep(100)];\r\n            case 4:\r\n                _e.sent();\r\n                taskScheduler(exeId);\r\n                _e.label = 5;\r\n            case 5: return [2 /*return*/];\r\n        }\r\n    });\r\n}); };\r\n/** 読み子によって発話中であるか */\r\nvar isSpeaking = false;\r\n/** 読み子を再生する */\r\nvar playYomiko = function (msg) { return __awaiter(void 0, void 0, void 0, function () {\r\n    return __generator(this, function (_a) {\r\n        switch (_a.label) {\r\n            case 0:\r\n                // log.info('[playYomiko] start');\r\n                isSpeaking = true;\r\n                // 読み子呼び出し\r\n                switch (config.typeYomiko) {\r\n                    case 'tamiyasu': {\r\n                        console.log(config.tamiyasuPath + \" \\\"\" + msg + \"\\\"\");\r\n                        child_process_1.spawn(config.tamiyasuPath, [msg]);\r\n                        break;\r\n                    }\r\n                    case 'bouyomi': {\r\n                        if (bouyomi)\r\n                            bouyomi.speak(msg);\r\n                        break;\r\n                    }\r\n                }\r\n                // 読み子が読んでる時間分相当待つ\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent['wait-yomiko-time'], msg);\r\n                _a.label = 1;\r\n            case 1:\r\n                if (!isSpeaking) return [3 /*break*/, 3];\r\n                return [4 /*yield*/, util_1.sleep(50)];\r\n            case 2:\r\n                _a.sent();\r\n                return [3 /*break*/, 1];\r\n            case 3: return [2 /*return*/];\r\n        }\r\n    });\r\n}); };\r\nelectron_1.ipcMain.on(const_1.electronEvent['speaking-end'], function (event) { return (isSpeaking = false); });\r\nvar isPlayingSe = false;\r\nvar playSe = function () { return __awaiter(void 0, void 0, void 0, function () {\r\n    var wavfilepath;\r\n    return __generator(this, function (_a) {\r\n        switch (_a.label) {\r\n            case 0:\r\n                wavfilepath = globalThis.electron.seList[Math.floor(Math.random() * globalThis.electron.seList.length)];\r\n                isPlayingSe = true;\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent['play-sound-start'], { wavfilepath: wavfilepath, volume: globalThis.config.playSeVolume });\r\n                _a.label = 1;\r\n            case 1:\r\n                if (!isPlayingSe) return [3 /*break*/, 3];\r\n                return [4 /*yield*/, util_1.sleep(50)];\r\n            case 2:\r\n                _a.sent();\r\n                return [3 /*break*/, 1];\r\n            case 3: return [2 /*return*/];\r\n        }\r\n    });\r\n}); };\r\nelectron_1.ipcMain.on(const_1.electronEvent['play-sound-end'], function (event) { return (isPlayingSe = false); });\r\nexports.createDom = function (message, type) {\r\n    var domStr = \"<li class=\\\"list-item\\\">\";\r\n    /** レス番とかの行が何かしら表示対象になっているか */\r\n    var isResNameShowed = false;\r\n    // アイコン表示\r\n    if (globalThis.config.showIcon) {\r\n        domStr += \"\\n    <span class=\\\"icon-block\\\">\\n      <img class=\\\"icon\\\" src=\\\"\" + message.imgUrl + \"\\\">\\n    </span>\\n    \";\r\n        isResNameShowed = true;\r\n    }\r\n    domStr += \"<div class=\\\"content\\\">\";\r\n    // レス番表示\r\n    if (globalThis.config.showNumber && message.number) {\r\n        domStr += \"\\n      <span class=\\\"resNumber\\\">\" + message.number + \"</span>\\n    \";\r\n        isResNameShowed = true;\r\n    }\r\n    // 名前表示\r\n    if (globalThis.config.showName && message.name) {\r\n        domStr += \"<span class=\\\"name\\\">\" + message.name + \"</span>\";\r\n        isResNameShowed = true;\r\n    }\r\n    // 時刻表示\r\n    if (globalThis.config.showTime && message.date) {\r\n        domStr += \"<span class=\\\"date\\\">\" + message.date + \"</span>\";\r\n        isResNameShowed = true;\r\n    }\r\n    // 名前と本文を改行で分ける\r\n    // 名前や時刻の行が一つも無ければ、改行しない\r\n    if (globalThis.config.newLine && isResNameShowed) {\r\n        domStr += '<br />';\r\n    }\r\n    // リンクを整形する\r\n    var text = message.text\r\n        .replace(/<a .*?>/g, '') // したらばはアンカーをaタグ化している\r\n        .replace(/<\\\\a>/g, '');\r\n    var reg = new RegExp(\"(h?ttps?(://[-_.!~*'()a-zA-Z0-9;/?:@&=+$,%#]+))\", 'g');\r\n    var commentText = text.replace(reg, '<span class=\"url\" onClick=\\'urlopen(\"$1\")\\'>$1</span>');\r\n    domStr += \"\\n    <span class=\\\"res\\\">\\n      \" + commentText + \"\\n    </span>\\n  \";\r\n    // サムネイル表示\r\n    var isThumbnailShow = (globalThis.config.thumbnail == 1 && type === 'chat') || globalThis.config.thumbnail == 2;\r\n    if (isThumbnailShow) {\r\n        var imgreg = new RegExp(\"(h?ttps?(://[-_.!~*'()a-zA-Z0-9;/?:@&=+$,%#]+)(.jpg|.png|.gif))\", 'g');\r\n        var imgUrls_1 = [];\r\n        var matched = text.match(imgreg);\r\n        if (matched) {\r\n            matched.map(function (value) {\r\n                // log.info(value);\r\n                imgUrls_1.push(value);\r\n            });\r\n        }\r\n        if (imgUrls_1.length > 0) {\r\n            domStr += '<div class=\"thumbnail\">';\r\n            domStr += imgUrls_1\r\n                .map(function (url) {\r\n                var tmp = url;\r\n                if (tmp.match(/^ttp/)) {\r\n                    tmp = \"h\" + tmp;\r\n                }\r\n                return \"<img class=\\\"img\\\" src=\\\"\" + tmp + \"\\\" />\";\r\n            })\r\n                .join('');\r\n            domStr += '</div>';\r\n        }\r\n    }\r\n    // 〆\r\n    domStr += \"</div>\\n  </li>\";\r\n    return domStr;\r\n};\r\n/**\r\n * コメントのDOMをブラウザに送る\r\n * 必要ならレス着信音も鳴らす\r\n * @param message\r\n */\r\nvar sendDom = function (messageList) { return __awaiter(void 0, void 0, void 0, function () {\r\n    var domStr, socketObject_1, text, MIN_DISP_TIME, e_2;\r\n    return __generator(this, function (_a) {\r\n        switch (_a.label) {\r\n            case 0:\r\n                _a.trys.push([0, 7, , 8]);\r\n                domStr = messageList.map(function (message) { return exports.createDom(message, 'server'); }).join('\\n');\r\n                socketObject_1 = {\r\n                    type: 'add',\r\n                    message: domStr,\r\n                };\r\n                aWss.clients.forEach(function (client) {\r\n                    client.send(JSON.stringify(socketObject_1));\r\n                });\r\n                // レンダラーのコメント一覧にも表示\r\n                sendDomForChatWindow(messageList);\r\n                if (!(config.playSe && globalThis.electron.seList.length > 0)) return [3 /*break*/, 2];\r\n                return [4 /*yield*/, playSe()];\r\n            case 1:\r\n                _a.sent();\r\n                _a.label = 2;\r\n            case 2:\r\n                if (!(globalThis.config.typeYomiko !== 'none')) return [3 /*break*/, 4];\r\n                text = messageList[messageList.length - 1].text.replace(/<br> /g, '\\n ').replace(/<br>/g, '\\n ');\r\n                text = text.replace(/<img.*?\\/>/g, '');\r\n                text = text.replace(/<a .*?>/g, '').replace(/<\\/a>/g, '');\r\n                text = util_1.unescapeHtml(text);\r\n                return [4 /*yield*/, playYomiko(text)];\r\n            case 3:\r\n                _a.sent();\r\n                _a.label = 4;\r\n            case 4:\r\n                if (!(globalThis.config.dispType === 1)) return [3 /*break*/, 6];\r\n                MIN_DISP_TIME = 2.5 * 1000;\r\n                return [4 /*yield*/, util_1.sleep(MIN_DISP_TIME)];\r\n            case 5:\r\n                _a.sent();\r\n                _a.label = 6;\r\n            case 6:\r\n                // 鳴らし終わって読み子が終わった\r\n                resetInitMessage();\r\n                return [3 /*break*/, 8];\r\n            case 7:\r\n                e_2 = _a.sent();\r\n                electron_log_1.default.error(e_2);\r\n                return [3 /*break*/, 8];\r\n            case 8: return [2 /*return*/];\r\n        }\r\n    });\r\n}); };\r\n/** チャットウィンドウへのコメント表示 */\r\nvar sendDomForChatWindow = function (messageList) {\r\n    var domStr2 = messageList\r\n        .map(function (message) {\r\n        var imgUrl = message.imgUrl && message.imgUrl.match(/^\\./) ? '../../public/' + message.imgUrl : message.imgUrl;\r\n        return __assign(__assign({}, message), { imgUrl: imgUrl });\r\n    })\r\n        .map(function (message) { return exports.createDom(message, 'chat'); })\r\n        .join('\\n');\r\n    globalThis.electron.chatWindow.webContents.send(const_1.electronEvent['show-comment'], { config: globalThis.config, dom: domStr2 });\r\n};\r\nvar resetInitMessage = function () {\r\n    if (globalThis.config.dispType === 1) {\r\n        var resetObj_1 = {\r\n            type: 'reset',\r\n            message: globalThis.config.initMessage,\r\n        };\r\n        aWss.clients.forEach(function (client) {\r\n            client.send(JSON.stringify(resetObj_1));\r\n        });\r\n    }\r\n};\r\nexports.default = {};\r\n","\"use strict\";\r\nvar __importDefault = (this && this.__importDefault) || function (mod) {\r\n    return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar fs_1 = __importDefault(require(\"fs\"));\r\nexports.readWavFiles = function (path) {\r\n    return new Promise(function (resolve, reject) {\r\n        fs_1.default.readdir(path, function (err, files) {\r\n            if (err)\r\n                reject(err);\r\n            var fileList = files.filter(function (file) {\r\n                return isExistFile(path + '/' + file) && /.*\\.wav$/.test(file); //絞り込み\r\n            });\r\n            resolve(fileList);\r\n        });\r\n    });\r\n};\r\nvar isExistFile = function (file) {\r\n    try {\r\n        fs_1.default.statSync(file).isFile();\r\n        return true;\r\n    }\r\n    catch (err) {\r\n        if (err.code === 'ENOENT')\r\n            return false;\r\n    }\r\n};\r\nexports.sleep = function (msec) { return new Promise(function (resolve) { return setTimeout(resolve, msec); }); };\r\nexports.escapeHtml = function (string) {\r\n    if (typeof string !== 'string') {\r\n        return string;\r\n    }\r\n    return string.replace(/[&'`\"<>]/g, function (match) {\r\n        return {\r\n            '&': '&amp;',\r\n            \"'\": '&#x27;',\r\n            '`': '&#x60;',\r\n            '\"': '&quot;',\r\n            '<': '&lt;',\r\n            '>': '&gt;',\r\n        }[match];\r\n    });\r\n};\r\nexports.unescapeHtml = function (str) {\r\n    return str\r\n        .replace(/&lt;/g, '<')\r\n        .replace(/&gt;/g, '>')\r\n        .replace(/&quot;/g, '\"')\r\n        .replace(/&#039;/g, \"'\")\r\n        .replace(/&#044;/g, ',')\r\n        .replace(/&amp;/g, '&');\r\n};\r\n","\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar live_chat_1 = require(\"./live-chat\");\r\nexports.LiveChat = live_chat_1.LiveChat;\r\n","\"use strict\";\r\nvar __extends = (this && this.__extends) || (function () {\r\n    var extendStatics = function (d, b) {\r\n        extendStatics = Object.setPrototypeOf ||\r\n            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };\r\n        return extendStatics(d, b);\r\n    };\r\n    return function (d, b) {\r\n        extendStatics(d, b);\r\n        function __() { this.constructor = d; }\r\n        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n    };\r\n})();\r\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\r\n    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n    return new (P || (P = Promise))(function (resolve, reject) {\r\n        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n        function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n        step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n    });\r\n};\r\nvar __generator = (this && this.__generator) || function (thisArg, body) {\r\n    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n    return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n    function verb(n) { return function (v) { return step([n, v]); }; }\r\n    function step(op) {\r\n        if (f) throw new TypeError(\"Generator is already executing.\");\r\n        while (_) try {\r\n            if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n            if (y = 0, t) op = [op[0] & 2, t.value];\r\n            switch (op[0]) {\r\n                case 0: case 1: t = op; break;\r\n                case 4: _.label++; return { value: op[1], done: false };\r\n                case 5: _.label++; y = op[1]; op = [0]; continue;\r\n                case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n                default:\r\n                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n                    if (t[2]) _.ops.pop();\r\n                    _.trys.pop(); continue;\r\n            }\r\n            op = body.call(thisArg, _);\r\n        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n    }\r\n};\r\nvar __importDefault = (this && this.__importDefault) || function (mod) {\r\n    return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar events_1 = require(\"events\");\r\nvar axios_1 = __importDefault(require(\"axios\"));\r\nvar parser_1 = require(\"./parser\");\r\nvar util_1 = require(\"../util\");\r\n/**\r\n * YouTubeライブチャット取得イベント\r\n */\r\nvar LiveChat = /** @class */ (function (_super) {\r\n    __extends(LiveChat, _super);\r\n    function LiveChat(options, interval) {\r\n        if (interval === void 0) { interval = 1000; }\r\n        var _this = _super.call(this) || this;\r\n        _this.interval = interval;\r\n        _this.prevTime = Date.now();\r\n        _this.isStop = false;\r\n        if ('channelId' in options) {\r\n            _this.channelId = options.channelId;\r\n        }\r\n        else if ('liveId' in options) {\r\n            _this.liveId = options.liveId;\r\n        }\r\n        else {\r\n            throw TypeError('Required channelId or liveId.');\r\n        }\r\n        return _this;\r\n    }\r\n    LiveChat.prototype.start = function () {\r\n        this.isStop = false;\r\n        this.fetchLiveId();\r\n    };\r\n    LiveChat.prototype.fetchLiveId = function () {\r\n        var _a;\r\n        return __awaiter(this, void 0, void 0, function () {\r\n            var url, liveRes, e_1;\r\n            var _this = this;\r\n            return __generator(this, function (_b) {\r\n                switch (_b.label) {\r\n                    case 0:\r\n                        if (this.isStop)\r\n                            return [2 /*return*/];\r\n                        if (!this.channelId) return [3 /*break*/, 4];\r\n                        url = \"https://www.youtube.com/channel/\" + this.channelId + \"/live\";\r\n                        _b.label = 1;\r\n                    case 1:\r\n                        _b.trys.push([1, 3, , 4]);\r\n                        return [4 /*yield*/, axios_1.default.get(url, { headers: LiveChat.headers })];\r\n                    case 2:\r\n                        liveRes = _b.sent();\r\n                        //   if (liveRes.data.match(/LIVE_STREAM_OFFLINE/)) {\r\n                        //     this.emit('error', new Error('Live stream offline'));\r\n                        //     return false;\r\n                        //   }\r\n                        this.liveId = (_a = liveRes.data.match(/videoId\\\\\":\\\\\"(.+?)\\\\/)) === null || _a === void 0 ? void 0 : _a[1];\r\n                        return [3 /*break*/, 4];\r\n                    case 3:\r\n                        e_1 = _b.sent();\r\n                        // チャンネルID自体が違うのはもうどうしようもないので止める\r\n                        this.emit('error', new Error(\"connection error url = \" + url));\r\n                        return [2 /*return*/];\r\n                    case 4:\r\n                        if (!this.liveId) return [3 /*break*/, 5];\r\n                        this.observer = setInterval(function () { return _this.fetchChat(); }, this.interval);\r\n                        this.emit('start', this.liveId);\r\n                        return [3 /*break*/, 7];\r\n                    case 5:\r\n                        // 配信が開始してないパターンが考えられるのでリトライ\r\n                        this.emit('error', new Error('Live stream not found'));\r\n                        return [4 /*yield*/, util_1.sleep(2000)];\r\n                    case 6:\r\n                        _b.sent();\r\n                        this.fetchLiveId();\r\n                        _b.label = 7;\r\n                    case 7: return [2 /*return*/];\r\n                }\r\n            });\r\n        });\r\n    };\r\n    LiveChat.prototype.stop = function (reason) {\r\n        this.isStop = true;\r\n        if (this.observer) {\r\n            clearInterval(this.observer);\r\n            this.emit('end', reason);\r\n        }\r\n    };\r\n    LiveChat.prototype.fetchChat = function () {\r\n        return __awaiter(this, void 0, void 0, function () {\r\n            var url, res, items, item, e_2;\r\n            var _this = this;\r\n            return __generator(this, function (_a) {\r\n                switch (_a.label) {\r\n                    case 0:\r\n                        url = \"https://www.youtube.com/live_chat?v=\" + this.liveId + \"&pbj=1\";\r\n                        _a.label = 1;\r\n                    case 1:\r\n                        _a.trys.push([1, 3, , 4]);\r\n                        return [4 /*yield*/, axios_1.default.get(url, { headers: LiveChat.headers })];\r\n                    case 2:\r\n                        res = _a.sent();\r\n                        items = res.data[1].response.contents.liveChatRenderer.actions\r\n                            .slice(0, -1)\r\n                            .filter(function (v) {\r\n                            var messageRenderer = parser_1.actionToRenderer(v);\r\n                            if (messageRenderer !== null) {\r\n                                if (messageRenderer) {\r\n                                    return parser_1.usecToTime(messageRenderer.timestampUsec) > _this.prevTime;\r\n                                }\r\n                            }\r\n                            return false;\r\n                        })\r\n                            .map(function (v) { return parser_1.parseData(v); });\r\n                        items.forEach(function (v) {\r\n                            if (v) {\r\n                                _this.emit('comment', v);\r\n                            }\r\n                        });\r\n                        if (items.length > 0) {\r\n                            console.log(\"[Youtube-chat] items = \" + items.length);\r\n                            item = items[items.length - 1];\r\n                            if (item)\r\n                                this.prevTime = item.timestamp;\r\n                        }\r\n                        return [3 /*break*/, 4];\r\n                    case 3:\r\n                        e_2 = _a.sent();\r\n                        this.emit('error', new Error(\"Error occured at fetchchat url=\" + url));\r\n                        return [3 /*break*/, 4];\r\n                    case 4: return [2 /*return*/];\r\n                }\r\n            });\r\n        });\r\n    };\r\n    LiveChat.prototype.on = function (event, listener) {\r\n        return _super.prototype.on.call(this, event, listener);\r\n    };\r\n    LiveChat.headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36' };\r\n    return LiveChat;\r\n}(events_1.EventEmitter));\r\nexports.LiveChat = LiveChat;\r\n","\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar parseThumbnailToImageItem = function (data, alt) {\r\n    var thumbnail = data.pop();\r\n    if (thumbnail) {\r\n        return {\r\n            url: thumbnail.url,\r\n            width: thumbnail.width,\r\n            height: thumbnail.height,\r\n            alt: alt,\r\n        };\r\n    }\r\n    return;\r\n};\r\nvar parseEmojiToImageItem = function (data) {\r\n    return parseThumbnailToImageItem(data.emoji.image.thumbnails, data.emoji.shortcuts.shift());\r\n};\r\nvar parseMessages = function (runs) {\r\n    return runs.map(function (run) {\r\n        var _a;\r\n        if ('text' in run) {\r\n            if ((_a = run === null || run === void 0 ? void 0 : run.navigationEndpoint) === null || _a === void 0 ? void 0 : _a.urlEndpoint.url) {\r\n                var tubeUrl = run.navigationEndpoint.urlEndpoint.url.replace(/^\\/redirect\\?/, '');\r\n                // console.log(tubeUrl);\r\n                var parsed = tubeUrl.split('&').filter(function (str) { return str.match(/^q=/); });\r\n                var orgUrl = decodeURIComponent(parsed[0].replace(/^q=/, ''));\r\n                // console.log(orgUrl);\r\n                return { text: orgUrl };\r\n            }\r\n            else {\r\n                return run;\r\n            }\r\n        }\r\n        else {\r\n            // 絵文字を画像に置換\r\n            return parseEmojiToImageItem(run);\r\n        }\r\n    });\r\n};\r\nexports.actionToRenderer = function (action) {\r\n    if (!action.addChatItemAction) {\r\n        return null;\r\n    }\r\n    var item = action.addChatItemAction.item;\r\n    if (item.liveChatTextMessageRenderer) {\r\n        return item.liveChatTextMessageRenderer;\r\n    }\r\n    else if (item.liveChatPaidMessageRenderer) {\r\n        return item.liveChatPaidMessageRenderer;\r\n    }\r\n    else if (item.liveChatPaidStickerRenderer) {\r\n        return item.liveChatPaidStickerRenderer;\r\n    }\r\n    else {\r\n        return item.liveChatMembershipItemRenderer;\r\n    }\r\n};\r\nexports.usecToTime = function (usec) {\r\n    return Math.floor(Number(usec) / 1000);\r\n};\r\nexports.parseData = function (data) {\r\n    var messageRenderer = exports.actionToRenderer(data);\r\n    if (messageRenderer === null) {\r\n        return null;\r\n    }\r\n    var message = [];\r\n    if ('message' in messageRenderer) {\r\n        message = messageRenderer.message.runs;\r\n    }\r\n    else if ('headerSubtext' in messageRenderer) {\r\n        message = messageRenderer.headerSubtext.runs;\r\n    }\r\n    var ret = {\r\n        id: messageRenderer.id,\r\n        author: {\r\n            name: messageRenderer.authorName.simpleText,\r\n            thumbnail: parseThumbnailToImageItem(messageRenderer.authorPhoto.thumbnails, messageRenderer.authorName.simpleText),\r\n            channelId: messageRenderer.authorExternalChannelId,\r\n        },\r\n        message: parseMessages(message),\r\n        membership: Boolean('headerSubtext' in messageRenderer),\r\n        isOwner: false,\r\n        timestamp: exports.usecToTime(messageRenderer.timestampUsec),\r\n    };\r\n    if (messageRenderer.authorBadges) {\r\n        var badge = messageRenderer.authorBadges[0].liveChatAuthorBadgeRenderer;\r\n        if (badge.customThumbnail) {\r\n            ret.author.badge = {\r\n                thumbnail: parseThumbnailToImageItem(badge.customThumbnail.thumbnails, badge.tooltip),\r\n                label: badge.tooltip,\r\n            };\r\n        }\r\n        else {\r\n            ret.isOwner = true;\r\n        }\r\n    }\r\n    if ('sticker' in messageRenderer) {\r\n        ret.superchat = {\r\n            amount: messageRenderer.purchaseAmountText.simpleText,\r\n            color: messageRenderer.backgroundColor,\r\n            sticker: parseThumbnailToImageItem(messageRenderer.sticker.thumbnails, messageRenderer.sticker.accessibility.accessibilityData.label),\r\n        };\r\n    }\r\n    else if ('purchaseAmountText' in messageRenderer) {\r\n        ret.superchat = {\r\n            amount: messageRenderer.purchaseAmountText.simpleText,\r\n            color: messageRenderer.bodyBackgroundColor,\r\n        };\r\n    }\r\n    return ret;\r\n};\r\n"],"mappings":";AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;AClFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;AClFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;AC1EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;AC1BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;ACrJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;AClOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;ACnSA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;ACpQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;ACxJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;ACpuBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;ACpDA;AACA;AACA;AACA;;;;;;;;;;;;;ACHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;AC/LA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;A","sourceRoot":""}
\ No newline at end of file
+{"version":3,"file":"index.js","sources":["webpack:///webpack/bootstrap","webpack:///./src/main/ReadIcons.ts","webpack:///./src/main/bouyomi-chan/index.ts","webpack:///./src/main/const.ts","webpack:///./src/main/getRes.ts","webpack:///./src/main/main.ts","webpack:///./src/main/niconama/index.ts","webpack:///./src/main/readBBS/Read5ch.ts","webpack:///./src/main/readBBS/readSitaraba.ts","webpack:///./src/main/startServer.ts","webpack:///./src/main/util.ts","webpack:///./src/main/youtube-chat/index.ts","webpack:///./src/main/youtube-chat/live-chat.ts","webpack:///./src/main/youtube-chat/parser.ts"],"sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"./src/main/main.ts\");\n","\"use strict\";\r\nvar __importDefault = (this && this.__importDefault) || function (mod) {\r\n    return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\n/**\r\n * アイコン表示に関するモジュール\r\n * シングルトン\r\n */\r\nvar fs_1 = __importDefault(require(\"fs\"));\r\nvar path_1 = __importDefault(require(\"path\"));\r\nvar electron_log_1 = __importDefault(require(\"electron-log\"));\r\nvar randomIconList;\r\nvar idIconList;\r\n/**\r\n * コンストラクタ\r\n * ・ランダムフォルダからアイコン名を取得してリスト化\r\n * ・IDフォルダからもリスト化、空の対応マップ作製\r\n * ・コテハン対応ファイルを読みこんでmapに格納\r\n */\r\nvar ReadIcons = /** @class */ (function () {\r\n    function ReadIcons() {\r\n        /**\r\n         * アイコンランダム表示機能(デフォルト)\r\n         * 起動時に作成したアイコンリストからランダムで1つ取得\r\n         */\r\n        this.getRandomIcons = function () {\r\n            var iconPath = '';\r\n            try {\r\n                var dirName = './img/random/';\r\n                // リストからランダム取得\r\n                //  const size = randomIconList.size;\r\n                var num = Math.floor(randomIconList.length * Math.random());\r\n                iconPath = dirName + randomIconList[num];\r\n            }\r\n            catch (e) {\r\n                electron_log_1.default.error(e);\r\n            }\r\n            return iconPath;\r\n        };\r\n        //画像ディレクトリ\r\n        var randomDir = path_1.default.resolve(__dirname, \"../public/img/random/\");\r\n        console.debug('[ReadIcons]loadRandomDir = ' + randomDir);\r\n        //  ランダムアイコン取得\r\n        randomIconList = readDir(randomDir);\r\n        //ID用アイコンディレクトリ\r\n        var idDir = path_1.default.resolve(__dirname, \"../public/img/id/\");\r\n        console.debug('[ReadIcons]loadIDDir = ' + idDir);\r\n        //  ランダムアイコン取得\r\n        idIconList = readDir(idDir);\r\n    }\r\n    return ReadIcons;\r\n}());\r\nvar readDir = function (imgDir) {\r\n    var iconFileList = [];\r\n    //  指定したディレクトリのアイコン取得\r\n    var files = fs_1.default.readdirSync(imgDir, { withFileTypes: true });\r\n    //pngファイルのみ返却リストに格納する\r\n    files.forEach(function (file) {\r\n        // asar圧縮するとfileが文字列になる。開発環境だとfileオブジェクトになる\r\n        var target = typeof file.name !== 'string' ? file : file.name;\r\n        var regx = /.*\\.png$/.test(target);\r\n        if (regx) {\r\n            iconFileList.push(target);\r\n        }\r\n    });\r\n    // console.log('[ReadIcons.readDir]end');\r\n    // console.log(JSON.stringify(iconFileList));\r\n    return iconFileList;\r\n};\r\n/**\r\n * IDによるアイコン固定機能(オプションでON,OFF可能)\r\n * 初出のIDならばランダムでアイコンを取得し\r\n * IDとファイル名のセットでマップに格納\r\n * @param string // ID\r\n * @return string filename\r\n */\r\n/**\r\n * コテハンリスト機能(オプションでON,OFF可能)\r\n * koteフォルダの下にkotehan.jsonを作って\r\n * 名前とアイコンファイル名の対応をマップにして返すだけ\r\n */\r\nexports.default = ReadIcons;\r\n","\"use strict\";\r\nvar __importDefault = (this && this.__importDefault) || function (mod) {\r\n    return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar net_1 = __importDefault(require(\"net\"));\r\nvar BouyomiChan = /** @class */ (function () {\r\n    function BouyomiChan(options) {\r\n        /**\r\n         * 棒読みちゃんのホスト\r\n         */\r\n        this.host = 'localhost';\r\n        /**\r\n         * 棒読みちゃんのポート番号\r\n         */\r\n        this.port = 50001;\r\n        /**\r\n         * 速度(-1:棒読みちゃん画面上の設定)\r\n         */\r\n        this.speed = -1;\r\n        /**\r\n         * 音程(-1:棒読みちゃん画面上の設定)\r\n         */\r\n        this.tone = -1;\r\n        /**\r\n         * 音量(-1:棒読みちゃん画面上の設定)\r\n         */\r\n        this.volume = -1;\r\n        /**\r\n         * 声質( 0:棒読みちゃん画面上の設定、1:女性1、2:女性2、3:男性1、4:男性2、5:中性、6:ロボット、7:機械1、8:機械2、10001~:SAPI5)\r\n         */\r\n        this.type = 0;\r\n        if (!options)\r\n            return;\r\n        if (options.host)\r\n            this.host = options.host;\r\n        if (options.port)\r\n            this.port = options.port;\r\n        if (options.speed)\r\n            this.speed = options.speed;\r\n        if (options.tone)\r\n            this.tone = options.tone;\r\n        if (options.volume)\r\n            this.volume = options.volume;\r\n        if (options.type)\r\n            this.type = options.type;\r\n    }\r\n    /**\r\n     * @param message 棒読みちゃんに読み上げてもらう文章\r\n     */\r\n    BouyomiChan.prototype.speak = function (message) {\r\n        /** 棒読みちゃんに送信する設定のバイト長 */\r\n        var SETTINGS_BYTES_LENGTH = 15;\r\n        var messageByteLength = Buffer.byteLength(message);\r\n        var bufferLength = SETTINGS_BYTES_LENGTH + messageByteLength;\r\n        var buff = Buffer.alloc(bufferLength);\r\n        /** メッセージ読み上げコマンド */\r\n        var COMMAND_TO_SPEAK = 1;\r\n        var len = buff.writeUInt16LE(COMMAND_TO_SPEAK);\r\n        len = buff.writeInt16LE(this.speed, len);\r\n        len = buff.writeInt16LE(this.tone, len);\r\n        len = buff.writeInt16LE(this.volume, len);\r\n        len = buff.writeUInt16LE(this.type, len);\r\n        /** 文字コード(0:UTF-8, 1:Unicode, 2:Shift-JIS) */\r\n        var ENCODING = 0;\r\n        len = buff.writeUInt8(ENCODING, len);\r\n        len = buff.writeUInt32LE(messageByteLength, len);\r\n        len = buff.write(message, len);\r\n        var client = net_1.default.createConnection(this.port, this.host);\r\n        client.write(buff);\r\n        client.end();\r\n    };\r\n    return BouyomiChan;\r\n}());\r\nexports.default = BouyomiChan;\r\n","\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.electronEvent = {\r\n    /** サーバー起動 */\r\n    'start-server': 'start-server',\r\n    /** サーバー停止 */\r\n    'stop-server': 'stop-server',\r\n    /** Config適用 */\r\n    'apply-config': 'apply-config',\r\n    /** アラート表示 */\r\n    'show-alert': 'show-alert',\r\n    /** 棒読み再生 */\r\n    'play-tamiyasu': 'play-tamiyasu',\r\n    /** レス着信音再生 */\r\n    'play-sound-start': 'play-sound-start',\r\n    'play-sound-end': 'play-sound-end',\r\n    'wait-yomiko-time': 'wait-yomiko-time',\r\n    'speaking-end': 'speaking-end',\r\n    /** コメント表示 */\r\n    'show-comment': 'show-comment',\r\n    /** コメント欄初期化 */\r\n    'clear-comment': 'clear-comment',\r\n    /** サーバー起動の返信 */\r\n    'start-server-reply': 'start-server-reply',\r\n    /** ステータス更新 */\r\n    UPDATE_STATUS: 'UPDATE_STATUS',\r\n};\r\n","\"use strict\";\r\nvar __assign = (this && this.__assign) || function () {\r\n    __assign = Object.assign || function(t) {\r\n        for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n            s = arguments[i];\r\n            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))\r\n                t[p] = s[p];\r\n        }\r\n        return t;\r\n    };\r\n    return __assign.apply(this, arguments);\r\n};\r\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\r\n    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n    return new (P || (P = Promise))(function (resolve, reject) {\r\n        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n        function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n        step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n    });\r\n};\r\nvar __generator = (this && this.__generator) || function (thisArg, body) {\r\n    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n    return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n    function verb(n) { return function (v) { return step([n, v]); }; }\r\n    function step(op) {\r\n        if (f) throw new TypeError(\"Generator is already executing.\");\r\n        while (_) try {\r\n            if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n            if (y = 0, t) op = [op[0] & 2, t.value];\r\n            switch (op[0]) {\r\n                case 0: case 1: t = op; break;\r\n                case 4: _.label++; return { value: op[1], done: false };\r\n                case 5: _.label++; y = op[1]; op = [0]; continue;\r\n                case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n                default:\r\n                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n                    if (t[2]) _.ops.pop();\r\n                    _.trys.pop(); continue;\r\n            }\r\n            op = body.call(thisArg, _);\r\n        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n    }\r\n};\r\nvar __importDefault = (this && this.__importDefault) || function (mod) {\r\n    return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar express_1 = __importDefault(require(\"express\"));\r\nvar body_parser_1 = __importDefault(require(\"body-parser\")); // jsonパーサ\r\nvar router = express_1.default.Router();\r\nvar electron_log_1 = __importDefault(require(\"electron-log\"));\r\nvar ReadIcons_1 = __importDefault(require(\"./ReadIcons\")); //アイコンファイル名取得\r\nvar readIcons = new ReadIcons_1.default();\r\nvar startServer_1 = require(\"./startServer\");\r\nvar readSitaraba_1 = __importDefault(require(\"./readBBS/readSitaraba\")); // したらば読み込み用モジュール\r\nvar Read5ch_1 = __importDefault(require(\"./readBBS/Read5ch\")); // 5ch互換板読み込み用モジュール\r\nvar sitaraba = new readSitaraba_1.default();\r\nvar read5ch = new Read5ch_1.default();\r\n// 掲示板読み込みモジュール、一度決定したら使いまわすためにグローバル宣言\r\nvar bbsModule = null;\r\n// リクエストのbodyをパース下りエンコードしたりするためのやつ\r\nrouter.use(body_parser_1.default.urlencoded({ extended: true }));\r\nrouter.use(body_parser_1.default.json());\r\n/**\r\n * ブラウザからの初期処理リクエスト\r\n */\r\nrouter.get('/', function (req, res, next) { return __awaiter(void 0, void 0, void 0, function () {\r\n    var threadUrl, resNum, result, doms;\r\n    return __generator(this, function (_a) {\r\n        switch (_a.label) {\r\n            case 0:\r\n                threadUrl = globalThis.config.url;\r\n                resNum = globalThis.config.resNumber ? Number(globalThis.config.resNumber) : NaN;\r\n                res.header('Content-Type', 'application/json; charset=UTF-8');\r\n                return [4 /*yield*/, exports.getRes(threadUrl, resNum)];\r\n            case 1:\r\n                result = _a.sent();\r\n                result.shift();\r\n                doms = result.map(function (item) { return startServer_1.createDom(item, 'server'); });\r\n                res.send(JSON.stringify(doms));\r\n                return [2 /*return*/];\r\n        }\r\n    });\r\n}); });\r\n/**\r\n * 掲示板のレスを取得する\r\n * @param threadUrl スレのURL\r\n * @param resNum この番号以降を取得する。指定しない場合は最新1件を取得。\r\n */\r\nexports.getRes = function (threadUrl, resNum) { return __awaiter(void 0, void 0, void 0, function () {\r\n    var response, e_1;\r\n    return __generator(this, function (_a) {\r\n        switch (_a.label) {\r\n            case 0:\r\n                _a.trys.push([0, 2, , 3]);\r\n                // リクエストURLを解析し、使用するモジュールを変更する\r\n                bbsModule = analysBBSName(threadUrl);\r\n                return [4 /*yield*/, bbsModule.read(threadUrl, resNum)];\r\n            case 1:\r\n                response = _a.sent();\r\n                globalThis.electron.threadConnectionError = 0;\r\n                console.log(\"[getRes.js] fetch \" + threadUrl + \" resNum = \" + resNum + \", result = \" + response.length);\r\n                return [2 /*return*/, response.map(function (res) {\r\n                        return __assign(__assign({}, res), { imgUrl: readIcons.getRandomIcons() });\r\n                    })];\r\n            case 2:\r\n                e_1 = _a.sent();\r\n                electron_log_1.default.error(e_1);\r\n                // エラー回数が規定回数以上かチェックして、超えてたら通知する\r\n                if (globalThis.config.notifyThreadConnectionErrorLimit > 0) {\r\n                    globalThis.electron.threadConnectionError += 1;\r\n                    if (globalThis.electron.threadConnectionError >= globalThis.config.notifyThreadConnectionErrorLimit) {\r\n                        electron_log_1.default.info('[getRes] エラー回数超過');\r\n                        globalThis.electron.threadConnectionError = 0;\r\n                        return [2 /*return*/, [\r\n                                {\r\n                                    name: 'unacastより',\r\n                                    imgUrl: './img/unacast.png',\r\n                                    text: '掲示板が規定回数通信エラーになりました。設定を見直すか、掲示板URLを変更してください。',\r\n                                },\r\n                            ]];\r\n                    }\r\n                }\r\n                return [2 /*return*/, []];\r\n            case 3: return [2 /*return*/];\r\n        }\r\n    });\r\n}); };\r\n/*\r\n * URLをみてどこのBBSか判定して使用するモジュールを返却する\r\n */\r\nvar analysBBSName = function (threadUrl) {\r\n    // したらばドメイン名\r\n    var sitarabaDomain = 'jbbs.shitaraba.net';\r\n    // こんな感じで必要に応じて増やしていけばいいんじゃね?\r\n    // const dokkanoBBS = 'dokka.bbs.com';\r\n    if (threadUrl.indexOf(sitarabaDomain) !== -1) {\r\n        // URLにしたらばドメイン名が入ってればしたらば\r\n        return sitaraba;\r\n    }\r\n    // どこにも該当しなかったらとりあえず5chで\r\n    // この辺も対応ドメインリストとか作ってちゃんと判定したほうがよさそう\r\n    return read5ch;\r\n};\r\nexports.default = router;\r\n","\"use strict\";\r\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\r\n    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n    return new (P || (P = Promise))(function (resolve, reject) {\r\n        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n        function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n        step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n    });\r\n};\r\nvar __generator = (this && this.__generator) || function (thisArg, body) {\r\n    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n    return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n    function verb(n) { return function (v) { return step([n, v]); }; }\r\n    function step(op) {\r\n        if (f) throw new TypeError(\"Generator is already executing.\");\r\n        while (_) try {\r\n            if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n            if (y = 0, t) op = [op[0] & 2, t.value];\r\n            switch (op[0]) {\r\n                case 0: case 1: t = op; break;\r\n                case 4: _.label++; return { value: op[1], done: false };\r\n                case 5: _.label++; y = op[1]; op = [0]; continue;\r\n                case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n                default:\r\n                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n                    if (t[2]) _.ops.pop();\r\n                    _.trys.pop(); continue;\r\n            }\r\n            op = body.call(thisArg, _);\r\n        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n    }\r\n};\r\nvar __importDefault = (this && this.__importDefault) || function (mod) {\r\n    return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n};\r\nvar __importStar = (this && this.__importStar) || function (mod) {\r\n    if (mod && mod.__esModule) return mod;\r\n    var result = {};\r\n    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];\r\n    result[\"default\"] = mod;\r\n    return result;\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\n// Electronのモジュール\r\nvar path_1 = __importDefault(require(\"path\"));\r\nvar electron_1 = __importStar(require(\"electron\"));\r\nvar electron_log_1 = __importDefault(require(\"electron-log\"));\r\nvar util_1 = require(\"./util\");\r\nvar electron_window_state_1 = __importDefault(require(\"electron-window-state\"));\r\nconsole.trace = function () {\r\n    //\r\n};\r\nprocess.on('uncaughtException', function (err) {\r\n    electron_log_1.default.error(err);\r\n});\r\n// アプリケーションをコントロールするモジュール\r\nvar app = electron_1.default.app;\r\n// 多重起動防止\r\nif (!app.requestSingleInstanceLock()) {\r\n    electron_log_1.default.error('[app] It is terminated for multiple launches.');\r\n    app.quit();\r\n}\r\nelse {\r\n    electron_log_1.default.info('[app] started');\r\n    app.allowRendererProcessReuse = true;\r\n    var iconPath_1 = path_1.default.resolve(__dirname, '../icon.png');\r\n    // サーバー起動モジュール\r\n    // eslint-disable-next-line @typescript-eslint/no-var-requires\r\n    var ss = require('./startServer');\r\n    console.trace(ss);\r\n    // メインウィンドウはGCされないようにグローバル宣言\r\n    globalThis.electron = {\r\n        mainWindow: null,\r\n        chatWindow: null,\r\n        seList: [],\r\n        twitchChat: null,\r\n        youtubeChat: null,\r\n        niconicoChat: null,\r\n        threadConnectionError: 0,\r\n        threadNumber: 0,\r\n        commentQueueList: [],\r\n    };\r\n    globalThis.config = {};\r\n    // 全てのウィンドウが閉じたら終了\r\n    // app.on('window-all-closed', () => {\r\n    //   if (process.platform != 'darwin') {\r\n    //     app.quit();\r\n    //   }\r\n    // });\r\n    // 右クリックメニュー\r\n    var mainContextMenu_1 = new electron_1.Menu();\r\n    mainContextMenu_1.append(new electron_1.MenuItem({\r\n        label: '最前面表示',\r\n        type: 'checkbox',\r\n        checked: false,\r\n        click: function (e) {\r\n            globalThis.electron.mainWindow.setAlwaysOnTop(e.checked);\r\n        },\r\n    }));\r\n    var chatContextMenu_1 = new electron_1.Menu();\r\n    chatContextMenu_1.append(new electron_1.MenuItem({\r\n        label: '最前面表示',\r\n        type: 'checkbox',\r\n        checked: false,\r\n        click: function (e) {\r\n            globalThis.electron.chatWindow.setAlwaysOnTop(e.checked);\r\n        },\r\n    }));\r\n    // Electronの初期化完了後に実行\r\n    app.on('ready', function () {\r\n        var windowState = electron_window_state_1.default({\r\n            defaultWidth: 700,\r\n            defaultHeight: 720,\r\n            file: 'mainWindow.json',\r\n        });\r\n        // ウィンドウサイズを(フレームサイズを含まない)設定\r\n        var mainWin = new electron_1.default.BrowserWindow({\r\n            // 前回起動時のを復元\r\n            x: windowState.x,\r\n            y: windowState.y,\r\n            width: windowState.width,\r\n            height: windowState.height,\r\n            useContentSize: true,\r\n            icon: iconPath_1,\r\n            webPreferences: {\r\n                nodeIntegration: true,\r\n            },\r\n            skipTaskbar: true,\r\n        });\r\n        globalThis.electron.mainWindow = mainWin;\r\n        windowState.manage(mainWin);\r\n        mainWin.setTitle('unacast');\r\n        mainWin.setMenu(null);\r\n        // レンダラーで使用するhtmlファイルを指定する\r\n        mainWin.loadURL(path_1.default.resolve(__dirname, '../src/html/index.html'));\r\n        // ウィンドウが閉じられたらアプリも終了\r\n        mainWin.on('close', function (event) {\r\n            // 確認ダイアログではいをクリックしたら閉じる\r\n            event.preventDefault();\r\n            electron_1.dialog\r\n                .showMessageBox(mainWin, {\r\n                type: 'question',\r\n                buttons: ['Yes', 'No'],\r\n                // title: '',\r\n                message: '終了しますか?',\r\n            })\r\n                .then(function (value) {\r\n                if (value.response === 0) {\r\n                    app.exit();\r\n                }\r\n            });\r\n        });\r\n        mainWin.on('closed', function () {\r\n            electron_log_1.default.info('[app] close');\r\n            app.exit();\r\n        });\r\n        // 開発者ツールを開く\r\n        // mainWin.webContents.openDevTools();\r\n        // タスクトレイの設定\r\n        var tray = null;\r\n        app.whenReady().then(function () {\r\n            tray = new electron_1.Tray(iconPath_1);\r\n            var contextMenu = electron_1.Menu.buildFromTemplate([\r\n                {\r\n                    label: '設定',\r\n                    click: function () {\r\n                        globalThis.electron.mainWindow.focus();\r\n                    },\r\n                },\r\n                {\r\n                    label: 'コメント',\r\n                    click: function () {\r\n                        globalThis.electron.chatWindow.focus();\r\n                    },\r\n                },\r\n                {\r\n                    label: '終了',\r\n                    click: function () {\r\n                        globalThis.electron.mainWindow.close();\r\n                    },\r\n                },\r\n            ]);\r\n            tray.setToolTip('∈(゚◎゚)∋ウナー');\r\n            tray.setContextMenu(contextMenu);\r\n            // タスクトレイクリック時の挙動\r\n            var isDoubleClicked = false;\r\n            tray.on('click', function (event) { return __awaiter(void 0, void 0, void 0, function () {\r\n                return __generator(this, function (_a) {\r\n                    switch (_a.label) {\r\n                        case 0:\r\n                            isDoubleClicked = false;\r\n                            return [4 /*yield*/, util_1.sleep(200)];\r\n                        case 1:\r\n                            _a.sent();\r\n                            if (isDoubleClicked)\r\n                                return [2 /*return*/];\r\n                            globalThis.electron.chatWindow.focus();\r\n                            return [2 /*return*/];\r\n                    }\r\n                });\r\n            }); });\r\n            tray.on('double-click', function (event) {\r\n                isDoubleClicked = true;\r\n                globalThis.electron.mainWindow.focus();\r\n            });\r\n        });\r\n        createChatWindow();\r\n        // 右クリックメニュー開く\r\n        globalThis.electron.mainWindow.webContents.on('context-menu', function (e, params) {\r\n            mainContextMenu_1.popup({ window: globalThis.electron.mainWindow, x: params.x, y: params.y });\r\n        });\r\n        globalThis.electron.chatWindow.webContents.on('context-menu', function (e, params) {\r\n            chatContextMenu_1.popup({ window: globalThis.electron.chatWindow, x: params.x, y: params.y });\r\n        });\r\n    });\r\n    // 音声再生できるようにする\r\n    app.commandLine.appendSwitch('--autoplay-policy', 'no-user-gesture-required');\r\n}\r\nvar createChatWindow = function () {\r\n    var windowState = electron_window_state_1.default({\r\n        defaultWidth: 400,\r\n        defaultHeight: 720,\r\n        file: 'chatWindow.json',\r\n    });\r\n    var iconPath = path_1.default.resolve(__dirname, '../icon.png');\r\n    var chatWindow = new electron_1.default.BrowserWindow({\r\n        x: windowState.x,\r\n        y: windowState.y,\r\n        width: windowState.width,\r\n        height: windowState.height,\r\n        useContentSize: true,\r\n        icon: iconPath,\r\n        webPreferences: {\r\n            nodeIntegration: true,\r\n        },\r\n        // タスクバーに表示しない\r\n        skipTaskbar: true,\r\n        // 閉じれなくする\r\n        closable: false,\r\n    });\r\n    windowState.manage(chatWindow);\r\n    chatWindow.setTitle('unacast');\r\n    chatWindow.setMenu(null);\r\n    // レンダラーで使用するhtmlファイルを指定する\r\n    chatWindow.loadURL(path_1.default.resolve(__dirname, '../src/html/chat.html'));\r\n    globalThis.electron.chatWindow = chatWindow;\r\n    // chatWindow.webContents.openDevTools();\r\n};\r\n","\"use strict\";\r\nvar __extends = (this && this.__extends) || (function () {\r\n    var extendStatics = function (d, b) {\r\n        extendStatics = Object.setPrototypeOf ||\r\n            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };\r\n        return extendStatics(d, b);\r\n    };\r\n    return function (d, b) {\r\n        extendStatics(d, b);\r\n        function __() { this.constructor = d; }\r\n        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n    };\r\n})();\r\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\r\n    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n    return new (P || (P = Promise))(function (resolve, reject) {\r\n        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n        function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n        step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n    });\r\n};\r\nvar __generator = (this && this.__generator) || function (thisArg, body) {\r\n    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n    return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n    function verb(n) { return function (v) { return step([n, v]); }; }\r\n    function step(op) {\r\n        if (f) throw new TypeError(\"Generator is already executing.\");\r\n        while (_) try {\r\n            if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n            if (y = 0, t) op = [op[0] & 2, t.value];\r\n            switch (op[0]) {\r\n                case 0: case 1: t = op; break;\r\n                case 4: _.label++; return { value: op[1], done: false };\r\n                case 5: _.label++; y = op[1]; op = [0]; continue;\r\n                case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n                default:\r\n                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n                    if (t[2]) _.ops.pop();\r\n                    _.trys.pop(); continue;\r\n            }\r\n            op = body.call(thisArg, _);\r\n        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n    }\r\n};\r\nvar __importDefault = (this && this.__importDefault) || function (mod) {\r\n    return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\n/**\r\n * ニコ生コメント\r\n */\r\nvar events_1 = require(\"events\");\r\nvar axios_1 = __importDefault(require(\"axios\"));\r\nvar cheerio_1 = __importDefault(require(\"cheerio\"));\r\nvar electron_log_1 = __importDefault(require(\"electron-log\"));\r\nvar util_1 = require(\"../util\");\r\nvar ws_1 = __importDefault(require(\"ws\"));\r\nvar NiconamaComment = /** @class */ (function (_super) {\r\n    __extends(NiconamaComment, _super);\r\n    function NiconamaComment(options) {\r\n        var _this = _super.call(this) || this;\r\n        /** 配信開始待ちのインターバル(ms) */\r\n        _this.waitBroadcastPollingInterval = 5000;\r\n        /** 初期処理のコメントを受信し終わった */\r\n        _this.isFirstCommentReceived = false;\r\n        /** 最新のコメント番号 */\r\n        _this.latestNo = NaN;\r\n        /** コメント取得のWebSocket */\r\n        _this.commentSocket = null;\r\n        /** ニコ生の配信開始待ち */\r\n        _this.pollingStartBroadcast = function () { return __awaiter(_this, void 0, void 0, function () {\r\n            var url, res, $, embeddedData, e_1;\r\n            var _a;\r\n            return __generator(this, function (_b) {\r\n                switch (_b.label) {\r\n                    case 0:\r\n                        url = \"https://live2.nicovideo.jp/watch/\" + this.communityId;\r\n                        electron_log_1.default.info(\"[pollingStartBroadcast] \" + url);\r\n                        _b.label = 1;\r\n                    case 1:\r\n                        _b.trys.push([1, 6, , 8]);\r\n                        return [4 /*yield*/, axios_1.default.get(url)];\r\n                    case 2:\r\n                        res = _b.sent();\r\n                        $ = cheerio_1.default.load(res.data);\r\n                        embeddedData = JSON.parse((_a = $('#embedded-data').attr('data-props')) !== null && _a !== void 0 ? _a : '');\r\n                        if (!(embeddedData.program.status === 'ENDED' || embeddedData.program.endTime * 1000 < new Date().getTime())) return [3 /*break*/, 4];\r\n                        return [4 /*yield*/, util_1.sleep(this.waitBroadcastPollingInterval)];\r\n                    case 3:\r\n                        _b.sent();\r\n                        this.pollingStartBroadcast();\r\n                        return [3 /*break*/, 5];\r\n                    case 4:\r\n                        // 始まってる\r\n                        this.emit('start');\r\n                        this.fetchCommentServerThread();\r\n                        _b.label = 5;\r\n                    case 5: return [3 /*break*/, 8];\r\n                    case 6:\r\n                        e_1 = _b.sent();\r\n                        this.emit('error', new Error(\"connection error to \" + url));\r\n                        return [4 /*yield*/, util_1.sleep(this.waitBroadcastPollingInterval * 2)];\r\n                    case 7:\r\n                        _b.sent();\r\n                        this.pollingStartBroadcast();\r\n                        return [3 /*break*/, 8];\r\n                    case 8: return [2 /*return*/];\r\n                }\r\n            });\r\n        }); };\r\n        /** ニコ生のコメントを取得 */\r\n        _this.fetchCommentServerThread = function () { return __awaiter(_this, void 0, void 0, function () {\r\n            var url, res, $, embeddedData, broadcastId, audienceToken, frontendId, threadWssUrl, tWs;\r\n            var _this = this;\r\n            var _a;\r\n            return __generator(this, function (_b) {\r\n                switch (_b.label) {\r\n                    case 0:\r\n                        electron_log_1.default.info(\"[fetchCommentServerThread]\");\r\n                        url = \"https://live2.nicovideo.jp/watch/\" + this.communityId;\r\n                        return [4 /*yield*/, axios_1.default.get(url)];\r\n                    case 1:\r\n                        res = _b.sent();\r\n                        $ = cheerio_1.default.load(res.data);\r\n                        embeddedData = JSON.parse((_a = $('#embedded-data').attr('data-props')) !== null && _a !== void 0 ? _a : '');\r\n                        broadcastId = embeddedData.program.broadcastId || embeddedData.program.reliveProgramId;\r\n                        audienceToken = embeddedData.player.audienceToken;\r\n                        frontendId = embeddedData.site.frontendId;\r\n                        threadWssUrl = \"wss://a.live2.nicovideo.jp/unama/wsapi/v2/watch/\" + broadcastId + \"?audience_token=\" + audienceToken + \"&frontend_id=\" + frontendId;\r\n                        electron_log_1.default.info(threadWssUrl);\r\n                        tWs = new ws_1.default(threadWssUrl);\r\n                        tWs.onmessage = function (event) {\r\n                            var obj = JSON.parse(event.data.toString());\r\n                            // log.info(JSON.stringify(obj, null, '  '));\r\n                            electron_log_1.default.info(\"[fetchCommentServerThread]WS - type: \" + obj.type);\r\n                            switch (obj.type) {\r\n                                case 'serverTime': {\r\n                                    // currentMs\r\n                                    break;\r\n                                }\r\n                                case 'seat': {\r\n                                    // keepIntervalSec\r\n                                    break;\r\n                                }\r\n                                case 'stream': {\r\n                                    // hlsのURLとか\r\n                                    break;\r\n                                }\r\n                                case 'room': {\r\n                                    var data = obj.data;\r\n                                    _this.fetchComment(data.messageServer.uri, data.threadId);\r\n                                    break;\r\n                                }\r\n                                case 'statistics': {\r\n                                    // 視聴者数とか\r\n                                    break;\r\n                                }\r\n                                case 'schedule': {\r\n                                    // 開始、終了時刻\r\n                                    break;\r\n                                }\r\n                                case 'akashic': {\r\n                                    var data = obj.data;\r\n                                    break;\r\n                                }\r\n                                case 'ping': {\r\n                                    break;\r\n                                }\r\n                                // 切断。枠が終了した時もここ。\r\n                                case 'disconnect': {\r\n                                    var data = obj.data;\r\n                                    _this.stop();\r\n                                    _this.start();\r\n                                    break;\r\n                                }\r\n                            }\r\n                        };\r\n                        tWs.on('open', function () {\r\n                            tWs.send(JSON.stringify({\r\n                                type: 'startWatching',\r\n                                data: { stream: { quality: 'high', protocol: 'hls', latency: 'low', chasePlay: false }, room: { protocol: 'webSocket', commentable: true }, reconnect: false },\r\n                            }));\r\n                            tWs.send(JSON.stringify({ type: 'getAkashic', data: { chasePlay: false } }));\r\n                        });\r\n                        return [2 /*return*/];\r\n                }\r\n            });\r\n        }); };\r\n        /**\r\n         *\r\n         * @param wsUrl コメントサーバのWebSocket URL\r\n         * @param threadId threadID\r\n         */\r\n        _this.fetchComment = function (wsUrl, threadId) { return __awaiter(_this, void 0, void 0, function () {\r\n            var ws;\r\n            var _this = this;\r\n            return __generator(this, function (_a) {\r\n                electron_log_1.default.info(\"[fetchComment] threadId = \" + threadId);\r\n                ws = new ws_1.default(wsUrl, 'niconama', {\r\n                    headers: {\r\n                        'Sec-WebSocket-Extensions': 'permessage-deflate; client_max_window_bits',\r\n                        'Sec-WebSocket-Protocol': 'msg.nicovideo.jp#json',\r\n                    },\r\n                });\r\n                ws.on('message', function (event) {\r\n                    var _a, _b, _c;\r\n                    var obj = JSON.parse(event.toString());\r\n                    // 初回取得時は ping, ping, thread, chat, chat..., ping, pingの順で受け取る\r\n                    // log.info(JSON.stringify(obj, null, '  '));\r\n                    // コメント番号更新\r\n                    if ((_a = obj === null || obj === void 0 ? void 0 : obj.chat) === null || _a === void 0 ? void 0 : _a.no) {\r\n                        _this.latestNo = obj.chat.no;\r\n                    }\r\n                    if (((_b = obj === null || obj === void 0 ? void 0 : obj.ping) === null || _b === void 0 ? void 0 : _b.content) === 'rf:0') {\r\n                        _this.isFirstCommentReceived = true;\r\n                        _this.emit('open', { liveId: '', number: _this.latestNo });\r\n                    }\r\n                    if (!_this.isFirstCommentReceived)\r\n                        return;\r\n                    var chat = obj;\r\n                    var comment = (_c = chat.chat) === null || _c === void 0 ? void 0 : _c.content;\r\n                    if (!comment)\r\n                        return;\r\n                    // /で始まるのはなんかコマンドなので除外する\r\n                    if (comment.match(/^\\/[a-z]+ /))\r\n                        return;\r\n                    electron_log_1.default.info(\"[fetchComment]WS - content: \" + comment);\r\n                    var item = {\r\n                        number: chat.chat.no.toString(),\r\n                        name: '',\r\n                        comment: comment,\r\n                    };\r\n                    _this.emit('comment', item);\r\n                });\r\n                ws.on('error', function (event) {\r\n                    electron_log_1.default.info('[fetchComment]なんかエラーだ');\r\n                    electron_log_1.default.info(event);\r\n                });\r\n                ws.on('open', function () {\r\n                    electron_log_1.default.info('[fetchComment] connected');\r\n                    ws.send(JSON.stringify([\r\n                        { ping: { content: 'rs:0' } },\r\n                        { ping: { content: 'ps:0' } },\r\n                        // eslint-disable-next-line @typescript-eslint/camelcase\r\n                        { thread: { thread: threadId, version: '20061206', user_id: 'guest', res_from: -150, with_global: 1, scores: 1, nicoru: 0 } },\r\n                        { ping: { content: 'pf:0' } },\r\n                        { ping: { content: 'rf:0' } },\r\n                    ]));\r\n                });\r\n                this.commentSocket = ws;\r\n                return [2 /*return*/];\r\n            });\r\n        }); };\r\n        /** コメント取得の停止 */\r\n        _this.stop = function () {\r\n            _this.isFirstCommentReceived = false;\r\n            _this.latestNo = NaN;\r\n            if (_this.commentSocket)\r\n                _this.commentSocket.close();\r\n            _this.emit('end');\r\n        };\r\n        if ('communityId' in options) {\r\n            _this.communityId = options.communityId;\r\n        }\r\n        else {\r\n            throw TypeError('Required channelId.');\r\n        }\r\n        return _this;\r\n    }\r\n    NiconamaComment.prototype.start = function () {\r\n        return __awaiter(this, void 0, void 0, function () {\r\n            return __generator(this, function (_a) {\r\n                if (this.communityId) {\r\n                    this.emit('wait');\r\n                    this.pollingStartBroadcast();\r\n                }\r\n                return [2 /*return*/];\r\n            });\r\n        });\r\n    };\r\n    NiconamaComment.prototype.on = function (event, listener) {\r\n        return _super.prototype.on.call(this, event, listener);\r\n    };\r\n    return NiconamaComment;\r\n}(events_1.EventEmitter));\r\nexports.default = NiconamaComment;\r\n","\"use strict\";\r\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\r\n    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n    return new (P || (P = Promise))(function (resolve, reject) {\r\n        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n        function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n        step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n    });\r\n};\r\nvar __generator = (this && this.__generator) || function (thisArg, body) {\r\n    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n    return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n    function verb(n) { return function (v) { return step([n, v]); }; }\r\n    function step(op) {\r\n        if (f) throw new TypeError(\"Generator is already executing.\");\r\n        while (_) try {\r\n            if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n            if (y = 0, t) op = [op[0] & 2, t.value];\r\n            switch (op[0]) {\r\n                case 0: case 1: t = op; break;\r\n                case 4: _.label++; return { value: op[1], done: false };\r\n                case 5: _.label++; y = op[1]; op = [0]; continue;\r\n                case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n                default:\r\n                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n                    if (t[2]) _.ops.pop();\r\n                    _.trys.pop(); continue;\r\n            }\r\n            op = body.call(thisArg, _);\r\n        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n    }\r\n};\r\nvar __importDefault = (this && this.__importDefault) || function (mod) {\r\n    return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\n/**\r\n * 5ch互換BBS読み込み用モジュール\r\n */\r\nvar axios_1 = __importDefault(require(\"axios\"));\r\nvar https_1 = __importDefault(require(\"https\"));\r\nvar iconv_lite_1 = __importDefault(require(\"iconv-lite\")); // 文字コード変換用パッケージ\r\nvar electron_log_1 = __importDefault(require(\"electron-log\"));\r\n// ステータスコード304 _NotModified\r\nvar NOT_MODIFIED = '304';\r\nvar RANGE_NOT_SATISFIABLE = '416';\r\n// 最終取得スレッド\r\nvar lastThreadUrl = '';\r\n// 最終レス番号\r\nvar lastResNumber = 0;\r\n//最終更新日時\r\nvar lastModified = null;\r\n// 最終バイト数\r\nvar lastByte = 0;\r\n/**\r\n * コンストラクタ\r\n *\r\n */\r\nvar Read5ch = /** @class */ (function () {\r\n    function Read5ch() {\r\n        var _this = this;\r\n        // constructor() {}\r\n        /**\r\n         * レス読み込み\r\n         * 引数で指定した板からレスを読む\r\n         * レス番号を指定していない場合は最新1件取得\r\n         * @param threadUrl スレURL\r\n         * @param resNum レス番号\r\n         */\r\n        this.read = function (threadUrl, resNum) { return __awaiter(_this, void 0, void 0, function () {\r\n            var rep, requestUrl, range, options, instance, responseJson, response, headers, str, error_1;\r\n            return __generator(this, function (_a) {\r\n                switch (_a.label) {\r\n                    case 0:\r\n                        // log.info(`[Read5ch] threadUrl=${threadUrl} resNum=${resNum}`);\r\n                        // 板や最終日レス番号がかわったら最初からとり直す(lastmodifiと rangeのリセット)\r\n                        if (threadUrl != lastThreadUrl || Number.isNaN(resNum) || resNum < lastResNumber) {\r\n                            lastThreadUrl = threadUrl;\r\n                            lastModified = null;\r\n                            lastByte = 0;\r\n                            console.trace('[Read5ch.js]resete!!!!!!!!!!!!!!!!');\r\n                        }\r\n                        else {\r\n                            console.trace('noresete');\r\n                        }\r\n                        rep = /\\/test\\/read.cgi(\\/.+)(\\/.+)\\//;\r\n                        requestUrl = threadUrl.replace(rep, '$1/dat$2.dat');\r\n                        range = lastByte;\r\n                        options = {\r\n                            url: requestUrl,\r\n                            method: 'GET',\r\n                            timeout: 3 * 1000,\r\n                            responseType: 'arraybuffer',\r\n                            headers: {\r\n                                'if-modified-since': lastModified,\r\n                                range: 'bytes=' + range + '-',\r\n                            },\r\n                        };\r\n                        instance = axios_1.default.create({\r\n                            httpsAgent: new https_1.default.Agent({\r\n                                rejectUnauthorized: false,\r\n                            }),\r\n                        });\r\n                        _a.label = 1;\r\n                    case 1:\r\n                        _a.trys.push([1, 3, , 4]);\r\n                        return [4 /*yield*/, instance(options)];\r\n                    case 2:\r\n                        response = _a.sent();\r\n                        headers = response.headers;\r\n                        // LastModifiedとRange更新処理\r\n                        if (headers['last-modified'] != null) {\r\n                            lastModified = headers['last-modified'];\r\n                        }\r\n                        str = iconv_lite_1.default.decode(Buffer.from(response.data), 'Shift_JIS');\r\n                        // レスポンスオブジェクト作成、content-rangeがある場合とない場合で処理を分ける\r\n                        if (headers['content-range'] == null || lastByte == 0) {\r\n                            console.trace('[Read5ch.read]content-range=' + headers['content-range']);\r\n                            responseJson = purseNewResponse(str, resNum);\r\n                        }\r\n                        else {\r\n                            responseJson = purseDiffResponse(str, resNum);\r\n                        }\r\n                        // 取得バイト数表示\r\n                        if (headers['content-length'] != null && responseJson.length > 0) {\r\n                            lastByte = lastByte + parseInt(headers['content-length']) - 1;\r\n                            console.trace('[Read5ch.read]lastByte=' + lastByte);\r\n                        }\r\n                        return [3 /*break*/, 4];\r\n                    case 3:\r\n                        error_1 = _a.sent();\r\n                        responseJson = [];\r\n                        if (error_1.status == NOT_MODIFIED) {\r\n                            electron_log_1.default.error('[Read5ch.js]5ch系BBSレス取得APIリクエストエラー、NOT_MODIFIED');\r\n                        }\r\n                        else if (error_1.status == RANGE_NOT_SATISFIABLE) {\r\n                            electron_log_1.default.error('[Read5ch.js]5ch系BBSレス取得APIリクエストエラー、RANGE_NOT_SATISFIABLE');\r\n                        }\r\n                        else {\r\n                            electron_log_1.default.error('[Read5ch.js]5ch系BBSレス取得APIリクエストエラー、message=' + error_1.message);\r\n                        }\r\n                        throw new Error('connection error');\r\n                    case 4: return [2 /*return*/, responseJson];\r\n                }\r\n            });\r\n        }); };\r\n    }\r\n    return Read5ch;\r\n}());\r\n/**\r\n * 取得したレスポンス(複数)のパース\r\n * 戻りとしてパースしたjsonオブジェクトの配列を返す\r\n * @param res 板から返却されたdat\r\n * @param resNum リクエストされたレス番号\r\n */\r\nvar purseNewResponse = function (res, resNum) {\r\n    // 結果を格納する配列\r\n    var result = [];\r\n    // レス番号\r\n    var num = 0;\r\n    // 新着レスを改行ごとにSplitする\r\n    var resArray = res.split(/\\r\\n|\\r|\\n/);\r\n    // 新着なしなら戻る。\r\n    if (resArray.length === 0) {\r\n        return result;\r\n    }\r\n    // 配列の最後に空の要素が入ることがあるので取り除く\r\n    if (resArray[resArray.length - 1].length === 0) {\r\n        resArray.pop();\r\n    }\r\n    // レス指定なしの場合最後の1件取得\r\n    if (Number.isNaN(resNum)) {\r\n        num = resArray.length - 1;\r\n    }\r\n    else {\r\n        num = resNum - 1;\r\n    }\r\n    // 1行ごとにパースする\r\n    for (; num < resArray.length; num++) {\r\n        // パースメソッド呼び出し\r\n        if (resArray[num].length > 0) {\r\n            result.push(purseResponse(resArray[num], num + 1));\r\n        }\r\n    }\r\n    lastResNumber = num + 1;\r\n    // パースしたオブジェクトの配列を返却\r\n    return result;\r\n};\r\n/**\r\n * 取得したレスポンス(複数)のパース\r\n * 戻りとしてパースしたjsonオブジェクトの配列を返す\r\n * @param res 板から返却されたdat1行分\r\n * @param resNum リクエストされたレス番号\r\n */\r\nvar purseDiffResponse = function (res, resNum) {\r\n    //結果を格納する配列\r\n    var result = [];\r\n    // レス番号\r\n    var num = resNum;\r\n    //新着レスを改行ごとにSplitする\r\n    var resArray = res.split(/\\r\\n|\\r|\\n/);\r\n    // 新着なしなら戻る。\r\n    if (resArray.length === 0) {\r\n        return result;\r\n    }\r\n    else {\r\n        // 配列の最後に空の要素が入ることがあるので取り除く\r\n        if (resArray[resArray.length - 1].length == 0) {\r\n            resArray.pop();\r\n        }\r\n    }\r\n    console.trace('[Read5ch.purseDiffResponse]取得レス番号=' + num);\r\n    //1行ごとにパースする\r\n    resArray.forEach(function (value) {\r\n        //パースメソッド呼び出し\r\n        if (value.length > 0) {\r\n            result.push(purseResponse(value, num));\r\n            num++;\r\n        }\r\n    });\r\n    // パースしたオブジェクトの配列を返却\r\n    return result;\r\n};\r\n/**\r\n * レスポンスのパース\r\n * Jsonオブジェクトを返却する\r\n * @param String // res レスポンス1レス\r\n * @param Integer // num レス番(0スタート)\r\n */\r\nvar purseResponse = function (res, num) {\r\n    //APIの返却値を<>で分割\r\n    //レスの要素\r\n    //0:名前\r\n    //1:メアド\r\n    //2:日付とID (2019/11/03(日) 08:55:00 ID:kanikani)みたいに表示\r\n    //3:本文\r\n    //4:スレタイ (1レス目のみ)\r\n    var splitRes = res.split('<>');\r\n    // 日付とID分離処理、' ID:'で区切る\r\n    var dateId = splitRes[2].split(' ID:');\r\n    var date = dateId[0];\r\n    var id = dateId.length === 2 ? dateId[1] : '';\r\n    var resJson = {\r\n        number: num.toString(),\r\n        name: splitRes[0],\r\n        email: splitRes[1],\r\n        date: date,\r\n        text: splitRes[3],\r\n        // threadTitle: splitRes[4],\r\n        id: id,\r\n        imgUrl: '',\r\n    };\r\n    // オブジェクトを返却\r\n    return resJson;\r\n};\r\nexports.default = Read5ch;\r\n","\"use strict\";\r\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\r\n    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n    return new (P || (P = Promise))(function (resolve, reject) {\r\n        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n        function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n        step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n    });\r\n};\r\nvar __generator = (this && this.__generator) || function (thisArg, body) {\r\n    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n    return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n    function verb(n) { return function (v) { return step([n, v]); }; }\r\n    function step(op) {\r\n        if (f) throw new TypeError(\"Generator is already executing.\");\r\n        while (_) try {\r\n            if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n            if (y = 0, t) op = [op[0] & 2, t.value];\r\n            switch (op[0]) {\r\n                case 0: case 1: t = op; break;\r\n                case 4: _.label++; return { value: op[1], done: false };\r\n                case 5: _.label++; y = op[1]; op = [0]; continue;\r\n                case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n                default:\r\n                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n                    if (t[2]) _.ops.pop();\r\n                    _.trys.pop(); continue;\r\n            }\r\n            op = body.call(thisArg, _);\r\n        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n    }\r\n};\r\nvar __importDefault = (this && this.__importDefault) || function (mod) {\r\n    return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\n/**\r\n * したらば読み込み用モジュール\r\n */\r\nvar axios_1 = __importDefault(require(\"axios\"));\r\nvar https_1 = __importDefault(require(\"https\"));\r\nvar iconv_lite_1 = __importDefault(require(\"iconv-lite\")); // 文字コード変換用パッケージ\r\n/**\r\n * コンストラクタ\r\n */\r\nvar ReadSitaraba = /** @class */ (function () {\r\n    function ReadSitaraba() {\r\n        // constructor() {}\r\n        var _this = this;\r\n        /**\r\n         * レス読み込み\r\n         * @description 引数で指定した板からレスを読む。\r\n         * @description レス番号を指定していない場合は最新1件取得\r\n         * @param threadUrl スレURL\r\n         * @param resNum レス番号\r\n         */\r\n        this.read = function (threadUrl, resNum) { return __awaiter(_this, void 0, void 0, function () {\r\n            var requestUrl, options, instance, response, str, responseJson;\r\n            return __generator(this, function (_a) {\r\n                switch (_a.label) {\r\n                    case 0:\r\n                        requestUrl = threadUrl.replace('read.cgi', 'rawmode.cgi');\r\n                        if (resNum > 0) {\r\n                            // レス番号がある場合レス番号以降を取得\r\n                            requestUrl += resNum + '-';\r\n                        }\r\n                        else {\r\n                            // レス番号がない場合最新の1件取得\r\n                            requestUrl += 'l1';\r\n                        }\r\n                        options = {\r\n                            url: requestUrl,\r\n                            method: 'GET',\r\n                            responseType: 'arraybuffer',\r\n                            timeout: 3 * 1000,\r\n                            headers: {\r\n                                Accept: '*/*',\r\n                            },\r\n                        };\r\n                        instance = axios_1.default.create({\r\n                            httpsAgent: new https_1.default.Agent({\r\n                                rejectUnauthorized: false,\r\n                            }),\r\n                        });\r\n                        return [4 /*yield*/, instance(options)];\r\n                    case 1:\r\n                        response = _a.sent();\r\n                        str = decodeUnicodeStr(iconv_lite_1.default.decode(Buffer.from(response.data), 'EUC-JP'));\r\n                        responseJson = purseNewResponse(str);\r\n                        return [2 /*return*/, responseJson];\r\n                }\r\n            });\r\n        }); };\r\n    }\r\n    return ReadSitaraba;\r\n}());\r\n/**\r\n * 取得したレスポンス(複数)のパース\r\n * @param res\r\n */\r\nvar purseNewResponse = function (res) {\r\n    //結果を格納する配列\r\n    var result = [];\r\n    // 新着レスを改行ごとにSplitする\r\n    var resArray = res.split(/\\r\\n|\\r|\\n/);\r\n    // 1行ごとにパースする\r\n    resArray.forEach(function (value) {\r\n        // パースメソッド呼び出し\r\n        if (value.length > 0) {\r\n            result.push(purseResponse(value));\r\n        }\r\n    });\r\n    return result;\r\n};\r\n/**\r\n * レスポンスのパース\r\n * Jsonオブジェクトを返却する\r\n * @param String // res レスポンス1レス\r\n */\r\nvar purseResponse = function (res) {\r\n    //APIの返却値を<>で分割\r\n    //レスの要素\r\n    //0:レス番号\r\n    //1:名前\r\n    //2:メアド\r\n    //3:日付\r\n    //4:本文\r\n    //5:スレタイ\r\n    //6:ID\r\n    var splitRes = res.split('<>');\r\n    var resJson = {\r\n        number: splitRes[0],\r\n        name: splitRes[1],\r\n        email: splitRes[2],\r\n        date: splitRes[3],\r\n        text: splitRes[4],\r\n        // threadTitle: splitRes[5],\r\n        id: splitRes[6],\r\n        imgUrl: '',\r\n    };\r\n    // オブジェクトを返却\r\n    return resJson;\r\n};\r\n/** したらばだけは全角ダッシュがUnicode文字列として格納されるので変換する */\r\nvar decodeUnicodeStr = function (str) {\r\n    return str.replace(/&#65374;/g, '~');\r\n};\r\nexports.default = ReadSitaraba;\r\n","\"use strict\";\r\nvar __assign = (this && this.__assign) || function () {\r\n    __assign = Object.assign || function(t) {\r\n        for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n            s = arguments[i];\r\n            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))\r\n                t[p] = s[p];\r\n        }\r\n        return t;\r\n    };\r\n    return __assign.apply(this, arguments);\r\n};\r\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\r\n    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n    return new (P || (P = Promise))(function (resolve, reject) {\r\n        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n        function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n        step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n    });\r\n};\r\nvar __generator = (this && this.__generator) || function (thisArg, body) {\r\n    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n    return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n    function verb(n) { return function (v) { return step([n, v]); }; }\r\n    function step(op) {\r\n        if (f) throw new TypeError(\"Generator is already executing.\");\r\n        while (_) try {\r\n            if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n            if (y = 0, t) op = [op[0] & 2, t.value];\r\n            switch (op[0]) {\r\n                case 0: case 1: t = op; break;\r\n                case 4: _.label++; return { value: op[1], done: false };\r\n                case 5: _.label++; y = op[1]; op = [0]; continue;\r\n                case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n                default:\r\n                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n                    if (t[2]) _.ops.pop();\r\n                    _.trys.pop(); continue;\r\n            }\r\n            op = body.call(thisArg, _);\r\n        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n    }\r\n};\r\nvar __spreadArrays = (this && this.__spreadArrays) || function () {\r\n    for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n    for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n        for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n            r[k] = a[j];\r\n    return r;\r\n};\r\nvar __importDefault = (this && this.__importDefault) || function (mod) {\r\n    return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n};\r\nvar __importStar = (this && this.__importStar) || function (mod) {\r\n    if (mod && mod.__esModule) return mod;\r\n    var result = {};\r\n    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];\r\n    result[\"default\"] = mod;\r\n    return result;\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar path_1 = __importDefault(require(\"path\"));\r\nvar express_1 = __importDefault(require(\"express\"));\r\nvar electron_log_1 = __importDefault(require(\"electron-log\"));\r\nvar dank_twitch_irc_1 = require(\"dank-twitch-irc\");\r\nvar youtube_chat_1 = require(\"./youtube-chat\");\r\nvar electron_1 = require(\"electron\");\r\nvar express_ws_1 = __importDefault(require(\"express-ws\"));\r\nvar util_1 = require(\"./util\");\r\n// レス取得APIをセット\r\nvar getRes_1 = __importStar(require(\"./getRes\"));\r\nvar bouyomi_chan_1 = __importDefault(require(\"./bouyomi-chan\"));\r\nvar child_process_1 = require(\"child_process\");\r\nvar const_1 = require(\"./const\");\r\nvar niconama_1 = __importDefault(require(\"./niconama\"));\r\nvar app;\r\n// サーバーをグローバル変数にセットできるようにする(サーバー停止処理のため)\r\nvar server;\r\n/** 棒読みちゃんインスタンス */\r\nvar bouyomi;\r\n/** スレッド定期取得実行するか */\r\nvar threadIntervalEvent = false;\r\n/** キュー処理実行するか */\r\nvar isExecuteQue = false;\r\n/** 接続中の全WebSocket */\r\nvar aWss;\r\nvar serverId = 0;\r\n/**\r\n * 設定の適用\r\n */\r\nelectron_1.ipcMain.on(const_1.electronEvent['apply-config'], function (event, config) { return __awaiter(void 0, void 0, void 0, function () {\r\n    var isChangedUrl, isChangeSePath, ret;\r\n    return __generator(this, function (_a) {\r\n        switch (_a.label) {\r\n            case 0:\r\n                electron_log_1.default.info('[apply-config] start');\r\n                electron_log_1.default.info(config);\r\n                isChangedUrl = globalThis.config.url !== config.url;\r\n                isChangeSePath = globalThis.config.sePath !== config.sePath;\r\n                globalThis.config = config;\r\n                if (!isChangeSePath) return [3 /*break*/, 2];\r\n                return [4 /*yield*/, exports.findSeList()];\r\n            case 1:\r\n                _a.sent();\r\n                _a.label = 2;\r\n            case 2:\r\n                // initメッセージ\r\n                resetInitMessage();\r\n                if (!isChangedUrl) return [3 /*break*/, 4];\r\n                return [4 /*yield*/, getRes_1.getRes(globalThis.config.url, NaN)];\r\n            case 3:\r\n                ret = _a.sent();\r\n                console.log(ret);\r\n                if (ret.length === 0) {\r\n                    globalThis.electron.mainWindow.webContents.send(const_1.electronEvent['show-alert'], '掲示板URLがおかしそうです');\r\n                    return [2 /*return*/];\r\n                }\r\n                globalThis.electron.threadNumber = Number(ret[ret.length - 1].number);\r\n                electron_log_1.default.info(\"[apply-config] new res num is \" + globalThis.electron.threadNumber);\r\n                // チャットウィンドウとブラウザに、末尾のスレだけ反映する\r\n                sendDom([ret[ret.length - 1]]);\r\n                _a.label = 4;\r\n            case 4: return [2 /*return*/];\r\n        }\r\n    });\r\n}); });\r\n/**\r\n * サーバー起動\r\n */\r\nelectron_1.ipcMain.on(const_1.electronEvent['start-server'], function (event, config) { return __awaiter(void 0, void 0, void 0, function () {\r\n    var expressInstance, nico;\r\n    return __generator(this, function (_a) {\r\n        globalThis.electron.chatWindow.webContents.send(const_1.electronEvent['clear-comment']);\r\n        globalThis.electron.threadNumber = 0;\r\n        globalThis.electron.commentQueueList = [];\r\n        globalThis.electron.threadConnectionError = 0;\r\n        serverId = new Date().getTime();\r\n        expressInstance = express_ws_1.default(express_1.default());\r\n        app = expressInstance.app;\r\n        aWss = expressInstance.getWss();\r\n        app.set('view engine', 'ejs');\r\n        // viewディレクトリの指定\r\n        app.set('views', path_1.default.resolve(__dirname, '../views'));\r\n        // 設定情報をグローバル変数へセットする\r\n        globalThis.config = config;\r\n        console.log('[startServer]設定値 = ');\r\n        console.log(globalThis.config);\r\n        app.get('/', function (req, res, next) {\r\n            res.render('server', config);\r\n            req.connection.end();\r\n        });\r\n        // サーバー設定のIF\r\n        app.get('/config', function (req, res, next) {\r\n            res.send(JSON.stringify(globalThis.config));\r\n        });\r\n        // 静的コンテンツはpublicディレクトリの中身を使用するという宣言\r\n        app.use(express_1.default.static(path_1.default.resolve(__dirname, '../public')));\r\n        // 2ch互換掲示板の取得\r\n        app.use('/getRes', getRes_1.default);\r\n        // SEを取得する\r\n        if (globalThis.config.sePath) {\r\n            exports.findSeList();\r\n        }\r\n        // Twitchに接続\r\n        if (globalThis.config.twitchId) {\r\n            startTwitchChat();\r\n        }\r\n        // Youtubeチャット\r\n        if (globalThis.config.youtubeId) {\r\n            startYoutubeChat();\r\n        }\r\n        // ニコ生\r\n        if (globalThis.config.niconicoId) {\r\n            nico = new niconama_1.default({ communityId: globalThis.config.niconicoId });\r\n            globalThis.electron.niconicoChat = nico;\r\n            nico.on('start', function () {\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'niconico', category: 'status', message: \"connection waiting\" });\r\n            });\r\n            nico.on('wait', function () {\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'niconico', category: 'status', message: \"wait for starting boradcast\" });\r\n            });\r\n            nico.on('open', function (event) {\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, {\r\n                    commentType: 'niconico',\r\n                    category: 'status',\r\n                    message: \"ok No=\" + event.number,\r\n                });\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, {\r\n                    commentType: 'niconico',\r\n                    category: 'liveId',\r\n                    message: \"\" + event.liveId,\r\n                });\r\n            });\r\n            nico.on('comment', function (event) {\r\n                globalThis.electron.commentQueueList.push({ imgUrl: './img/niconico.png', number: event.number, name: event.name, text: event.comment });\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, {\r\n                    commentType: 'niconico',\r\n                    category: 'status',\r\n                    message: \"ok No=\" + event.number,\r\n                });\r\n            });\r\n            // 切断とか枠終了とか\r\n            nico.on('end', function () {\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, {\r\n                    commentType: 'niconico',\r\n                    category: 'status',\r\n                    message: \"disconnect\",\r\n                });\r\n            });\r\n            nico.on('error', function () {\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'niconico', category: 'status', message: \"error\" });\r\n            });\r\n            nico.start();\r\n        }\r\n        // 棒読みちゃん接続\r\n        if (config.typeYomiko === 'bouyomi') {\r\n            if (config.bouyomiPort) {\r\n                bouyomi = new bouyomi_chan_1.default({ port: config.bouyomiPort, volume: config.bouyomiVolume });\r\n            }\r\n        }\r\n        // レス取得定期実行\r\n        threadIntervalEvent = true;\r\n        getResInterval(serverId);\r\n        // キュー処理の開始\r\n        isExecuteQue = true;\r\n        taskScheduler(serverId);\r\n        // WebSocketを立てる\r\n        app.ws('/ws', function (ws, req) {\r\n            ws.on('message', function (message) {\r\n                console.trace('Received: ' + message);\r\n                if (message === 'ping') {\r\n                    ws.send('pong');\r\n                }\r\n            });\r\n            ws.on('close', function () {\r\n                console.log('I lost a client');\r\n            });\r\n        });\r\n        // 指定したポートで待ち受け開始\r\n        server = app.listen(config.port, function () {\r\n            console.log('[startServer] start server on port:' + config.port);\r\n        });\r\n        // 成功メッセージ返却\r\n        event.returnValue = 'success';\r\n        return [2 /*return*/];\r\n    });\r\n}); });\r\nexports.findSeList = function () { return __awaiter(void 0, void 0, void 0, function () {\r\n    var list, e_1;\r\n    return __generator(this, function (_a) {\r\n        switch (_a.label) {\r\n            case 0:\r\n                _a.trys.push([0, 4, , 5]);\r\n                if (!globalThis.config.sePath) return [3 /*break*/, 2];\r\n                return [4 /*yield*/, util_1.readWavFiles(globalThis.config.sePath)];\r\n            case 1:\r\n                list = _a.sent();\r\n                globalThis.electron.seList = list.map(function (file) { return globalThis.config.sePath + \"/\" + file; });\r\n                console.log(\"SE files = \" + globalThis.electron.seList.length);\r\n                return [3 /*break*/, 3];\r\n            case 2:\r\n                globalThis.electron.seList = [];\r\n                _a.label = 3;\r\n            case 3: return [3 /*break*/, 5];\r\n            case 4:\r\n                e_1 = _a.sent();\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent['show-alert'], '着信音のパスがおかしそうです');\r\n                return [3 /*break*/, 5];\r\n            case 5: return [2 /*return*/];\r\n        }\r\n    });\r\n}); };\r\n/**\r\n * Twitchチャットに接続\r\n * @description 再接続処理はライブラリが勝手にやってくれる\r\n */\r\nvar startTwitchChat = function () { return __awaiter(void 0, void 0, void 0, function () {\r\n    var twitchChat;\r\n    return __generator(this, function (_a) {\r\n        try {\r\n            twitchChat = new dank_twitch_irc_1.ChatClient();\r\n            twitchChat.connect();\r\n            twitchChat.join(globalThis.config.twitchId);\r\n            globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'twitch', category: 'status', message: 'wait live' });\r\n            // 接続完了\r\n            twitchChat.on('ready', function () {\r\n                console.log('[Twitch] Successfully connected to chat');\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'twitch', category: 'status', message: 'ok' });\r\n            });\r\n            // チャット受信\r\n            twitchChat.on('PRIVMSG', function (msg) {\r\n                electron_log_1.default.info('[Twitch] comment received');\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'twitch', category: 'status', message: 'ok' });\r\n                // log.info(JSON.stringify(msg, null, '  '));\r\n                var imgUrl = './img/twitch.png';\r\n                var name = util_1.escapeHtml(msg.displayName);\r\n                var text = util_1.escapeHtml(msg.messageText);\r\n                // エモートを画像タグにする\r\n                msg.emotes.map(function (emote) {\r\n                    text = text.replace(emote.code, \"<img src=\\\"https://static-cdn.jtvnw.net/emoticons/v1/\" + emote.id + \"/1.0\\\" />\");\r\n                });\r\n                globalThis.electron.commentQueueList.push({ imgUrl: imgUrl, name: name, text: text });\r\n            });\r\n            globalThis.electron.twitchChat = twitchChat;\r\n            // なんかエラーがあった\r\n            twitchChat.on('error', function (event) {\r\n                electron_log_1.default.error(\"[Twitch] \" + JSON.stringify(event));\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'twitch', category: 'status', message: 'error!' });\r\n            });\r\n            twitchChat.on('close', function (event) {\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'twitch', category: 'status', message: 'connection end' });\r\n            });\r\n        }\r\n        catch (e) {\r\n            electron_log_1.default.error(e);\r\n            globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'twitch', category: 'status', message: 'error!' });\r\n        }\r\n        return [2 /*return*/];\r\n    });\r\n}); };\r\n/** Youtubeチャットに接続 */\r\nvar startYoutubeChat = function () { return __awaiter(void 0, void 0, void 0, function () {\r\n    return __generator(this, function (_a) {\r\n        try {\r\n            electron_log_1.default.info('[Youtube Chat] connect started');\r\n            globalThis.electron.youtubeChat = new youtube_chat_1.LiveChat({ channelId: globalThis.config.youtubeId });\r\n            globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'youtube', category: 'status', message: 'wait live' });\r\n            // 接続開始イベント\r\n            globalThis.electron.youtubeChat.on('start', function (liveId) {\r\n                electron_log_1.default.info(\"[Youtube Chat] connected liveId = \" + liveId);\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'youtube', category: 'liveid', message: liveId });\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'youtube', category: 'status', message: 'ok' });\r\n            });\r\n            // 接続終了イベント\r\n            globalThis.electron.youtubeChat.on('end', function (reason) {\r\n                electron_log_1.default.info('[Youtube Chat] disconnect');\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'youtube', category: 'status', message: 'connection end' });\r\n            });\r\n            // チャット受信\r\n            globalThis.electron.youtubeChat.on('comment', function (comment) {\r\n                var _a, _b;\r\n                electron_log_1.default.info('[Youtube] comment received');\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'youtube', category: 'status', message: 'ok' });\r\n                // log.info(JSON.stringify(comment, null, '  '));\r\n                var imgUrl = (_b = (_a = comment.author.thumbnail) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '';\r\n                var name = util_1.escapeHtml(comment.author.name);\r\n                // 絵文字と結合する\r\n                var text = '';\r\n                for (var _i = 0, _c = comment.message; _i < _c.length; _i++) {\r\n                    var message = _c[_i];\r\n                    var txtItem = message.text;\r\n                    if (txtItem) {\r\n                        text += util_1.escapeHtml(txtItem);\r\n                    }\r\n                    else {\r\n                        var imageItem = message;\r\n                        text += \"<img src=\\\"\" + imageItem.url + \"\\\" width=\\\"\" + 24 + \"\\\" height=\\\"\" + 24 + \"\\\" />\";\r\n                    }\r\n                }\r\n                // const text = escapeHtml((comment.message[0] as any).text);\r\n                globalThis.electron.commentQueueList.push({ imgUrl: imgUrl, name: name, text: text });\r\n            });\r\n            // 何かエラーがあった\r\n            globalThis.electron.youtubeChat.on('error', function (err) {\r\n                electron_log_1.default.error(\"[Youtube Chat] error \" + err.message);\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'youtube', category: 'status', message: \"error! \" + err.message });\r\n            });\r\n            globalThis.electron.youtubeChat.start();\r\n        }\r\n        catch (e) {\r\n            // たぶんここには来ない\r\n            electron_log_1.default.error(e);\r\n        }\r\n        return [2 /*return*/];\r\n    });\r\n}); };\r\n/**\r\n * サーバー停止\r\n */\r\nelectron_1.ipcMain.on(const_1.electronEvent['stop-server'], function (event) {\r\n    console.log('[startServer]server stop');\r\n    server.close();\r\n    aWss.close();\r\n    app = null;\r\n    event.returnValue = 'stop';\r\n    // キュー処理停止\r\n    isExecuteQue = false;\r\n    globalThis.electron.commentQueueList = [];\r\n    // レス取得の停止\r\n    threadIntervalEvent = false;\r\n    globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'bbs', category: 'status', message: \"connection end\" });\r\n    // Twitchチャットの停止\r\n    if (globalThis.electron.twitchChat) {\r\n        globalThis.electron.twitchChat.close();\r\n        globalThis.electron.twitchChat.removeAllListeners();\r\n        globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'twitch', category: 'status', message: \"connection end\" });\r\n    }\r\n    // Youtubeチャットの停止\r\n    if (globalThis.electron.youtubeChat) {\r\n        globalThis.electron.youtubeChat.stop();\r\n        globalThis.electron.youtubeChat.removeAllListeners();\r\n        globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'youtube', category: 'status', message: \"connection end\" });\r\n        globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'youtube', category: 'liveId', message: \"none\" });\r\n    }\r\n    // ニコ生チャットの停止\r\n    if (globalThis.electron.niconicoChat) {\r\n        globalThis.electron.niconicoChat.stop();\r\n        globalThis.electron.niconicoChat.removeAllListeners();\r\n        globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'niconico', category: 'status', message: \"connection end\" });\r\n        globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'niconico', category: 'liveId', message: \"none\" });\r\n    }\r\n});\r\nvar getResInterval = function (exeId) { return __awaiter(void 0, void 0, void 0, function () {\r\n    var resNum, isfirst, result, temp, _loop_1, _i, result_1, item;\r\n    return __generator(this, function (_a) {\r\n        switch (_a.label) {\r\n            case 0:\r\n                isfirst = false;\r\n                if (!globalThis.electron.threadNumber) {\r\n                    // 初回\r\n                    isfirst = true;\r\n                    resNum = globalThis.config.resNumber ? Number(globalThis.config.resNumber) : NaN;\r\n                }\r\n                else {\r\n                    // 2回目以降\r\n                    resNum = globalThis.electron.threadNumber;\r\n                }\r\n                return [4 /*yield*/, getRes_1.getRes(globalThis.config.url, resNum)];\r\n            case 1:\r\n                result = _a.sent();\r\n                // 指定したレス番は除外対象\r\n                if (!isfirst)\r\n                    result.shift();\r\n                if (result.length > 0 && result[result.length - 1].number) {\r\n                    globalThis.electron.threadNumber = Number(result[result.length - 1].number);\r\n                    if (isfirst) {\r\n                        temp = result;\r\n                        if (!globalThis.config.dispSort) {\r\n                            temp = temp.reverse();\r\n                        }\r\n                        sendDomForChatWindow(temp);\r\n                    }\r\n                    else {\r\n                        _loop_1 = function (item) {\r\n                            // リストに同じレス番があったら追加しない\r\n                            if (!globalThis.electron.commentQueueList.find(function (comment) { return comment.number === item.number; })) {\r\n                                globalThis.electron.commentQueueList.push(item);\r\n                            }\r\n                        };\r\n                        for (_i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n                            item = result_1[_i];\r\n                            _loop_1(item);\r\n                        }\r\n                    }\r\n                    globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'bbs', category: 'status', message: \"ok res=\" + globalThis.electron.threadNumber });\r\n                }\r\n                else if (result.length > 0) {\r\n                    globalThis.electron.mainWindow.webContents.send(const_1.electronEvent.UPDATE_STATUS, { commentType: 'bbs', category: 'status', message: 'error!' });\r\n                    // 番号が無くて結果が入ってるのは通信エラーメッセージ\r\n                    sendDomForChatWindow(result);\r\n                }\r\n                return [4 /*yield*/, notifyThreadResLimit()];\r\n            case 2:\r\n                _a.sent();\r\n                if (!(threadIntervalEvent && exeId === serverId)) return [3 /*break*/, 4];\r\n                return [4 /*yield*/, util_1.sleep(globalThis.config.interval * 1000)];\r\n            case 3:\r\n                _a.sent();\r\n                getResInterval(exeId);\r\n                _a.label = 4;\r\n            case 4: return [2 /*return*/];\r\n        }\r\n    });\r\n}); };\r\n/** レス番が上限かチェックして、超えてたら通知する */\r\nvar notifyThreadResLimit = function () { return __awaiter(void 0, void 0, void 0, function () {\r\n    return __generator(this, function (_a) {\r\n        switch (_a.label) {\r\n            case 0:\r\n                if (!(globalThis.config.notifyThreadResLimit > 0 && globalThis.electron.threadNumber >= globalThis.config.notifyThreadResLimit)) return [3 /*break*/, 2];\r\n                globalThis.electron.commentQueueList.push({\r\n                    name: 'unacastより',\r\n                    imgUrl: './img/unacast.png',\r\n                    text: \"\\u30EC\\u30B9\\u304C\" + globalThis.config.notifyThreadResLimit + \"\\u3092\\u8D85\\u3048\\u307E\\u3057\\u305F\\u3002\\u6B21\\u30B9\\u30EC\\u3092\\u7ACB\\u3066\\u3066\\u304F\\u3060\\u3055\\u3044\\u3002\",\r\n                });\r\n                // TODO: 次スレ検索ポーリング処理を走らせる\r\n                // スレ立て中だと思うのでちょっと待つ\r\n                return [4 /*yield*/, util_1.sleep(10 * 1000)];\r\n            case 1:\r\n                // TODO: 次スレ検索ポーリング処理を走らせる\r\n                // スレ立て中だと思うのでちょっと待つ\r\n                _a.sent();\r\n                _a.label = 2;\r\n            case 2: return [2 /*return*/];\r\n        }\r\n    });\r\n}); };\r\n/**\r\n * キューに溜まったコメントを処理する\r\n */\r\nvar taskScheduler = function (exeId) { return __awaiter(void 0, void 0, void 0, function () {\r\n    var temp, comment;\r\n    var _a, _b, _c, _d;\r\n    return __generator(this, function (_e) {\r\n        switch (_e.label) {\r\n            case 0:\r\n                if (!(((_b = (_a = globalThis.electron) === null || _a === void 0 ? void 0 : _a.commentQueueList) === null || _b === void 0 ? void 0 : _b.length) > 0)) return [3 /*break*/, 3];\r\n                electron_log_1.default.info(\"[taskScheduler] \" + ((_d = (_c = globalThis.electron) === null || _c === void 0 ? void 0 : _c.commentQueueList) === null || _d === void 0 ? void 0 : _d.length));\r\n                if (!(globalThis.config.commentProcessType === 0)) return [3 /*break*/, 1];\r\n                temp = __spreadArrays(globalThis.electron.commentQueueList);\r\n                globalThis.electron.commentQueueList = [];\r\n                // 新着が上の場合は逆順にする\r\n                if (!globalThis.config.dispSort) {\r\n                    temp = temp.reverse();\r\n                }\r\n                sendDom(temp);\r\n                return [3 /*break*/, 3];\r\n            case 1:\r\n                comment = globalThis.electron.commentQueueList.shift();\r\n                return [4 /*yield*/, sendDom([comment])];\r\n            case 2:\r\n                _e.sent();\r\n                _e.label = 3;\r\n            case 3:\r\n                if (!(isExecuteQue && exeId === serverId)) return [3 /*break*/, 5];\r\n                return [4 /*yield*/, util_1.sleep(100)];\r\n            case 4:\r\n                _e.sent();\r\n                taskScheduler(exeId);\r\n                _e.label = 5;\r\n            case 5: return [2 /*return*/];\r\n        }\r\n    });\r\n}); };\r\n/** 読み子によって発話中であるか */\r\nvar isSpeaking = false;\r\n/** 読み子を再生する */\r\nvar playYomiko = function (msg) { return __awaiter(void 0, void 0, void 0, function () {\r\n    return __generator(this, function (_a) {\r\n        switch (_a.label) {\r\n            case 0:\r\n                // log.info('[playYomiko] start');\r\n                isSpeaking = true;\r\n                // 読み子呼び出し\r\n                switch (config.typeYomiko) {\r\n                    case 'tamiyasu': {\r\n                        console.log(config.tamiyasuPath + \" \\\"\" + msg + \"\\\"\");\r\n                        child_process_1.spawn(config.tamiyasuPath, [msg]);\r\n                        break;\r\n                    }\r\n                    case 'bouyomi': {\r\n                        if (bouyomi)\r\n                            bouyomi.speak(msg);\r\n                        break;\r\n                    }\r\n                }\r\n                // 読み子が読んでる時間分相当待つ\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent['wait-yomiko-time'], msg);\r\n                _a.label = 1;\r\n            case 1:\r\n                if (!isSpeaking) return [3 /*break*/, 3];\r\n                return [4 /*yield*/, util_1.sleep(50)];\r\n            case 2:\r\n                _a.sent();\r\n                return [3 /*break*/, 1];\r\n            case 3: return [2 /*return*/];\r\n        }\r\n    });\r\n}); };\r\nelectron_1.ipcMain.on(const_1.electronEvent['speaking-end'], function (event) { return (isSpeaking = false); });\r\nvar isPlayingSe = false;\r\nvar playSe = function () { return __awaiter(void 0, void 0, void 0, function () {\r\n    var wavfilepath;\r\n    return __generator(this, function (_a) {\r\n        switch (_a.label) {\r\n            case 0:\r\n                wavfilepath = globalThis.electron.seList[Math.floor(Math.random() * globalThis.electron.seList.length)];\r\n                isPlayingSe = true;\r\n                globalThis.electron.mainWindow.webContents.send(const_1.electronEvent['play-sound-start'], { wavfilepath: wavfilepath, volume: globalThis.config.playSeVolume });\r\n                _a.label = 1;\r\n            case 1:\r\n                if (!isPlayingSe) return [3 /*break*/, 3];\r\n                return [4 /*yield*/, util_1.sleep(50)];\r\n            case 2:\r\n                _a.sent();\r\n                return [3 /*break*/, 1];\r\n            case 3: return [2 /*return*/];\r\n        }\r\n    });\r\n}); };\r\nelectron_1.ipcMain.on(const_1.electronEvent['play-sound-end'], function (event) { return (isPlayingSe = false); });\r\nexports.createDom = function (message, type) {\r\n    var domStr = \"<li class=\\\"list-item\\\">\";\r\n    /** レス番とかの行が何かしら表示対象になっているか */\r\n    var isResNameShowed = false;\r\n    // アイコン表示\r\n    if (globalThis.config.showIcon) {\r\n        domStr += \"\\n    <span class=\\\"icon-block\\\">\\n      <img class=\\\"icon\\\" src=\\\"\" + message.imgUrl + \"\\\">\\n    </span>\\n    \";\r\n        isResNameShowed = true;\r\n    }\r\n    domStr += \"<div class=\\\"content\\\">\";\r\n    // レス番表示\r\n    if (globalThis.config.showNumber && message.number) {\r\n        domStr += \"\\n      <span class=\\\"resNumber\\\">\" + message.number + \"</span>\\n    \";\r\n        isResNameShowed = true;\r\n    }\r\n    // 名前表示\r\n    if (globalThis.config.showName && message.name) {\r\n        domStr += \"<span class=\\\"name\\\">\" + message.name + \"</span>\";\r\n        isResNameShowed = true;\r\n    }\r\n    // 時刻表示\r\n    if (globalThis.config.showTime && message.date) {\r\n        domStr += \"<span class=\\\"date\\\">\" + message.date + \"</span>\";\r\n        isResNameShowed = true;\r\n    }\r\n    // 名前と本文を改行で分ける\r\n    // 名前や時刻の行が一つも無ければ、改行しない\r\n    if (globalThis.config.newLine && isResNameShowed) {\r\n        domStr += '<br />';\r\n    }\r\n    // リンクを整形する\r\n    var text = message.text\r\n        .replace(/<a .*?>/g, '') // したらばはアンカーをaタグ化している\r\n        .replace(/<\\\\a>/g, '');\r\n    var reg = new RegExp(\"(h?ttps?(://[-_.!~*'()a-zA-Z0-9;/?:@&=+$,%#]+))\", 'g');\r\n    var commentText = text.replace(reg, '<span class=\"url\" onClick=\\'urlopen(\"$1\")\\'>$1</span>');\r\n    domStr += \"\\n    <span class=\\\"res\\\">\\n      \" + commentText + \"\\n    </span>\\n  \";\r\n    // サムネイル表示\r\n    var isThumbnailShow = (globalThis.config.thumbnail == 1 && type === 'chat') || globalThis.config.thumbnail == 2;\r\n    if (isThumbnailShow) {\r\n        var imgreg = new RegExp(\"(h?ttps?(://[-_.!~*'()a-zA-Z0-9;/?:@&=+$,%#]+)(.jpg|.png|.gif))\", 'g');\r\n        var imgUrls_1 = [];\r\n        var matched = text.match(imgreg);\r\n        if (matched) {\r\n            matched.map(function (value) {\r\n                // log.info(value);\r\n                imgUrls_1.push(value);\r\n            });\r\n        }\r\n        if (imgUrls_1.length > 0) {\r\n            domStr += '<div class=\"thumbnail\">';\r\n            domStr += imgUrls_1\r\n                .map(function (url) {\r\n                var tmp = url;\r\n                if (tmp.match(/^ttp/)) {\r\n                    tmp = \"h\" + tmp;\r\n                }\r\n                return \"<img class=\\\"img\\\" src=\\\"\" + tmp + \"\\\" />\";\r\n            })\r\n                .join('');\r\n            domStr += '</div>';\r\n        }\r\n    }\r\n    // 〆\r\n    domStr += \"</div>\\n  </li>\";\r\n    return domStr;\r\n};\r\n/**\r\n * コメントのDOMをブラウザに送る\r\n * 必要ならレス着信音も鳴らす\r\n * @param message\r\n */\r\nvar sendDom = function (messageList) { return __awaiter(void 0, void 0, void 0, function () {\r\n    var domStr, socketObject_1, text, MIN_DISP_TIME, e_2;\r\n    return __generator(this, function (_a) {\r\n        switch (_a.label) {\r\n            case 0:\r\n                _a.trys.push([0, 7, , 8]);\r\n                domStr = messageList.map(function (message) { return exports.createDom(message, 'server'); }).join('\\n');\r\n                socketObject_1 = {\r\n                    type: 'add',\r\n                    message: domStr,\r\n                };\r\n                aWss.clients.forEach(function (client) {\r\n                    client.send(JSON.stringify(socketObject_1));\r\n                });\r\n                // レンダラーのコメント一覧にも表示\r\n                sendDomForChatWindow(messageList);\r\n                if (!(config.playSe && globalThis.electron.seList.length > 0)) return [3 /*break*/, 2];\r\n                return [4 /*yield*/, playSe()];\r\n            case 1:\r\n                _a.sent();\r\n                _a.label = 2;\r\n            case 2:\r\n                if (!(globalThis.config.typeYomiko !== 'none')) return [3 /*break*/, 4];\r\n                text = messageList[messageList.length - 1].text.replace(/<br> /g, '\\n ').replace(/<br>/g, '\\n ');\r\n                text = text.replace(/<img.*?\\/>/g, '');\r\n                text = text.replace(/<a .*?>/g, '').replace(/<\\/a>/g, '');\r\n                text = util_1.unescapeHtml(text);\r\n                return [4 /*yield*/, playYomiko(text)];\r\n            case 3:\r\n                _a.sent();\r\n                _a.label = 4;\r\n            case 4:\r\n                if (!(globalThis.config.dispType === 1)) return [3 /*break*/, 6];\r\n                MIN_DISP_TIME = 2.5 * 1000;\r\n                return [4 /*yield*/, util_1.sleep(MIN_DISP_TIME)];\r\n            case 5:\r\n                _a.sent();\r\n                _a.label = 6;\r\n            case 6:\r\n                // 鳴らし終わって読み子が終わった\r\n                resetInitMessage();\r\n                return [3 /*break*/, 8];\r\n            case 7:\r\n                e_2 = _a.sent();\r\n                electron_log_1.default.error(e_2);\r\n                return [3 /*break*/, 8];\r\n            case 8: return [2 /*return*/];\r\n        }\r\n    });\r\n}); };\r\n/** チャットウィンドウへのコメント表示 */\r\nvar sendDomForChatWindow = function (messageList) {\r\n    var domStr2 = messageList\r\n        .map(function (message) {\r\n        var imgUrl = message.imgUrl && message.imgUrl.match(/^\\./) ? '../../public/' + message.imgUrl : message.imgUrl;\r\n        return __assign(__assign({}, message), { imgUrl: imgUrl });\r\n    })\r\n        .map(function (message) { return exports.createDom(message, 'chat'); })\r\n        .join('\\n');\r\n    globalThis.electron.chatWindow.webContents.send(const_1.electronEvent['show-comment'], { config: globalThis.config, dom: domStr2 });\r\n};\r\nvar resetInitMessage = function () {\r\n    if (globalThis.config.dispType === 1) {\r\n        var resetObj_1 = {\r\n            type: 'reset',\r\n            message: globalThis.config.initMessage,\r\n        };\r\n        aWss.clients.forEach(function (client) {\r\n            client.send(JSON.stringify(resetObj_1));\r\n        });\r\n    }\r\n};\r\nexports.default = {};\r\n","\"use strict\";\r\nvar __importDefault = (this && this.__importDefault) || function (mod) {\r\n    return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar fs_1 = __importDefault(require(\"fs\"));\r\nexports.readWavFiles = function (path) {\r\n    return new Promise(function (resolve, reject) {\r\n        fs_1.default.readdir(path, function (err, files) {\r\n            if (err)\r\n                reject(err);\r\n            var fileList = files.filter(function (file) {\r\n                return isExistFile(path + '/' + file) && /.*\\.wav$/.test(file); //絞り込み\r\n            });\r\n            resolve(fileList);\r\n        });\r\n    });\r\n};\r\nvar isExistFile = function (file) {\r\n    try {\r\n        fs_1.default.statSync(file).isFile();\r\n        return true;\r\n    }\r\n    catch (err) {\r\n        if (err.code === 'ENOENT')\r\n            return false;\r\n    }\r\n};\r\nexports.sleep = function (msec) { return new Promise(function (resolve) { return setTimeout(resolve, msec); }); };\r\nexports.escapeHtml = function (string) {\r\n    if (typeof string !== 'string') {\r\n        return string;\r\n    }\r\n    return string.replace(/[&'`\"<>]/g, function (match) {\r\n        return {\r\n            '&': '&amp;',\r\n            \"'\": '&#x27;',\r\n            '`': '&#x60;',\r\n            '\"': '&quot;',\r\n            '<': '&lt;',\r\n            '>': '&gt;',\r\n        }[match];\r\n    });\r\n};\r\nexports.unescapeHtml = function (str) {\r\n    return str\r\n        .replace(/&lt;/g, '<')\r\n        .replace(/&gt;/g, '>')\r\n        .replace(/&quot;/g, '\"')\r\n        .replace(/&#039;/g, \"'\")\r\n        .replace(/&#044;/g, ',')\r\n        .replace(/&amp;/g, '&');\r\n};\r\n","\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar live_chat_1 = require(\"./live-chat\");\r\nexports.LiveChat = live_chat_1.LiveChat;\r\n","\"use strict\";\r\nvar __extends = (this && this.__extends) || (function () {\r\n    var extendStatics = function (d, b) {\r\n        extendStatics = Object.setPrototypeOf ||\r\n            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };\r\n        return extendStatics(d, b);\r\n    };\r\n    return function (d, b) {\r\n        extendStatics(d, b);\r\n        function __() { this.constructor = d; }\r\n        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n    };\r\n})();\r\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\r\n    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n    return new (P || (P = Promise))(function (resolve, reject) {\r\n        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n        function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n        step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n    });\r\n};\r\nvar __generator = (this && this.__generator) || function (thisArg, body) {\r\n    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n    return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n    function verb(n) { return function (v) { return step([n, v]); }; }\r\n    function step(op) {\r\n        if (f) throw new TypeError(\"Generator is already executing.\");\r\n        while (_) try {\r\n            if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n            if (y = 0, t) op = [op[0] & 2, t.value];\r\n            switch (op[0]) {\r\n                case 0: case 1: t = op; break;\r\n                case 4: _.label++; return { value: op[1], done: false };\r\n                case 5: _.label++; y = op[1]; op = [0]; continue;\r\n                case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n                default:\r\n                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n                    if (t[2]) _.ops.pop();\r\n                    _.trys.pop(); continue;\r\n            }\r\n            op = body.call(thisArg, _);\r\n        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n    }\r\n};\r\nvar __importDefault = (this && this.__importDefault) || function (mod) {\r\n    return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar events_1 = require(\"events\");\r\nvar axios_1 = __importDefault(require(\"axios\"));\r\nvar parser_1 = require(\"./parser\");\r\nvar util_1 = require(\"../util\");\r\n/**\r\n * YouTubeライブチャット取得イベント\r\n */\r\nvar LiveChat = /** @class */ (function (_super) {\r\n    __extends(LiveChat, _super);\r\n    function LiveChat(options, interval) {\r\n        if (interval === void 0) { interval = 1000; }\r\n        var _this = _super.call(this) || this;\r\n        _this.interval = interval;\r\n        _this.prevTime = Date.now();\r\n        _this.isStop = false;\r\n        if ('channelId' in options) {\r\n            _this.channelId = options.channelId;\r\n        }\r\n        else if ('liveId' in options) {\r\n            _this.liveId = options.liveId;\r\n        }\r\n        else {\r\n            throw TypeError('Required channelId or liveId.');\r\n        }\r\n        return _this;\r\n    }\r\n    LiveChat.prototype.start = function () {\r\n        this.isStop = false;\r\n        this.fetchLiveId();\r\n    };\r\n    LiveChat.prototype.fetchLiveId = function () {\r\n        var _a;\r\n        return __awaiter(this, void 0, void 0, function () {\r\n            var url, liveRes, e_1;\r\n            var _this = this;\r\n            return __generator(this, function (_b) {\r\n                switch (_b.label) {\r\n                    case 0:\r\n                        if (this.isStop)\r\n                            return [2 /*return*/];\r\n                        if (!this.channelId) return [3 /*break*/, 4];\r\n                        url = \"https://www.youtube.com/channel/\" + this.channelId + \"/live\";\r\n                        _b.label = 1;\r\n                    case 1:\r\n                        _b.trys.push([1, 3, , 4]);\r\n                        return [4 /*yield*/, axios_1.default.get(url, { headers: LiveChat.headers })];\r\n                    case 2:\r\n                        liveRes = _b.sent();\r\n                        //   if (liveRes.data.match(/LIVE_STREAM_OFFLINE/)) {\r\n                        //     this.emit('error', new Error('Live stream offline'));\r\n                        //     return false;\r\n                        //   }\r\n                        this.liveId = (_a = liveRes.data.match(/videoId\\\\\":\\\\\"(.+?)\\\\/)) === null || _a === void 0 ? void 0 : _a[1];\r\n                        return [3 /*break*/, 4];\r\n                    case 3:\r\n                        e_1 = _b.sent();\r\n                        // チャンネルID自体が違うのはもうどうしようもないので止める\r\n                        this.emit('error', new Error(\"connection error url = \" + url));\r\n                        return [2 /*return*/];\r\n                    case 4:\r\n                        if (!this.liveId) return [3 /*break*/, 5];\r\n                        this.observer = setInterval(function () { return _this.fetchChat(); }, this.interval);\r\n                        this.emit('start', this.liveId);\r\n                        return [3 /*break*/, 7];\r\n                    case 5:\r\n                        // 配信が開始してないパターンが考えられるのでリトライ\r\n                        this.emit('error', new Error('Live stream not found'));\r\n                        return [4 /*yield*/, util_1.sleep(2000)];\r\n                    case 6:\r\n                        _b.sent();\r\n                        this.fetchLiveId();\r\n                        _b.label = 7;\r\n                    case 7: return [2 /*return*/];\r\n                }\r\n            });\r\n        });\r\n    };\r\n    LiveChat.prototype.stop = function (reason) {\r\n        this.isStop = true;\r\n        if (this.observer) {\r\n            clearInterval(this.observer);\r\n            this.emit('end', reason);\r\n        }\r\n    };\r\n    LiveChat.prototype.fetchChat = function () {\r\n        return __awaiter(this, void 0, void 0, function () {\r\n            var url, res, items, item, e_2;\r\n            var _this = this;\r\n            return __generator(this, function (_a) {\r\n                switch (_a.label) {\r\n                    case 0:\r\n                        url = \"https://www.youtube.com/live_chat?v=\" + this.liveId + \"&pbj=1\";\r\n                        _a.label = 1;\r\n                    case 1:\r\n                        _a.trys.push([1, 3, , 4]);\r\n                        return [4 /*yield*/, axios_1.default.get(url, { headers: LiveChat.headers })];\r\n                    case 2:\r\n                        res = _a.sent();\r\n                        items = res.data[1].response.contents.liveChatRenderer.actions\r\n                            .slice(0, -1)\r\n                            .filter(function (v) {\r\n                            var messageRenderer = parser_1.actionToRenderer(v);\r\n                            if (messageRenderer !== null) {\r\n                                if (messageRenderer) {\r\n                                    return parser_1.usecToTime(messageRenderer.timestampUsec) > _this.prevTime;\r\n                                }\r\n                            }\r\n                            return false;\r\n                        })\r\n                            .map(function (v) { return parser_1.parseData(v); });\r\n                        items.forEach(function (v) {\r\n                            if (v) {\r\n                                _this.emit('comment', v);\r\n                            }\r\n                        });\r\n                        if (items.length > 0) {\r\n                            console.log(\"[Youtube-chat] items = \" + items.length);\r\n                            item = items[items.length - 1];\r\n                            if (item)\r\n                                this.prevTime = item.timestamp;\r\n                        }\r\n                        return [3 /*break*/, 4];\r\n                    case 3:\r\n                        e_2 = _a.sent();\r\n                        this.emit('error', new Error(\"Error occured at fetchchat url=\" + url));\r\n                        return [3 /*break*/, 4];\r\n                    case 4: return [2 /*return*/];\r\n                }\r\n            });\r\n        });\r\n    };\r\n    LiveChat.prototype.on = function (event, listener) {\r\n        return _super.prototype.on.call(this, event, listener);\r\n    };\r\n    LiveChat.headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36' };\r\n    return LiveChat;\r\n}(events_1.EventEmitter));\r\nexports.LiveChat = LiveChat;\r\n","\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar parseThumbnailToImageItem = function (data, alt) {\r\n    var thumbnail = data.pop();\r\n    if (thumbnail) {\r\n        return {\r\n            url: thumbnail.url,\r\n            width: thumbnail.width,\r\n            height: thumbnail.height,\r\n            alt: alt,\r\n        };\r\n    }\r\n    return;\r\n};\r\nvar parseEmojiToImageItem = function (data) {\r\n    return parseThumbnailToImageItem(data.emoji.image.thumbnails, data.emoji.shortcuts.shift());\r\n};\r\nvar parseMessages = function (runs) {\r\n    return runs.map(function (run) {\r\n        var _a;\r\n        if ('text' in run) {\r\n            if ((_a = run === null || run === void 0 ? void 0 : run.navigationEndpoint) === null || _a === void 0 ? void 0 : _a.urlEndpoint.url) {\r\n                var tubeUrl = run.navigationEndpoint.urlEndpoint.url.replace(/^\\/redirect\\?/, '');\r\n                // console.log(tubeUrl);\r\n                var parsed = tubeUrl.split('&').filter(function (str) { return str.match(/^q=/); });\r\n                var orgUrl = decodeURIComponent(parsed[0].replace(/^q=/, ''));\r\n                // console.log(orgUrl);\r\n                return { text: orgUrl };\r\n            }\r\n            else {\r\n                return run;\r\n            }\r\n        }\r\n        else {\r\n            // 絵文字を画像に置換\r\n            return parseEmojiToImageItem(run);\r\n        }\r\n    });\r\n};\r\nexports.actionToRenderer = function (action) {\r\n    if (!action.addChatItemAction) {\r\n        return null;\r\n    }\r\n    var item = action.addChatItemAction.item;\r\n    if (item.liveChatTextMessageRenderer) {\r\n        return item.liveChatTextMessageRenderer;\r\n    }\r\n    else if (item.liveChatPaidMessageRenderer) {\r\n        return item.liveChatPaidMessageRenderer;\r\n    }\r\n    else if (item.liveChatPaidStickerRenderer) {\r\n        return item.liveChatPaidStickerRenderer;\r\n    }\r\n    else {\r\n        return item.liveChatMembershipItemRenderer;\r\n    }\r\n};\r\nexports.usecToTime = function (usec) {\r\n    return Math.floor(Number(usec) / 1000);\r\n};\r\nexports.parseData = function (data) {\r\n    var messageRenderer = exports.actionToRenderer(data);\r\n    if (messageRenderer === null) {\r\n        return null;\r\n    }\r\n    var message = [];\r\n    if ('message' in messageRenderer) {\r\n        message = messageRenderer.message.runs;\r\n    }\r\n    else if ('headerSubtext' in messageRenderer) {\r\n        message = messageRenderer.headerSubtext.runs;\r\n    }\r\n    var ret = {\r\n        id: messageRenderer.id,\r\n        author: {\r\n            name: messageRenderer.authorName.simpleText,\r\n            thumbnail: parseThumbnailToImageItem(messageRenderer.authorPhoto.thumbnails, messageRenderer.authorName.simpleText),\r\n            channelId: messageRenderer.authorExternalChannelId,\r\n        },\r\n        message: parseMessages(message),\r\n        membership: Boolean('headerSubtext' in messageRenderer),\r\n        isOwner: false,\r\n        timestamp: exports.usecToTime(messageRenderer.timestampUsec),\r\n    };\r\n    if (messageRenderer.authorBadges) {\r\n        var badge = messageRenderer.authorBadges[0].liveChatAuthorBadgeRenderer;\r\n        if (badge.customThumbnail) {\r\n            ret.author.badge = {\r\n                thumbnail: parseThumbnailToImageItem(badge.customThumbnail.thumbnails, badge.tooltip),\r\n                label: badge.tooltip,\r\n            };\r\n        }\r\n        else {\r\n            ret.isOwner = true;\r\n        }\r\n    }\r\n    if ('sticker' in messageRenderer) {\r\n        ret.superchat = {\r\n            amount: messageRenderer.purchaseAmountText.simpleText,\r\n            color: messageRenderer.backgroundColor,\r\n            sticker: parseThumbnailToImageItem(messageRenderer.sticker.thumbnails, messageRenderer.sticker.accessibility.accessibilityData.label),\r\n        };\r\n    }\r\n    else if ('purchaseAmountText' in messageRenderer) {\r\n        ret.superchat = {\r\n            amount: messageRenderer.purchaseAmountText.simpleText,\r\n            color: messageRenderer.bodyBackgroundColor,\r\n        };\r\n    }\r\n    return ret;\r\n};\r\n"],"mappings":";AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;AClFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;AClFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;AC1EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;AC1BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;ACrJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;AC5PA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;ACnSA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;ACpQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;ACxJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;ACpuBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;ACpDA;AACA;AACA;AACA;;;;;;;;;;;;;ACHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;AC/LA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;A","sourceRoot":""}
\ No newline at end of file
diff --git a/package.json b/package.json
index 42a8f02..66051d0 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "unacast",
-  "version": "0.6.1",
+  "version": "0.6.2",
   "description": "掲示板のレスをYoutubeコメント風に表示したいという思想の元に開発されるツール",
   "main": "dist/index.js",
   "scripts": {
diff --git a/src/main/main.ts b/src/main/main.ts
index b68342b..a4d9916 100644
--- a/src/main/main.ts
+++ b/src/main/main.ts
@@ -1,6 +1,6 @@
 // Electronのモジュール
 import path from 'path';
-import electron, { Tray, Menu, dialog } from 'electron';
+import electron, { Tray, Menu, dialog, MenuItem } from 'electron';
 import log from 'electron-log';
 import { sleep } from './util';
 import windowStateKeeper from 'electron-window-state';
@@ -54,6 +54,31 @@ if (!app.requestSingleInstanceLock()) {
   //   }
   // });
 
+  // 右クリックメニュー
+  const mainContextMenu = new Menu();
+  mainContextMenu.append(
+    new MenuItem({
+      label: '最前面表示',
+      type: 'checkbox',
+      checked: false,
+      click: (e) => {
+        globalThis.electron.mainWindow.setAlwaysOnTop(e.checked);
+      },
+    }),
+  );
+
+  const chatContextMenu = new Menu();
+  chatContextMenu.append(
+    new MenuItem({
+      label: '最前面表示',
+      type: 'checkbox',
+      checked: false,
+      click: (e) => {
+        globalThis.electron.chatWindow.setAlwaysOnTop(e.checked);
+      },
+    }),
+  );
+
   // Electronの初期化完了後に実行
   app.on('ready', () => {
     const windowState = windowStateKeeper({
@@ -152,6 +177,14 @@ if (!app.requestSingleInstanceLock()) {
     });
 
     createChatWindow();
+
+    // 右クリックメニュー開く
+    globalThis.electron.mainWindow.webContents.on('context-menu', (e, params) => {
+      mainContextMenu.popup({ window: globalThis.electron.mainWindow, x: params.x, y: params.y });
+    });
+    globalThis.electron.chatWindow.webContents.on('context-menu', (e, params) => {
+      chatContextMenu.popup({ window: globalThis.electron.chatWindow, x: params.x, y: params.y });
+    });
   });
 
   // 音声再生できるようにする