diff --git a/d.ts/index.d.ts b/d.ts/index.d.ts index 61f8ddb9e190..f9c1053d2c2a 100644 --- a/d.ts/index.d.ts +++ b/d.ts/index.d.ts @@ -3,6 +3,11 @@ declare module '*.vue' { export default Vue; } +declare module '*.txt' { + const content: string; + export default content; +} + declare namespace NodeJS { export interface Global { linesParsed: number; diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index b05d3c7b5815..72d740188b56 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -8628,6 +8628,14 @@ "unpipe": "1.0.0" } }, + "raw-loader": { + "version": "3.0.0", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "schema-utils": "^1.0.0" + } + }, "rc": { "version": "1.2.8", "dev": true, diff --git a/package.json b/package.json index 5ee098671f4b..b49197fd0af8 100644 --- a/package.json +++ b/package.json @@ -159,6 +159,7 @@ "minimist": "1.2.0", "mocha": "6.1.4", "node-sass": "4.12.0", + "raw-loader": "3.0.0", "sinon": "7.3.2", "terser": "4.1.2", "test-until": "1.1.1", diff --git a/public/index.html b/public/index.html index 5e6ab8bcc335..1c602d38ec89 100644 --- a/public/index.html +++ b/public/index.html @@ -20,9 +20,6 @@ - - - diff --git a/public/pages/registry/customVariables/edit.html b/public/pages/registry/customVariables/edit.html deleted file mode 100644 index eda927434b2b..000000000000 --- a/public/pages/registry/customVariables/edit.html +++ /dev/null @@ -1,499 +0,0 @@ - - - - {{ title }} - {{ variableName }} - - - - {{commons.translate('dialog.formNotValid')}} - - - - - - -
- -
-
- - - {{ commons.translate('registry.customvariables.variable.help') }} -
- - {{ commons.translate('registry.customvariables.variable.error.isEmpty') }} -
-
- -
- - - {{ commons.translate('registry.customvariables.description.help') }} -
- -
-
-
- -
- - - - -
- -
- - -
- -
- - {{ commons.translate('registry.customvariables.response.default-help') }} -
-
- -
-
- - -
{{ commons.translate('registry.customvariables.type.error.isNotSelected') }}
-
- -
- -
- - - -
- -
-
- -
-
-
- - - -
{{ commons.translate('registry.customvariables.usableOptions.error.atLeastOneValue') }}
-
- -
-
- -
-
-
- -
- - -
- - - -
{{ evalError }}
- -
-
- -
-
- -
{{ commons.translate('registry.customvariables.historyIsEmpty') }}
-
-
-
{{moment(h.timestamp).format('LL')}} {{ moment(h.timestamp).format('LTS') }}
-
{{ h.sender ? h.sender : 'Dashboard'}}
-
- {{ h.oldValue }} => {{ h.currentValue}} -
-
-
-
-
-
- -
- -
- - -
- -
- -
-
- - \ No newline at end of file diff --git a/public/pages/registry/customVariables/list.html b/public/pages/registry/customVariables/list.html deleted file mode 100644 index f8e571ee98da..000000000000 --- a/public/pages/registry/customVariables/list.html +++ /dev/null @@ -1,136 +0,0 @@ - - - -
- - - - - - - - - - - - - - - - - - - - - - -
$_{{ commons.translate('registry.customvariables.description.name') }}{{ commons.translate('registry.customvariables.type.name') }}{{ commons.translate('registry.customvariables.currentValue.name') }}{{ commons.translate('registry.customvariables.additional-info') }}
{{ variable.variableName }} - {{ variable.description && variable.description.length !== 0 ? variable.description : commons.translate('not-available') }} - {{ commons.translate('registry.customvariables.types.' + variable.type) }}{{ variable.currentValue && variable.currentValue.length !== 0 ? variable.currentValue : commons.translate('not-available') }} - - {{ commons.translate('registry.customvariables.run-script') }}: - - -
- {{ commons.translate('registry.customvariables.last-run') }} {{ variable.runAt ? new Date(variable.runAt).toLocaleString() : commons.translate('commons.never') }} -
-
- - {{ commons.translate('registry.customvariables.usableOptions.name') }}: - {{ variable.usableOptions }} - -
- {{ commons.translate('registry.customvariables.isReadOnly') | capitalize }} -
- -
- {{ commons.translate('registry.customvariables.response.name') }}: - {{ commons.translate('registry.customvariables.response.default') }} - {{ commons.translate('registry.customvariables.response.custom') }} - {{ commons.translate('registry.customvariables.response.command') }} - {{ variable.responseText }} -
-
- {{ commons.translate('registry.customvariables.permissionToChange') }}: - {{ getPermissionName(variable.permission) }} - Permission not found -
-
- {{ commons.translate('dialog.buttons.edit') }} - -
-
- - \ No newline at end of file diff --git a/src/bot/customvariables.js b/src/bot/customvariables.js index a010876be458..e62e263b8429 100644 --- a/src/bot/customvariables.js +++ b/src/bot/customvariables.js @@ -1,138 +1,137 @@ -'use strict' +'use strict'; -const _ = require('lodash') -const crypto = require('crypto') -const safeEval = require('safe-eval') -const axios = require('axios') +const _ = require('lodash'); +const safeEval = require('safe-eval'); +const axios = require('axios'); const { isMainThread } = require('worker_threads'); -const mathjs = require('mathjs') +const mathjs = require('mathjs'); -const Message = require('./message') +const Message = require('./message'); import { permission } from './permissions'; const commons = require('./commons'); class CustomVariables { constructor () { - this.timeouts = {} + this.timeouts = {}; if (isMainThread) { - this.addMenuAndListenersToPanel() - this.checkIfCacheOrRefresh() - global.db.engine.index('custom.variables.history', [{ index: 'cvarId' }]) + this.addMenuAndListenersToPanel(); + this.checkIfCacheOrRefresh(); + global.db.engine.index('custom.variables.history', [{ index: 'cvarId' }]); } } async addMenuAndListenersToPanel () { - clearTimeout(this.timeouts[`${this.constructor.name}.addMenuAndListenersToPanel`]) + clearTimeout(this.timeouts[`${this.constructor.name}.addMenuAndListenersToPanel`]); if (_.isNil(global.panel)) { - this.timeouts[`${this.constructor.name}.addMenuAndListenersToPanel`] = setTimeout(() => this.addMenuAndListenersToPanel(), 1000) + this.timeouts[`${this.constructor.name}.addMenuAndListenersToPanel`] = setTimeout(() => this.addMenuAndListenersToPanel(), 1000); } else { - global.panel.addMenu({ category: 'registry', name: 'custom-variables', id: 'registry.customVariables/list' }) - this.sockets() + global.panel.addMenu({ category: 'registry', name: 'custom-variables', id: 'registry.customVariables/list' }); + this.sockets(); } } sockets () { - const io = global.panel.io.of('/registry/customVariables') + const io = global.panel.io.of('/registry/customVariables'); io.on('connection', (socket) => { socket.on('list.variables', async (cb) => { - let variables = await global.db.engine.find('custom.variables') - cb(null, variables) - }) + let variables = await global.db.engine.find('custom.variables'); + cb(null, variables); + }); socket.on('run.script', async (_id, cb) => { - let item + let item; try { - item = await global.db.engine.findOne('custom.variables', { _id: String(_id) }) - item = await global.db.engine.update('custom.variables', { _id: String(_id) }, { currentValue: await this.runScript(item.evalValue, { _current: item.currentValue }), runAt: Date.now() }) + item = await global.db.engine.findOne('custom.variables', { _id: String(_id) }); + item = await global.db.engine.update('custom.variables', { _id: String(_id) }, { currentValue: await this.runScript(item.evalValue, { _current: item.currentValue }), runAt: Date.now() }); } catch (e) { - cb(e.stack, null) + cb(e.stack, null); } - cb(null, item) - }) + cb(null, item); + }); socket.on('test.script', async (opts, cb) => { - let returnedValue + let returnedValue; try { - returnedValue = await this.runScript(opts.evalValue, { _current: opts.currentValue, sender: { username: 'testuser', userId: '0' }}) + returnedValue = await this.runScript(opts.evalValue, { _current: opts.currentValue, sender: { username: 'testuser', userId: '0' }}); } catch (e) { - cb(e.stack, null) + cb(e.stack, null); } - cb(null, returnedValue) - }) - socket.on('isUnique', async (variable, cb) => { - cb(null, _.isEmpty(await global.db.engine.findOne('custom.variables', { variableName: String(variable) }))) - }) + cb(null, returnedValue); + }); + socket.on('isUnique', async ({ variable, id }, cb) => { + cb(null, (await global.db.engine.find('custom.variables', { variableName: String(variable) })).filter(o => String(o._id) !== id).length === 0); + }); socket.on('delete', async (id, cb) => { - await global.db.engine.remove('custom.variables', { _id: String(id) }) - await global.db.engine.remove('custom.variables.watch', { variableId: String(id) }) // force unwatch - this.updateWidgetAndTitle() - cb() - }) + await global.db.engine.remove('custom.variables', { _id: String(id) }); + await global.db.engine.remove('custom.variables.watch', { variableId: String(id) }); // force unwatch + this.updateWidgetAndTitle(); + cb(); + }); socket.on('load', async (id, cb) => { - const variable = await global.db.engine.findOne('custom.variables', { _id: String(id) }) - const history = await global.db.engine.find('custom.variables.history', { cvarId: String(id) }) - cb({variable, history}) - }) + const variable = await global.db.engine.findOne('custom.variables', { _id: String(id) }); + const history = await global.db.engine.find('custom.variables.history', { cvarId: String(id) }); + cb({variable, history}); + }); socket.on('save', async (data, cb) => { - var _id + var _id; try { if (!_.isNil(data._id)) { - _id = String(data._id); delete (data._id) - await global.db.engine.update('custom.variables', { _id }, data) - this.updateWidgetAndTitle(data.variableName) + _id = String(data._id); delete (data._id); + await global.db.engine.update('custom.variables', { _id }, data); + this.updateWidgetAndTitle(data.variableName); } else { - delete (data._id) - let item = await global.db.engine.insert('custom.variables', data) - _id = String(item._id) - this.updateWidgetAndTitle(data.variableName) + delete (data._id); + let item = await global.db.engine.insert('custom.variables', data); + _id = String(item._id); + this.updateWidgetAndTitle(data.variableName); } - cb(null, _id) + cb(null, _id); } catch (e) { - cb(e.stack, _id) + cb(e.stack, _id); } - }) - }) + }); + }); } async runScript (script, opts) { - let sender = !_.isNil(opts.sender) ? opts.sender : null - let param = !_.isNil(opts.param) ? opts.param : null + let sender = !_.isNil(opts.sender) ? opts.sender : null; + let param = !_.isNil(opts.param) ? opts.param : null; if (typeof sender === 'string') { sender = { username: sender, userId: await global.users.getIdByName(sender) - } + }; } // we need to check +1 variables, as they are part of commentary - const containUsers = !_.isNil(script.match(/users/g)) && script.match(/users/g).length > 1 + const containUsers = !_.isNil(script.match(/users/g)) && script.match(/users/g).length > 1; const containRandom = !_.isNil(script.replace(/Math\.random|_\.random/g, '').match(/random/g)); - const containOnline = !_.isNil(script.match(/online/g)) + const containOnline = !_.isNil(script.match(/online/g)); - let users = [] + let users = []; if (containUsers || containRandom) { - users = await global.users.getAll() + users = await global.users.getAll(); } - let onlineViewers = [] - let onlineSubscribers = [] - let onlineFollowers = [] + let onlineViewers = []; + let onlineSubscribers = []; + let onlineFollowers = []; if (containOnline) { - onlineViewers = await global.db.engine.find('users.online') + onlineViewers = await global.db.engine.find('users.online'); for (let viewer of onlineViewers) { - let user = await global.db.engine.find('users', { username: viewer.username, is: { subscriber: true } }) - if (!_.isEmpty(user)) onlineSubscribers.push(user.username) + let user = await global.db.engine.find('users', { username: viewer.username, is: { subscriber: true } }); + if (!_.isEmpty(user)) {onlineSubscribers.push(user.username)}; } for (let viewer of onlineViewers) { - let user = await global.db.engine.find('users', { username: viewer.username, is: { follower: true } }) - if (!_.isEmpty(user)) onlineFollowers.push(user.username) + let user = await global.db.engine.find('users', { username: viewer.username, is: { follower: true } }); + if (!_.isEmpty(user)) {onlineFollowers.push(user.username)}; } } @@ -145,19 +144,19 @@ class CustomVariables { viewer: _.sample(_.map(users, 'username')), follower: _.sample(_.map(_.filter(users, (o) => _.get(o, 'is.follower', false)), 'username')), subscriber: _.sample(_.map(_.filter(users, (o) => _.get(o, 'is.subscriber', false)), 'username')) - } + }; // get custom variables const customVariablesDb = await global.db.engine.find('custom.variables'); - const customVariables = {} + const customVariables = {}; for (const cvar of customVariablesDb) { - customVariables[cvar.variableName] = cvar.currentValue + customVariables[cvar.variableName] = cvar.currentValue; } // update globals and replace theirs values - script = (await new Message(script).global({ escape: "'" })) + script = (await new Message(script).global({ escape: '\'' })); - let toEval = `(async function evaluation () { ${script} })()` + let toEval = `(async function evaluation () { ${script} })()`; let context = { url: async (url, opts) => { if (typeof opts === 'undefined') { @@ -166,20 +165,20 @@ class CustomVariables { method: 'GET', headers: undefined, data: undefined, - } + }; } else { - opts.url = url + opts.url = url; } if (!['GET', 'POST', 'PUT', 'DELETE'].includes(opts.method.toUpperCase())) { - throw Error('only GET, POST, PUT, DELETE methods are supported') + throw Error('only GET, POST, PUT, DELETE methods are supported'); } if (opts.url.trim().length === 0) { - throw Error('url was not properly specified') + throw Error('url was not properly specified'); } - const request = await axios(opts) + const request = await axios(opts); return { data: request.data, status: request.status, statusText: request.statusText }; }, _: _, @@ -239,38 +238,38 @@ class CustomVariables { subscriber: _.get(_user, 'is.subscriber', false), mod: await commons.isModerator(username) } - } + }; return userObj; }, ...customVariables, - } - return (safeEval(toEval, context)) + }; + return (safeEval(toEval, context)); } async isVariableSet (variableName) { - let item = await global.db.engine.findOne('custom.variables', { variableName }) - return !_.isEmpty(item) ? String(item._id) : null + let item = await global.db.engine.findOne('custom.variables', { variableName }); + return !_.isEmpty(item) ? String(item._id) : null; } async isVariableSetById (_id) { - let item = await global.db.engine.findOne('custom.variables', { _id }) - return !_.isEmpty(item) ? String(item.variableName) : null + let item = await global.db.engine.findOne('custom.variables', { _id }); + return !_.isEmpty(item) ? String(item.variableName) : null; } async getValueOf (variableName, opts) { - if (!variableName.startsWith('$_')) variableName = `$_${variableName}` - let item = await global.db.engine.findOne('custom.variables', { variableName }) - if (_.isEmpty(item)) return '' // return empty if variable doesn't exist + if (!variableName.startsWith('$_')) {variableName = `$_${variableName}`}; + let item = await global.db.engine.findOne('custom.variables', { variableName }); + if (_.isEmpty(item)) {return ''}; // return empty if variable doesn't exist if (item.type === 'eval' && Number(item.runEvery) === 0) { item.currentValue = await this.runScript(item.evalValue, { _current: item.currentValue, ...opts - }) - await global.db.engine.update('custom.variables', { variableName }, { currentValue: item.currentValue, runAt: Date.now() }) + }); + await global.db.engine.update('custom.variables', { variableName }, { currentValue: item.currentValue, runAt: Date.now() }); } - return item.currentValue + return item.currentValue; } /* Sets value of variable with proper checks @@ -279,16 +278,16 @@ class CustomVariables { * { updated, isOK } */ async setValueOf (variableName, currentValue, opts) { - let item = await global.db.engine.findOne('custom.variables', { variableName }) - let isOk = true - let isEval = false - let oldValue = null + let item = await global.db.engine.findOne('custom.variables', { variableName }); + let isOk = true; + let isEval = false; + let oldValue = null; - opts.sender = _.isNil(opts.sender) ? null : opts.sender - opts.readOnlyBypass = _.isNil(opts.readOnlyBypass) ? false : opts.readOnlyBypass + opts.sender = _.isNil(opts.sender) ? null : opts.sender; + opts.readOnlyBypass = _.isNil(opts.readOnlyBypass) ? false : opts.readOnlyBypass; // add simple text variable, if not existing if (_.isEmpty(item)) { - item = await global.db.engine.insert('custom.variables', { variableName, currentValue, type: 'text', responseType: 0, permission: permission.MODERATORS }) + item = await global.db.engine.insert('custom.variables', { variableName, currentValue, type: 'text', responseType: 0, permission: permission.MODERATORS }); } else { // set item permission to owner if missing item.permission = typeof item.permission === 'undefined' ? permission.CASTERS : item.permission; @@ -296,93 +295,93 @@ class CustomVariables { commons.isVIP(opts.sender), commons.isModerator(opts.sender), commons.isOwner(opts.sender) - ]) + ]); if (typeof opts.sender === 'string') { opts.sender = { username: opts.sender, userId: await global.users.getIdByName(opts.sender) - } + }; } const permissionsAreValid = _.isNil(opts.sender) || (await global.permissions.check(opts.sender.userId, item.permission)).access; if ((item.readOnly && !opts.readOnlyBypass) || !permissionsAreValid) { - isOk = false + isOk = false; } else { - oldValue = item.currentValue + oldValue = item.currentValue; if (item.type === 'number') { if (['+', '-'].includes(currentValue)) { - currentValue = mathjs.eval(`${item.currentValue} ${currentValue} 1`) + currentValue = mathjs.eval(`${item.currentValue} ${currentValue} 1`); } else { - const isNumber = _.isFinite(Number(currentValue)) - isOk = isNumber - currentValue = isNumber ? Number(currentValue) : item.currentValue + const isNumber = _.isFinite(Number(currentValue)); + isOk = isNumber; + currentValue = isNumber ? Number(currentValue) : item.currentValue; } } else if (item.type === 'options') { // check if is in usableOptions - let isUsableOption = item.usableOptions.split(',').map((o) => o.trim()).includes(currentValue) - isOk = isUsableOption - currentValue = isUsableOption ? currentValue : item.currentValue + let isUsableOption = item.usableOptions.split(',').map((o) => o.trim()).includes(currentValue); + isOk = isUsableOption; + currentValue = isUsableOption ? currentValue : item.currentValue; } else if (item.type === 'eval') { - opts.param = currentValue - item.currentValue = await this.getValueOf(variableName, opts) - isEval = true + opts.param = currentValue; + item.currentValue = await this.getValueOf(variableName, opts); + isEval = true; } // do update only on non-eval variables - if (item.type !== 'eval' && isOk) item = await global.db.engine.update('custom.variables', { variableName }, { currentValue }) + if (item.type !== 'eval' && isOk) {item = await global.db.engine.update('custom.variables', { variableName }, { currentValue })}; } } - item.setValue = item.currentValue + item.setValue = item.currentValue; if (isOk) { - this.updateWidgetAndTitle(variableName) + this.updateWidgetAndTitle(variableName); if (!isEval) { - this.addChangeToHistory({ sender: _.get(opts, 'sender.username', null), item, oldValue }) - item.currentValue = '' // be silent if parsed correctly + this.addChangeToHistory({ sender: _.get(opts, 'sender.username', null), item, oldValue }); + item.currentValue = ''; // be silent if parsed correctly } } - return { updated: item, isOk, isEval } + return { updated: item, isOk, isEval }; } async addChangeToHistory(opts) { - await global.db.engine.insert('custom.variables.history', { cvarId: String(opts.item._id), sender: opts.sender, oldValue: opts.oldValue, currentValue: opts.item.currentValue, timestamp: String(new Date())}) + await global.db.engine.insert('custom.variables.history', { cvarId: String(opts.item._id), sender: opts.sender, oldValue: opts.oldValue, currentValue: opts.item.currentValue, timestamp: String(new Date())}); } async checkIfCacheOrRefresh () { - clearTimeout(this.timeouts[`${this.constructor.name}.checkIfCacheOrRefresh`]) - let items = await global.db.engine.find('custom.variables', { type: 'eval' }) + clearTimeout(this.timeouts[`${this.constructor.name}.checkIfCacheOrRefresh`]); + let items = await global.db.engine.find('custom.variables', { type: 'eval' }); for (let item of items) { try { - item.runAt = _.isNil(item.runAt) ? 0 : item.runAt - const shouldRun = item.runEvery > 0 && Date.now() - new Date(item.runAt).getTime() >= item.runEvery + item.runAt = _.isNil(item.runAt) ? 0 : item.runAt; + const shouldRun = item.runEvery > 0 && Date.now() - new Date(item.runAt).getTime() >= item.runEvery; if (shouldRun) { - let newValue = await this.runScript(item.evalValue, { _current: item.currentValue }) - await global.db.engine.update('custom.variables', { _id: String(item._id) }, { runAt: Date.now(), currentValue: newValue }) - await this.updateWidgetAndTitle(item.variableName) + let newValue = await this.runScript(item.evalValue, { _current: item.currentValue }); + await global.db.engine.update('custom.variables', { _id: String(item._id) }, { runAt: Date.now(), currentValue: newValue }); + await this.updateWidgetAndTitle(item.variableName); } } catch (e) {} // silence errors } - this.timeouts[`${this.constructor.name}.checkIfCacheOrRefresh`] = setTimeout(() => this.checkIfCacheOrRefresh(), 1000) + this.timeouts[`${this.constructor.name}.checkIfCacheOrRefresh`] = setTimeout(() => this.checkIfCacheOrRefresh(), 1000); } async updateWidgetAndTitle (variable) { if (!isMainThread) { - global.workers.sendToMaster({ type: 'widget_custom_variables', emit: 'refresh' }) - } else if (!_.isNil(global.widgets.custom_variables.socket)) global.widgets.custom_variables.socket.emit('refresh') // send update to widget + global.workers.sendToMaster({ type: 'widget_custom_variables', emit: 'refresh' }); + } else if (!_.isNil(global.widgets.custom_variables.socket)) {global.widgets.custom_variables.socket.emit('refresh')}; // send update to widget if (!_.isNil(variable)) { - const regexp = new RegExp(`\\${variable}`, 'ig') - let title = await global.cache.rawStatus() + const regexp = new RegExp(`\\${variable}`, 'ig'); + let title = await global.cache.rawStatus(); if (title.match(regexp)) { if (!isMainThread) { - global.workers.sendToMaster({ type: 'call', ns: 'api', fnc: 'setTitleAndGame', args: [null] }) + global.workers.sendToMaster({ type: 'call', ns: 'api', fnc: 'setTitleAndGame', args: [null] }); } else { - global.api.setTitleAndGame(null) + global.api.setTitleAndGame(null); } } } } } -module.exports = CustomVariables +module.exports = CustomVariables; diff --git a/src/panel/index.ts b/src/panel/index.ts index 55e30c043f91..9fc3f78b9dd2 100644 --- a/src/panel/index.ts +++ b/src/panel/index.ts @@ -110,6 +110,8 @@ const main = async () => { { path: '/settings/permissions/:id?', name: 'PermissionsSettings', component: () => import('./views/settings/permissions.vue') }, { path: '/settings/:type/:id?', name: 'InterfaceSettings', component: () => import('./views/settings/interface.vue') }, + { path: '/registry/customvariables/list', name: 'CustomVariableList', component: () => import('./views/registries/custom-variables/custom-variables-list.vue') }, + { path: '/registry/customvariables/edit/:id?', name: 'CustomVariableEdit', component: () => import('./views/registries/custom-variables/custom-variables-edit.vue') }, { path: '/registry/goals/list', name: 'GoalsRegistryList', component: () => import('./views/registries/goalsList.vue') }, { path: '/registry/goals/edit/:id?', name: 'GoalsRegistryEdit', component: () => import('./views/registries/goalsEdit.vue') }, ], @@ -118,7 +120,7 @@ const main = async () => { new Vue({ router, created() { - this.$moment.locale(global.configuration.core.general.lang); // set proper moment locale + this.$moment.locale(global.configuration.lang); // set proper moment locale }, template: `
diff --git a/src/panel/views/registries/custom-variables/custom-variables-code.txt b/src/panel/views/registries/custom-variables/custom-variables-code.txt new file mode 100644 index 000000000000..ae1e46bb1a8e --- /dev/null +++ b/src/panel/views/registries/custom-variables/custom-variables-code.txt @@ -0,0 +1,41 @@ +/* Available functions + user(username?: string): Promise<{ username: string, id: string, is: { follower: boolean, mod: boolean, online: boolean, subscriber: boolean, vip: boolean }}> - returns user object (if null -> sender) + url(url: string, opts?: { method: 'POST' | 'GET', headers: object, data: object}): Promise<{ data: object, status: number, statusText: string}> +* +* Available variables + _, _current, users, param (only in custom command) + sender?: { // (only in custom commands, keyword) + username: string, + userId: string, + } + random: { + online: { + viewer: string, + follower: string, + subscriber: string + }, + viewer: string, + follower: string, + subscriber: string + } + stream: { + uptime: string, + chatMessages: number, + currentViewers: number, + currentBits: number, + currentFollowers: number, + currentHosts: number, + currentViews: number, + currentTips: number, + currentWatched: number, + currency: string, + maxViewers: number, + newChatters: number, + game: string, + status: string + } +* +* IMPORTANT: Must contain return statement! +*/ + +return ''; \ No newline at end of file diff --git a/src/panel/views/registries/custom-variables/custom-variables-edit.vue b/src/panel/views/registries/custom-variables/custom-variables-edit.vue new file mode 100644 index 000000000000..af18f5ed990b --- /dev/null +++ b/src/panel/views/registries/custom-variables/custom-variables-edit.vue @@ -0,0 +1,486 @@ + + + + + \ No newline at end of file diff --git a/src/panel/views/registries/custom-variables/custom-variables-list.vue b/src/panel/views/registries/custom-variables/custom-variables-list.vue new file mode 100644 index 000000000000..e1fabb21d37d --- /dev/null +++ b/src/panel/views/registries/custom-variables/custom-variables-list.vue @@ -0,0 +1,174 @@ + + + \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index cbb0543426a0..c542bc0b232b 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -55,6 +55,10 @@ module.exports = [{ ], module: { rules: [ + { + test: /\.txt$/i, + use: 'raw-loader', + }, { test: /\.ts$/, exclude: /(node_modules|bower_components)/, @@ -126,6 +130,10 @@ module.exports = [{ ], module: { rules: [ + { + test: /\.txt$/i, + use: 'raw-loader', + }, { test: /\.ts$/, exclude: /(node_modules|bower_components)/, diff --git a/yarn.lock b/yarn.lock index b3b427052879..2c9cd429c81c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8488,6 +8488,14 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" +raw-loader@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-3.0.0.tgz#9a660dc9cfbfb8324eede3ea3511454d2a5d0389" + integrity sha512-FsELYliOpX5HdPdxa7PzTmEc5OTchmLUs/r4f8oLDGCYE+xC2FjVbDXzdyLcBrdlDnvkx1x5wzphixcWpxJG5w== + dependencies: + loader-utils "^1.1.0" + schema-utils "^1.0.0" + rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"