diff --git a/package-lock.json b/package-lock.json index e8c6c7ab..893fa236 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1349,6 +1349,16 @@ } } }, + "@dabh/diagnostics": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", + "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==", + "requires": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "@develar/schema-utils": { "version": "2.6.5", "resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz", @@ -5157,7 +5167,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "requires": { "color-name": "1.1.3" } @@ -5165,14 +5174,12 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "color-string": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.5.tgz", "integrity": "sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg==", - "dev": true, "requires": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" @@ -5190,6 +5197,26 @@ "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", "dev": true }, + "colorspace": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", + "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", + "requires": { + "color": "3.0.x", + "text-hex": "1.0.x" + }, + "dependencies": { + "color": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", + "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" + } + } + } + }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -7122,6 +7149,11 @@ "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", "dev": true }, + "enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -7939,6 +7971,11 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" }, + "fast-safe-stringify": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", + "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" + }, "faye-websocket": { "version": "0.11.3", "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz", @@ -7956,6 +7993,11 @@ "pend": "~1.2.0" } }, + "fecha": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz", + "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==" + }, "ffi-napi": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/ffi-napi/-/ffi-napi-4.0.1.tgz", @@ -8162,6 +8204,11 @@ "readable-stream": "^2.3.6" } }, + "fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, "follow-redirects": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.2.tgz", @@ -10200,6 +10247,11 @@ "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.4.tgz", "integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==" }, + "kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "latest-version": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", @@ -10450,6 +10502,25 @@ "chalk": "^2.0.1" } }, + "logform": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.2.0.tgz", + "integrity": "sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg==", + "requires": { + "colors": "^1.2.1", + "fast-safe-stringify": "^2.0.4", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "triple-beam": "^1.3.0" + }, + "dependencies": { + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" + } + } + }, "loglevel": { "version": "1.7.1", "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz", @@ -14018,7 +14089,6 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", - "dev": true, "requires": { "is-arrayish": "^0.3.1" }, @@ -14026,8 +14096,7 @@ "is-arrayish": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", - "dev": true + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" } } }, @@ -14429,6 +14498,11 @@ "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", "dev": true }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" + }, "stackframe": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz", @@ -14906,6 +14980,11 @@ } } }, + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -15110,6 +15189,11 @@ "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=" }, + "triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, "truncate-utf8-bytes": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", @@ -17588,6 +17672,61 @@ "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz", "integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=" }, + "winston": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", + "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==", + "requires": { + "@dabh/diagnostics": "^2.0.2", + "async": "^3.1.0", + "is-stream": "^2.0.0", + "logform": "^2.2.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.4.0" + }, + "dependencies": { + "async": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", + "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" + }, + "one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "requires": { + "fn.name": "1.x.x" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "winston-transport": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz", + "integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==", + "requires": { + "readable-stream": "^2.3.7", + "triple-beam": "^1.2.0" + } + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", diff --git a/package.json b/package.json index 2d862c30..ec0ad9a8 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "castmate", "version": "0.0.3", "private": "true", - "description": "", + "description": "CastMate is a broadcaster tool that allows Twitch viewers to interact with a broadcasters stream components through Chat Commands, Channel Point rewards, and more.", "author": "LordTocs & FitzBro", "scripts": { "serve": "vue-cli-service serve", @@ -52,6 +52,7 @@ "vuex": "^3.6.2", "websocket": "^1.0.33", "win32-api": "^9.6.0", + "winston": "^3.3.3", "yaml": "^1.10.0" }, "devDependencies": { diff --git a/src/App.vue b/src/App.vue index cc6d619e..f5c7429a 100644 --- a/src/App.vue +++ b/src/App.vue @@ -40,6 +40,16 @@ + + + mdi-folder-music + + + + Open Sounds Folder + + + Plugins @@ -65,14 +75,18 @@ - - Loading CastMate - + + Loading CastMate + @@ -87,6 +101,8 @@ + + \ No newline at end of file diff --git a/src/components/commands/CommandEditor.vue b/src/components/commands/CommandEditor.vue new file mode 100644 index 00000000..f4aa10b4 --- /dev/null +++ b/src/components/commands/CommandEditor.vue @@ -0,0 +1,58 @@ + + + + + + + + Synchronous + + + Synchronous sequences wait for other synchronous sequences to + finish before playing. + + + + + + + mdi-play + + + + + + + + Delete + + + + + + + \ No newline at end of file diff --git a/src/components/data/DataView.vue b/src/components/data/DataView.vue index 323c7d9e..7aa5e305 100644 --- a/src/components/data/DataView.vue +++ b/src/components/data/DataView.vue @@ -32,6 +32,7 @@ export default { props: { schema: {}, value: {}, + label: {} }, }; diff --git a/src/components/data/ObjectEditor.vue b/src/components/data/ObjectEditor.vue index 33f4230f..3f5ad16e 100644 --- a/src/components/data/ObjectEditor.vue +++ b/src/components/data/ObjectEditor.vue @@ -28,7 +28,6 @@ export default { let newValue = this.value ? { ...this.value } : {}; if (value != "" && value != undefined) { - console.log("Update Obj", key, value); newValue[key] = value; } else { delete newValue[key]; diff --git a/src/components/dialogs/NamedItemModal.vue b/src/components/dialogs/NamedItemModal.vue new file mode 100644 index 00000000..8df34640 --- /dev/null +++ b/src/components/dialogs/NamedItemModal.vue @@ -0,0 +1,68 @@ + + + + + + {{ header }} + + + + + + + + + + Cancel + + + Create + + + + + + + + + + \ No newline at end of file diff --git a/src/components/profiles/CommandEditor.vue b/src/components/profiles/CommandEditor.vue deleted file mode 100644 index b9a88dd6..00000000 --- a/src/components/profiles/CommandEditor.vue +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - Add Import - - Delete - - - - - - - \ No newline at end of file diff --git a/src/components/profiles/NewProfileModal.vue b/src/components/profiles/NewProfileModal.vue deleted file mode 100644 index 1a22e52e..00000000 --- a/src/components/profiles/NewProfileModal.vue +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - Create New Profile - - - - - - - - - Cancel - - - Create - - - - - - - - - \ No newline at end of file diff --git a/src/components/profiles/RewardsEditor.vue b/src/components/profiles/RewardsEditor.vue index b1969a2e..542b35ed 100644 --- a/src/components/profiles/RewardsEditor.vue +++ b/src/components/profiles/RewardsEditor.vue @@ -34,7 +34,7 @@ import { mapGetters } from "vuex"; //import RewardSelector from "@/components/data/RewardSelector.vue"; import RewardCard from "../rewards/RewardCard.vue"; -import AddRewardPopover from "./AddRewardPopover.vue"; +import AddRewardPopover from "../rewards/AddRewardPopover.vue"; export default { components: { RewardCard, diff --git a/src/components/profiles/TriggerEditor.vue b/src/components/profiles/TriggerEditor.vue deleted file mode 100644 index c5b1bf25..00000000 --- a/src/components/profiles/TriggerEditor.vue +++ /dev/null @@ -1,189 +0,0 @@ - - - - {{ triggerName }} - - - - updateCommand(commandKey, newData)" - @delete="deleteCommand(commandKey)" - @key-change="(v) => changeKey(commandKey, v)" - /> - - - - - - Imports - - - - - changeImport(i, v)" - /> - - - - Delete - - - - - - - - - - - Add Command - Import Triggers - - - - - {{ triggerName }} - - $emit('input', v)" /> - - - - - - - - updateCommand(commandKey, newData)" - @delete="deleteCommand(commandKey)" - @key-change="(v) => changeKey(commandKey, v)" - /> - - - - - - Add Command - - - - - - - \ No newline at end of file diff --git a/src/components/profiles/TriggersEditor.vue b/src/components/profiles/TriggersEditor.vue index c5ff78f6..e2e66176 100644 --- a/src/components/profiles/TriggersEditor.vue +++ b/src/components/profiles/TriggersEditor.vue @@ -14,7 +14,7 @@ diff --git a/src/components/profiles/ActionListItem.vue b/src/components/sequences/SequenceItem.vue similarity index 58% rename from src/components/profiles/ActionListItem.vue rename to src/components/sequences/SequenceItem.vue index 59449221..d9f22407 100644 --- a/src/components/profiles/ActionListItem.vue +++ b/src/components/sequences/SequenceItem.vue @@ -2,31 +2,29 @@ - {{ firstAction.name }} + {{ actionDefinition.name }} - - Import - + Import updateAction(firstActionKey, v)" + :actionKey="actionKey" + :value="actionData" + @input="(v) => updateAction(actionKey, v)" /> @@ -41,7 +39,7 @@ \ No newline at end of file diff --git a/src/components/triggers/SingleCommandTrigger.vue b/src/components/triggers/SingleCommandTrigger.vue new file mode 100644 index 00000000..06e91236 --- /dev/null +++ b/src/components/triggers/SingleCommandTrigger.vue @@ -0,0 +1,35 @@ + + + + {{ triggerName }} + + $emit('input', v)" /> + + + + + + + + \ No newline at end of file diff --git a/src/components/triggers/TriggerEditor.vue b/src/components/triggers/TriggerEditor.vue new file mode 100644 index 00000000..41d3ab5b --- /dev/null +++ b/src/components/triggers/TriggerEditor.vue @@ -0,0 +1,51 @@ + + $emit('input', v)" + /> + $emit('input', v)" + /> + + + + + \ No newline at end of file diff --git a/src/components/triggers/TriggerImports.vue b/src/components/triggers/TriggerImports.vue new file mode 100644 index 00000000..ec2089e8 --- /dev/null +++ b/src/components/triggers/TriggerImports.vue @@ -0,0 +1,46 @@ + + + Imports + + + + + changeImport(i, v)" /> + + + Delete + + + + + + + + + + \ No newline at end of file diff --git a/src/core/actions/action-queue.js b/src/core/actions/action-queue.js index 524d94d4..e5ae739a 100644 --- a/src/core/actions/action-queue.js +++ b/src/core/actions/action-queue.js @@ -1,6 +1,10 @@ const { sleep } = require("../utils/sleep.js"); const { Mutex } = require("async-mutex"); const { reactiveCopy } = require("../utils/reactive.js"); +const logger = require('../utils/logger'); +const { ipcMain } = require("electron"); +const { loadActionable } = require('./profiles'); + function isActionable(actionable) { @@ -52,6 +56,25 @@ class ActionQueue } this.plugins = plugins; + + ipcMain.handle('pushToQueue', async (event, actions) => + { + const dummySet = new Set(); + + const actionable = { actions, sync: false } + + loadActionable(actionable, dummySet) + + this.convertOffsets(actionable.actions); + + console.log(actionable); + this.pushToQueue(actionable, { + user: "Test User", + userColor: "#4411FF", + message: "Test Message From User", + filteredMessage: "Test Message From User", + }) + }) } setTriggers(triggers) @@ -136,7 +159,7 @@ class ActionQueue if ("number" in options) { - console.log(`Fired ${name} : ${options.number}`) + logger.info(`Fired ${name} : ${options.number}`) //Handle a numberlike event action let selected = null; for (let key in event) @@ -159,7 +182,7 @@ class ActionQueue } else if ("name" in options) { - console.log(`Fired ${name} : ${options.name}`) + logger.info(`Fired ${name} : ${options.name}`) //Handle a namelike event let namedEvent = event[options.name]; if (namedEvent && isActionable(namedEvent)) @@ -170,7 +193,7 @@ class ActionQueue } if (isActionable(event)) { - console.log(`Fired ${name}`) + logger.info(`Fired ${name}`) this.pushToQueue(event, options); return true; } @@ -237,7 +260,7 @@ class ActionQueue if (this.queue.length == 0) return; - console.log("Starting new chain"); + logger.info("Starting new synchronous chain"); let release = await this.queueMutex.acquire(); let front = this.queue.shift(); let frontPromise = this._runAction(front.action, front.context); diff --git a/src/core/actions/profile-manager.js b/src/core/actions/profile-manager.js index 2b4a6ce5..16d2b554 100644 --- a/src/core/actions/profile-manager.js +++ b/src/core/actions/profile-manager.js @@ -6,6 +6,7 @@ const chokidar = require("chokidar"); const { sleep } = require("../utils/sleep"); const path = require('path'); const { userFolder } = require("../utils/configuration"); +const logger = require("../utils/logger"); class ProfileManager { @@ -23,18 +24,18 @@ class ProfileManager async load() { this.profileWatcher = chokidar.watch(path.join(userFolder, 'profiles/')); - this.triggersWatcher = chokidar.watch(path.join(userFolder, 'triggers/')); + this.commandsWatcher = chokidar.watch(path.join(userFolder, 'commands/')); this.sequencesWatcher = chokidar.watch(path.join(userFolder, 'sequences/')); this.profileWatcher.on('add', async (path) => { - console.log("Profile Added: ", path); + logger.info(`Profile Added: ${path}`); await sleep(50); this.loadProfile(path); }); this.profileWatcher.on('change', async (path) => { - console.log("Profile Changed: ", path); + logger.info(`Profile Changed: ${path}`); let profile = this.profiles.find((p) => p.filename == path); if (!profile) return; @@ -49,7 +50,7 @@ class ProfileManager if (i == -1) return; - console.log("Profile Deleted: ", path); + logger.info(`Profile Deleted: ${path}`); this.profiles[i].watcher.unsubscribe(); @@ -58,9 +59,9 @@ class ProfileManager this.recombine(); }); - this.triggersWatcher.on('change', async (path) => + this.commandsWatcher.on('change', async (path) => { - console.log("Triggers Changed: ", path); + logger.info(`Commands Changed: ${path}`); await sleep(50); for (let profile of this.profiles) { @@ -71,7 +72,7 @@ class ProfileManager this.sequencesWatcher.on('change', async (path) => { await sleep(50); - console.log("Sequence Changed: ", path); + logger.info(`Sequence Changed: ${path}`); for (let profile of this.profiles) { profile.handleFileChanged(path); @@ -132,7 +133,7 @@ class ProfileManager { let [activeProfiles, inactiveProfiles] = _.partition(this.profiles, (profile) => evalConditional(profile.conditions, this.plugins.combinedState)); - console.log("Changing Profiles: ", activeProfiles.map(p => p.filename).join(', ')); + logger.info(`Combining Profiles: ${activeProfiles.map(p => p.filename).join(', ')}`); this.triggers = Profile.mergeTriggers(activeProfiles); diff --git a/src/core/actions/profiles.js b/src/core/actions/profiles.js index ce76a9b0..7b84cb85 100644 --- a/src/core/actions/profiles.js +++ b/src/core/actions/profiles.js @@ -2,10 +2,10 @@ const fs = require("fs"); const YAML = require("yaml"); const path = require("path"); const { userFolder } = require("../utils/configuration"); +const logger = require("../utils/logger"); function loadFile(filename, fileset, root = userFolder) { - //console.log(`Loading ${filename}`); const adjustedFilename = path.join(root, filename); let contents = fs.readFileSync(adjustedFilename, "utf-8"); let pojo = YAML.parse(contents); @@ -27,6 +27,7 @@ function loadActionable(actionable, fileset) let actionsInsert = loadFile(action["import"], fileset); if (!(actionsInsert instanceof Array)) { + logger.error(`Imports in the middle of action arrays must be arrays themselves.`); throw new Error("Imports in the middle of action arrays must be arrays themselves"); } @@ -39,7 +40,7 @@ function loadActionable(actionable, fileset) } catch (err) { - console.log("Unable to load file ", action["import"]); + logger.error(`Unable to load file ${action["import"]}`); throw err; } } @@ -90,7 +91,7 @@ function loadTrigger(triggerObj, fileset) } catch (err) { - console.log("Unable to load file ", filename); + logger.error(`Unable to load file ${filename}`); throw err; } } @@ -117,7 +118,7 @@ class Profile { let fileset = new Set(); - console.log("Loading Profile: ", this.filename); + logger.info(`Loading Profile: ${this.filename}`); let profileConfig = loadFile(this.filename, fileset, "."); if (profileConfig.triggers) @@ -130,10 +131,10 @@ class Profile } catch (err) { - console.log("Unable to load file ", this.filename); + logger.error(`Unable to load file ${this.filename}`); throw err; } - + } } @@ -177,4 +178,4 @@ Profile.mergeTriggers = function (profiles) return combined; } -module.exports = { Profile }; \ No newline at end of file +module.exports = { Profile, loadActionable }; \ No newline at end of file diff --git a/src/core/plugins/aoe3.js b/src/core/plugins/aoe3.js index b6ec0372..063e5a41 100644 --- a/src/core/plugins/aoe3.js +++ b/src/core/plugins/aoe3.js @@ -165,11 +165,10 @@ module.exports = { } data[unitName] = unitData; - console.log(`Scraped ${unitName}`); + this.logger.info(`Scraped ${unitName}`); } } - // console.log(JSON.stringify(data, null, 2)); fs.writeFileSync(path.join(userFolder, 'data/aoe3GameStats.json'), JSON.stringify(data, null, 2)) } else diff --git a/src/core/plugins/inputs.js b/src/core/plugins/inputs.js index c685870f..92c0fd85 100644 --- a/src/core/plugins/inputs.js +++ b/src/core/plugins/inputs.js @@ -115,7 +115,7 @@ module.exports = { let error = kernel32.GetLastError(); if (error) { - console.log("VK Error", error); + this.logger.error(`VK Error ${error}`); } } }, @@ -162,7 +162,7 @@ module.exports = { let error = kernel32.GetLastError(); if (error) { - console.log("VK Error", error); + this.logger.error(`SendInput Error ${error}`); } } } diff --git a/src/core/plugins/kofi.js b/src/core/plugins/kofi.js index fee4de5a..086a16e3 100644 --- a/src/core/plugins/kofi.js +++ b/src/core/plugins/kofi.js @@ -12,8 +12,6 @@ module.exports = { const routes = this.webServices.routes; routes.post(`/kofi`, (req, res) => { - console.log("KOFI!") - console.log(req.body); let data = JSON.parse(req.body.data); if (data.type == "Donation") { diff --git a/src/core/plugins/lights.js b/src/core/plugins/lights.js index ae373b98..77d91806 100644 --- a/src/core/plugins/lights.js +++ b/src/core/plugins/lights.js @@ -169,12 +169,12 @@ module.exports = { } catch (err) { - console.error("The link button on the bridge was not pressed. Press and try again."); + this.logger.error("The link button on the bridge was not pressed. Press and try again."); } if (i != retries - 1) { - console.log("Trying again in 5 seconds..."); + this.logger.info("Trying again in 5 seconds..."); await sleep(5000); } } diff --git a/src/core/plugins/minecraft.js b/src/core/plugins/minecraft.js index f6cc4eb2..87f9d9e4 100644 --- a/src/core/plugins/minecraft.js +++ b/src/core/plugins/minecraft.js @@ -67,9 +67,9 @@ module.exports = { return; } let fullCommand = await template(command, context); - console.log("MCRCON: ", fullCommand); + this.logger.info(`MCRCON Send: ${fullCommand}`); let result = await this.rcon.send(fullCommand); - console.log("MCRCON: ", result); + this.logger.info(`MCRCON Recv: ${result}`); } } } diff --git a/src/core/plugins/obs.js b/src/core/plugins/obs.js index e55e3c41..10f3de90 100644 --- a/src/core/plugins/obs.js +++ b/src/core/plugins/obs.js @@ -15,7 +15,6 @@ module.exports = { }) this.obs.on("ConnectionClosed", () => { - console.log("Failed to connect to OBS...retrying.") setTimeout(() => { this.connectOBS() }, 5000); }); }, @@ -33,7 +32,7 @@ module.exports = { let result = await this.obs.send("GetCurrentScene"); //this.profiles.setCondition("scene", result.name); this.state.obsScene = result.name; - console.log("OBS connected!"); + this.logger.info("OBS connected!"); } catch { return; } @@ -92,7 +91,6 @@ module.exports = { { const sourceName = await template(filterData.sourceName, context); const filterName = await template(filterData.filterName, context); - console.log("Filter: ", sourceName, filterName); await this.obs.send('SetSourceFilterVisibility', { sourceName, diff --git a/src/core/plugins/sounds.js b/src/core/plugins/sounds.js index ec219fd6..defa8245 100644 --- a/src/core/plugins/sounds.js +++ b/src/core/plugins/sounds.js @@ -50,7 +50,7 @@ module.exports = { } else { - console.log("Sound Window Not Available") + this.logger.error("Audio Window Not Available"); } } } diff --git a/src/core/plugins/tts.js b/src/core/plugins/tts.js index 37886d98..72e31b80 100644 --- a/src/core/plugins/tts.js +++ b/src/core/plugins/tts.js @@ -19,7 +19,7 @@ module.exports = { async handler(data, context) { const message = await template(data, context); - console.log("Speaking", message); + this.logger.info(`Speaking: ${message}`); say.speak(message); } } diff --git a/src/core/plugins/twitch.js b/src/core/plugins/twitch.js index b567f45b..942fb3ce 100644 --- a/src/core/plugins/twitch.js +++ b/src/core/plugins/twitch.js @@ -96,7 +96,7 @@ module.exports = { uiName: "Twitch", async init() { - console.log("Starting Twitch"); + this.logger.info("Starting Twitch"); await this.doInitialAuth(); @@ -134,7 +134,6 @@ module.exports = { await this.channelAuth.trySilentAuth(); await this.botAuth.trySilentAuth(); - await this.completeAuth(); }, @@ -156,7 +155,7 @@ module.exports = { let index = this.webServices.app._router.stack.findIndex((item) => item.handle == this.webhookRouter) if (index >= 0) { - console.log("Removing router by index", index); + this.logger.info("Removing router by index", index); this.webServices.app._router.stack.splice(index, 1); } } @@ -176,17 +175,57 @@ module.exports = { await this.shutdown(); - await this.doAuth(); + try + { + await this.doAuth(); + } + catch (err) + { + this.logger.error(`Failed to Auth`); + this.logger.error(`${err}`); + } - await this.setupChatTriggers(); + try + { + await this.setupChatTriggers(); + } + catch (err) + { + this.logger.error(`Failed to setup Chat Triggers`); + this.logger.error(`${err}`); + } - await this.setupWebHookTriggers(); + try + { + await this.setupWebHookTriggers(); + } + catch (err) + { + this.logger.error(`Failed to setup WebHook Triggers`); + this.logger.error(`${err}`); + } - await this.setupPubSubTriggers(); + try + { + await this.setupPubSubTriggers(); + } + catch (err) + { + this.logger.error(`Failed to set up PubSub Triggers`); + this.logger.error(`${err}`); + } await this.initConditions(); - await this.initChannelRewards(); + try + { + await this.initChannelRewards(); + } + catch (err) + { + this.logger.error(`Failed to setup Channel Rewards`); + this.logger.error(`${err}`); + } }, async doAuth() @@ -320,7 +359,7 @@ module.exports = { this.followerCache.add(follow.userId); - console.log(`followed by ${follow.userDisplayName}`); + this.logger.info(`followed by ${follow.userDisplayName}`); this.actions.trigger('follow', { user: follow.userDisplayName, userId: follow.userId, ...{ userColor: this.colorCache[follow.userId] } }); @@ -328,15 +367,16 @@ module.exports = { this.state.followers = follows.total; }); + let subHook = await this.webhooks.subscribeToStreamChanges(this.channelId, async (stream) => { //Stream Changed - console.log("Stream Changed"); + this.logger.info("Stream Changed"); try { let game = await stream.getGame(); - console.log("Game Name", game.name); + this.logger.info(`Game Name: ${game.name}`); this.state.twitchCategory = game.name; } @@ -357,7 +397,7 @@ module.exports = { await this.pubSubClient.onBits(this.channelId, (message) => { - console.log(`Bits: ${message.bits}`); + this.logger.info(`Bits: ${message.bits}`); this.actions.trigger("bits", { @@ -372,7 +412,7 @@ module.exports = { await this.pubSubClient.onRedemption(this.channelId, (redemption) => { - console.log(`Redemption: ${redemption.rewardId} ${redemption.rewardName}`); + this.logger.info(`Redemption: ${redemption.rewardId} ${redemption.rewardName}`); let message = redemption.message; if (!message) { @@ -393,13 +433,13 @@ module.exports = { { if (message.isGift) { - console.log(`Gifted sub ${message.gifterDisplayName} -> ${message.userDisplayName}`); + this.logger.info(`Gifted sub ${message.gifterDisplayName} -> ${message.userDisplayName}`); this.actions.trigger('subscribe', { name: "gift", gifter: message.gifterDisplayName, user: message.userDisplayName, userId: message.userId, ...{ userColor: this.colorCache[message.userId] } }); } else { let months = message.months ? message.months : 0; - console.log(`Sub ${message.userDisplayName} : ${months}`); + this.logger.info(`Sub ${message.userDisplayName} : ${months}`); this.actions.trigger('subscribe', { number: months, user: message.userDisplayName, userId: message.userId, prime: message.subPlan == "Prime", ...{ userColor: this.colorCache[message.userId] } }) } @@ -513,7 +553,7 @@ module.exports = { }) } catch (err) { - console.log(`Error creating channel reward: ${rewardKey}. Message: ${err}`); + this.logger.error(`Error creating channel reward: ${rewardKey}. Message: ${err}`); } } }, @@ -602,7 +642,6 @@ module.exports = { }, async onSecretsReload() { - console.log("Secrets Changed"); await this.shutdown(); await this.doInitialAuth(); @@ -727,8 +766,6 @@ module.exports = { let result = ""; - console.log(diff); - if (diff.years > 0) { result += ` ${diff.years} year${diff.years > 1 ? 's' : ''}`; diff --git a/src/core/plugins/variables.js b/src/core/plugins/variables.js index 1b016139..545dffe7 100644 --- a/src/core/plugins/variables.js +++ b/src/core/plugins/variables.js @@ -90,13 +90,14 @@ module.exports = { { setValue = await this.handleTemplateNumber(setValue, context); } - console.log("Setting ", variableData.name, "to", setValue) + this.logger.info(`Setting ${variableData.name} to ${setValue}`); this.state[variableData.name] = setValue; } else if ("offset" in variableData) { //Add the value this.state[variableData.name] += variableData.offset; + this.logger.info(`Offseting ${variableData.name} by ${variableData.offset}`); } } } diff --git a/src/core/utils/configuration.js b/src/core/utils/configuration.js index 45d7792e..f3d9dbf5 100644 --- a/src/core/utils/configuration.js +++ b/src/core/utils/configuration.js @@ -3,11 +3,11 @@ const path = require('path'); const fs = require("fs"); const isPortable = process.argv.includes('--portable'); -const userFolder = (!isPortable ? path.join(app.getPath('userData'), 'user') : './user'); +const userFolder = path.resolve((!isPortable ? path.join(app.getPath('userData'), 'user') : './user')); -const settingsFilePath = path.join(userFolder, "settings.yaml"); -const secretsFilePath = path.join(userFolder, "secrets/secrets.yaml"); -const rewardsFilePath = path.join(userFolder, "rewards.yaml"); +const settingsFilePath = path.resolve(path.join(userFolder, "settings.yaml")); +const secretsFilePath = path.resolve(path.join(userFolder, "secrets/secrets.yaml")); +const rewardsFilePath = path.resolve(path.join(userFolder, "rewards.yaml")); function ensureFolder(path) @@ -29,8 +29,6 @@ function ensureFile(path) function ensureUserFolder() { - console.log("Ensuring User Folder: ", userFolder); - ensureFolder(userFolder); ensureFolder(path.join(userFolder, "data")); ensureFolder(path.join(userFolder, "profiles")); @@ -38,7 +36,7 @@ function ensureUserFolder() ensureFolder(path.join(userFolder, "sequences")); ensureFolder(path.join(userFolder, "sounds")); - ensureFolder(path.join(userFolder, "triggers")); + ensureFolder(path.join(userFolder, "commands")); ensureFile(rewardsFilePath); ensureFile(secretsFilePath); diff --git a/src/core/utils/logger.js b/src/core/utils/logger.js new file mode 100644 index 00000000..c3eabd39 --- /dev/null +++ b/src/core/utils/logger.js @@ -0,0 +1,28 @@ +const winston = require('winston'); +const path = require('path'); +const { userFolder } = require('./configuration'); + +const logger = winston.createLogger({ + level: 'info', + format: winston.format.json(), + transports: [ + // + // - Write all logs with level `error` and below to `error.log` + // - Write all logs with level `info` and below to `combined.log` + // + new winston.transports.File({ filename: path.join(userFolder, 'error.log'), level: 'error' }), + new winston.transports.File({ filename: path.join(userFolder, 'combined.log') }), + ], +}); + +// +// If we're not in production then log to the `console` with the format: +// `${info.level}: ${info.message} JSON.stringify({ ...rest }) ` +// +if (process.env.NODE_ENV !== 'production') +{ + logger.add(new winston.transports.Console({ + format: winston.format.simple(), + })); +} +module.exports = logger; \ No newline at end of file diff --git a/src/core/utils/plugin.js b/src/core/utils/plugin.js index fb10e2f1..432997b5 100644 --- a/src/core/utils/plugin.js +++ b/src/core/utils/plugin.js @@ -2,7 +2,7 @@ const { reactify } = require("./reactive"); const { cleanSchemaForIPC } = require("./schema"); const _ = require('lodash'); const { ipcMain } = require("electron"); - +const logger = require('../utils/logger'); class Plugin { constructor(config) @@ -12,7 +12,7 @@ class Plugin this.name = config.name; this.uiName = config.uiName || config.name; this.color = config.color; - console.log(`Loading Plugin: ${config.name}`); + logger.info(`Loading Plugin: ${config.name}`); this.initFunc = config.init; //Bind the init func to the pluginObj if (this.initFunc) @@ -96,6 +96,8 @@ class Plugin }) } + this.pluginObj.logger = logger; + //Create all the state. this.pluginObj.state = {}; for (let stateKey in config.state) @@ -125,7 +127,7 @@ class Plugin } catch (err) { // TODO: Throw exception to UI - console.log(`Error loading ${this.name} plugin. Error Msg: ${err}.`) + logger.error(`Error loading ${this.name} plugin. Error Msg: ${err}.`) } } } @@ -150,7 +152,6 @@ class Plugin this.pluginObj.secrets = newPluginSecrets; if (this.onSecretsReload) { - console.log("Secrets Changed Plugin: ", this.name); let oldPluginSecrets = oldSecrets[this.name] || {}; if (!_.isEqual(newPluginSecrets, oldPluginSecrets)) { diff --git a/src/core/utils/twitchAuth.js b/src/core/utils/twitchAuth.js index 76e0cfca..9f01b56f 100644 --- a/src/core/utils/twitchAuth.js +++ b/src/core/utils/twitchAuth.js @@ -2,6 +2,7 @@ const qs = require('querystring'); const { AccessToken } = require('twitch-auth'); const { BrowserWindow } = require('electron'); +const logger = require('./logger'); const scopes = [ "analytics:read:extensions", @@ -61,7 +62,7 @@ class ElectronAuthManager //Tests if auth can succeed silently. const promise = new Promise((resolve, reject) => { - console.log(`Attempting ${this.name} Twitch Silent Auth`) + logger.info(`Attempting ${this.name} Twitch Silent Auth`) const params = { response_type: "token", client_id: this._clientId, @@ -89,11 +90,11 @@ class ElectronAuthManager const url = new URL(details.url); const matchUrl = url.origin + url.pathname; - console.log(`Silent ${this.name} BeforeRequest`, matchUrl); + logger.info(`Silent ${this.name} BeforeRequest`, matchUrl); if (matchUrl == this._redirectUri) { const respParams = qs.parse(details.url.substr(details.url.indexOf('#') + 1)); - console.log("RedirectUri Detected"); + logger.info("RedirectUri Detected"); if (respParams.error || respParams.access_token) { window.destroy(); @@ -116,7 +117,7 @@ class ElectronAuthManager //todo return this sucker. resolve(this._accessToken); - console.log("Resolved"); + logger.info("Resolved"); } callback({ cancel: true }); } @@ -132,7 +133,8 @@ class ElectronAuthManager } }); - window.loadURL(authUrl).then(() => { + window.loadURL(authUrl).then(() => + { let fullUrl = window.webContents.getURL(); const url = new URL(fullUrl); const matchUrl = url.origin + url.pathname; @@ -182,11 +184,11 @@ class ElectronAuthManager const url = new URL(details.url); const matchUrl = url.origin + url.pathname; - console.log('BeforeRequest', matchUrl); + logger.info(`BeforeRequest ${matchUrl}`); if (matchUrl == this._redirectUri) { const respParams = qs.parse(details.url.substr(details.url.indexOf('#') + 1)); - console.log("RedirectUri Detected"); + logger.info("RedirectUri Detected"); if (respParams.error || respParams.access_token) { window.destroy(); @@ -194,14 +196,14 @@ class ElectronAuthManager if (respParams.error) { - console.log("Error!"); + logger.info("Error!"); //todo error! reject(respParams.error); callback({ cancel: true }); } else if (respParams.access_token) { - console.log("Access Token Success"); + logger.info("Access Token Success"); this._accessToken = new AccessToken({ access_token: respParams.access_token, scope: scopes, diff --git a/src/core/utils/webserver.js b/src/core/utils/webserver.js index 1cce2bcf..fc4ca448 100644 --- a/src/core/utils/webserver.js +++ b/src/core/utils/webserver.js @@ -5,6 +5,7 @@ const http = require("http"); const publicIp = require('public-ip'); const { userFolder } = require("./configuration"); const path = require("path"); +const logger = require("./logger"); async function createWebServices(settings, secrets, plugins) { @@ -61,7 +62,7 @@ async function createWebServices(settings, secrets, plugins) { server.listen(port, () => { - console.log(`Started Internal Webserver on port ${port}`); + logger.info(`Started Internal Webserver on port ${port}`); app.use(express.static("./web")); app.use("/user", express.static(path.join(userFolder, "data"), { etag: false diff --git a/src/router/index.js b/src/router/index.js index cd1299a3..03ba6d6e 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -2,7 +2,7 @@ import Vue from 'vue' import VueRouter from 'vue-router' import Profiles from "../views/Profiles.vue"; import ProfileEditor from "../views/ProfileEditor.vue"; -import TriggersEditor from "../views/TriggersEditor.vue"; +import CommandFileEditor from "../views/CommandFileEditor.vue"; import SequenceEditor from "../views/SequenceEditor.vue"; import Plugin from "../views/Plugin.vue"; import Rewards from "../views/Rewards.vue"; @@ -21,9 +21,9 @@ const routes = [ component: ProfileEditor }, { - path: "/triggers/:triggers", - name: "Trigger Editor", - component: TriggersEditor + path: "/commandFiles/:commandFile", + name: "Command File Editor", + component: CommandFileEditor }, { path: "/sequences/:sequence", diff --git a/src/store/ipc.js b/src/store/ipc.js index 2fb401a1..090f1aac 100644 --- a/src/store/ipc.js +++ b/src/store/ipc.js @@ -32,6 +32,7 @@ export default { { Object.assign(result, plugin.actions) } + //Special Injected Actions, these don't map to a plugin action. result.delay = { name: "Delay (After)", data: { type: "Number" }, @@ -42,6 +43,12 @@ export default { data: { type: "Number" }, description: "Puts a delay before the current action", }; + result.import = { + name: "Import Sequence", + data: { type: "String" }, + description: "Imports a sequence.", + color: "#7C4275" + } result.timestamp = { name: "Timestamp", data: { type: "Number" }, diff --git a/src/store/rewards.js b/src/store/rewards.js index b3d2a320..23c527b9 100644 --- a/src/store/rewards.js +++ b/src/store/rewards.js @@ -35,9 +35,6 @@ export default { { let newRewards = { ...state.rewards }; - console.log(rewardName) - console.log(newReward); - if (rewardName != newReward.name) { newRewards = changeObjectKey(newRewards, rewardName, newReward.name); diff --git a/src/views/CommandFileEditor.vue b/src/views/CommandFileEditor.vue new file mode 100644 index 00000000..118ffc5b --- /dev/null +++ b/src/views/CommandFileEditor.vue @@ -0,0 +1,125 @@ + + + + + + + updateCommand(commandKey, newData)" + @delete="deleteCommand(commandKey)" + @key-change="(v) => updateCommandKey(commandKey, v)" + /> + + + + + + Add Command + + + + + mdi-close + mdi-dots-vertical + + + + mdi-content-save + + + mdi-delete + + + + Saved + + + + + + + + \ No newline at end of file diff --git a/src/views/Plugin.vue b/src/views/Plugin.vue index 1333499e..8f8e3f8c 100644 --- a/src/views/Plugin.vue +++ b/src/views/Plugin.vue @@ -72,7 +72,6 @@ import { mapGetters } from "vuex"; import DataInput from "../components/data/DataInput.vue"; import Level from "@/components/layout/Level.vue"; import fs from "fs"; - import YAML from "yaml"; export default { diff --git a/src/views/Profiles.vue b/src/views/Profiles.vue index cd8e43d4..9b6554fa 100644 --- a/src/views/Profiles.vue +++ b/src/views/Profiles.vue @@ -26,19 +26,19 @@ - Triggers + Command Files - + - {{ trigger.name }} + {{ commandFile.name }} @@ -69,9 +69,48 @@ - + + + + - + + + + mdi-close + mdi-plus + + + + mdi-plus + Sequence + + + mdi-plus + Commands File + + + mdi-plus + Profile + + + + @@ -91,22 +130,21 @@ import fs from "fs"; import path from "path"; import YAML from "yaml"; -import NewProfileModal from "../components/profiles/NewProfileModal.vue"; import { mapGetters } from "vuex"; +import NamedItemModal from "../components/dialogs/NamedItemModal.vue"; export default { components: { - NewProfileModal, + NamedItemModal, }, computed: { ...mapGetters("ipc", ["paths"]), }, data() { return { - newProfileName: null, - profilePop: false, profiles: [], - triggers: [], + commandFiles: [], sequences: [], + fabOpen: false, }; }, methods: { @@ -114,22 +152,22 @@ export default { let profiles = await fs.promises.readdir( path.join(this.paths.userFolder, "profiles") ); - let triggers = await fs.promises.readdir( - path.join(this.paths.userFolder, "triggers") + let commandFiles = await fs.promises.readdir( + path.join(this.paths.userFolder, "commands") ); let sequences = await fs.promises.readdir( path.join(this.paths.userFolder, "sequences") ); profiles = profiles.filter((f) => path.extname(f) == ".yaml"); - triggers = triggers.filter((f) => path.extname(f) == ".yaml"); + commandFiles = commandFiles.filter((f) => path.extname(f) == ".yaml"); sequences = sequences.filter((f) => path.extname(f) == ".yaml"); this.profiles = profiles.map((f) => ({ name: path.basename(f, ".yaml"), })); - this.triggers = triggers.map((f) => ({ + this.commandFiles = commandFiles.map((f) => ({ name: path.basename(f, ".yaml"), })); @@ -137,9 +175,7 @@ export default { name: path.basename(f, ".yaml"), })); }, - async createProfile() { - this.profilePop = false; - + async createNewProfile(name) { let newYaml = YAML.stringify({ triggers: {}, variables: {}, @@ -147,10 +183,31 @@ export default { }); await fs.promises.writeFile( - path.join( - this.paths.userFolder, - `profiles/${this.newProfileName}.yaml` - ), + path.join(this.paths.userFolder, `profiles/${name}.yaml`), + newYaml, + "utf-8" + ); + + await this.getFiles(); + }, + + async createNewSequence(name) { + let newYaml = YAML.stringify([]); + + await fs.promises.writeFile( + path.join(this.paths.userFolder, `sequences/${name}.yaml`), + newYaml, + "utf-8" + ); + + await this.getFiles(); + }, + + async createNewCommandFile(name) { + let newYaml = YAML.stringify({}); + + await fs.promises.writeFile( + path.join(this.paths.userFolder, `commands/${name}.yaml`), newYaml, "utf-8" ); @@ -176,4 +233,14 @@ export default { position: absolute; margin: 0 0 16px 16px; } + +.fab-label { + position: absolute; + right: 50px; + background-color: rgba(0, 0, 0, 0.5); + padding: 10px; + box-shadow: 0px 3px 5px -1px rgba(0, 0, 0, 0.2), + 0px 6px 10px 0px rgba(0, 0, 0, 0.14), 0px 1px 18px 0px rgba(0, 0, 0, 0.12); + border-radius: 2px; +} \ No newline at end of file diff --git a/src/views/SequenceEditor.vue b/src/views/SequenceEditor.vue index d39fa67c..987a2b4b 100644 --- a/src/views/SequenceEditor.vue +++ b/src/views/SequenceEditor.vue @@ -2,7 +2,7 @@ - + @@ -31,8 +31,8 @@ - - \ No newline at end of file diff --git a/vue.config.js b/vue.config.js index e08dacb0..2312c1ef 100644 --- a/vue.config.js +++ b/vue.config.js @@ -8,6 +8,10 @@ module.exports = { externals: ["win32-api", "ffi-napi", "ref-napi", "node-gyp-build", "@peter-murray/hue-bridge-model", "node-hue-api", "jsdom", "canvas", "chokidar"], nodeIntegration: true, builderOptions: { + nsis: { + oneClick: false, + allowToChangeInstallationDirectory: true, + }, publish: [{ provider: 'github', owner: "LordTocs",