Skip to content

Commit fdac1e5

Browse files
authored
Merge pull request #80 from Kruiser8/develop
Updates for v2.0.6
2 parents 80a44c2 + 9afbe21 commit fdac1e5

11 files changed

Lines changed: 340 additions & 49 deletions

File tree

index.html

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
<html>
22
<head>
33
<meta charset="UTF-8">
4+
<!-- IndexedDB -->
5+
<script>
6+
async function loadKeyval() {
7+
idbKeyval = await import('https://cdn.jsdelivr.net/npm/idb-keyval@6.2.1/dist/index.min.js');
8+
}
9+
loadKeyval()
10+
</script>
411
<!-- JQuery -->
512
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
613
<!-- SockJS for SLOBS -->
@@ -9,8 +16,6 @@
916
<script src='https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.3/socket.io.js' type='text/javascript'></script>
1017
<!-- Twitch Chat -->
1118
<script src="https://cdn.jsdelivr.net/npm/comfy.js@latest/dist/comfy.min.js"></script>
12-
<!-- IndexedDB -->
13-
<script src="https://cdn.jsdelivr.net/npm/idb-keyval@3/dist/idb-keyval-iife.min.js"></script>
1419
<!-- UUID -->
1520
<script src="https://cdn.jsdelivr.net/npm/uuid@latest/dist/umd/uuidv4.min.js"></script>
1621
<!-- TES (Twitch EventSub) -->

js/Documentation.md

Lines changed: 108 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Each handler provides its own triggers and actions that can be used in a trigger
66
- [General](#general)
77
* [Case Sensitivity](#case-sensitivity)
88
* [Quotes](#quotes)
9+
* [Multi-line Inputs](#multi-line-inputs)
910
* [Comments](#comments)
1011
* [Parameters](#parameters)
1112
* [Aliases](#aliases)
@@ -285,6 +286,7 @@ Each handler provides its own triggers and actions that can be used in a trigger
285286
+ [OnTWUnban](#ontwunban)
286287
* [Actions](#twitch-actions)
287288
+ [Twitch AddBlockedTerm](#twitch-addblockedterm)
289+
+ [Twitch AdSchedule](#twitch-adschedule)
288290
+ [Twitch Announcement](#twitch-announcement)
289291
+ [Twitch Auth](#twitch-auth)
290292
+ [Twitch Authenticate](#twitch-authenticate)
@@ -432,6 +434,46 @@ OBS Scene "Starting Soon"
432434

433435
***
434436

437+
### Multi-line Inputs
438+
As of Kruiz Control v2.0.6, the inputs to triggers and actions can be split over multiple lines. For example, the below action provides a [`Function`](#function) input via multiple lines.
439+
```
440+
OnInit
441+
Function "
442+
var data = 4;
443+
return { value: data * 2 };
444+
"
445+
Error {data}
446+
```
447+
448+
_Note: While an individual input can be multiple lines, inputs cannot be distributed over multiple lines._
449+
450+
The below events are **NOT** valid.
451+
452+
```
453+
# Invalid because the inputs are provided on the following lines.
454+
OnInit
455+
Random
456+
"Chat Send 'Option 1'"
457+
"Chat Send 'Option 2'"
458+
459+
# Invalid because the first input ends on the first line.
460+
# The second option will be skipped.
461+
OnInit
462+
Random "Chat Send 'Option 1'"
463+
"Chat Send 'Option 2'"
464+
```
465+
466+
The below is technically valid, albeit funky looking. As long as a quote is not terminated until the following line, it will be parsed as a multi-line input.
467+
468+
```
469+
# Since the end double quote for the first input is on the second line, the second line is included when processing the action.
470+
OnInit
471+
Random "Chat Send 'Option 1'
472+
" "Chat Send 'Option 2'"
473+
```
474+
475+
***
476+
435477
### Comments
436478
Trigger files support comments using the **#** character. This allows you to leave text in the trigger file that is not treated as a trigger or action.
437479

@@ -1432,16 +1474,53 @@ A small selection of actions that are included for increased usability.
14321474
**Format** | `Function <function>`
14331475
**Example** | `Function 'return {total: {total} + 1}'`
14341476

1435-
`<function>` is a javascript function body. For reference, please see this [documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/Function). If the function returns an object, each property of the Object is usable as a parameter in the rest of the trigger.
1477+
`<function>` is a javascript function body. For reference, please see this [documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/Function).
1478+
1479+
If the function returns an object, each property of the Object is usable as a parameter in the rest of the trigger.
1480+
1481+
- If a `continue` parameter is returned and the value is `false`, the trigger will exit and not continue processing actions.
1482+
1483+
- If an `actions` array parameter is returned, each item of the array will be inserted into the event and processed.
1484+
1485+
##### Example Usage
1486+
1487+
<table>
1488+
<tr>
1489+
<td>The below returns a random element from an array in <code>api_data</code>.</td>
1490+
</tr>
1491+
<tr>
1492+
<td>
14361493

1437-
The below returns a random element from an array in _api_data_.
1438-
```js
1494+
```m
14391495
Function 'var arr = [api_data]; return {random: arr[Math.floor(Math.random() * arr.length)]}'
14401496
```
14411497

1442-
If a `continue` parameter is returned and the value is `false`, the trigger will exit and not continue processing actions.
1498+
</td>
1499+
</tr>
1500+
</table>
1501+
1502+
<table>
1503+
<tr>
1504+
<td><em>Note: As of Kruiz Control v2.0.6, multi-line inputs are now supported.</em>
14431505

1444-
If an `actions` array parameter is returned, each item of the array will be inserted into the event and processed.
1506+
The above example can be rewritten as the multi-line <code>function</code> below.</td>
1507+
</tr>
1508+
<tr>
1509+
<td>
1510+
1511+
```m
1512+
OnInit
1513+
Function "
1514+
var arr = [api_data];
1515+
return {
1516+
random: arr[Math.floor(Math.random() * arr.length)]
1517+
};
1518+
"
1519+
```
1520+
1521+
</td>
1522+
</tr>
1523+
</table>
14451524

14461525
***
14471526

@@ -1509,7 +1588,7 @@ The following `<comparator>` values are valid: `=`, `<`, `>`, `<=`, `>=`, `!=` (
15091588

15101589
Multiple comparisons can be combined in one **If** line using the following `<conjunction>` values: `and`, `or`.
15111590

1512-
The `<optional_skip>` value allows you to specify the number of lines to skip if the criteria is not met. This value is completely optional and allows for advanced logic handling.
1591+
The `<optional_skip>` value allows you to specify the number of lines to skip if the criteria is not met. This value is completely optional and allows for advanced logic handling. When skipping lines, multi-line inputs are considered one line and comments are not considered.
15131592

15141593

15151594
| | |
@@ -1547,7 +1626,7 @@ The `<optional_skip>` value allows you to specify the number of lines to skip if
15471626
#### Loop
15481627
| | |
15491628
------------ | -------------
1550-
**Info** | Used to repeat a set of actions a specified number of times. `<lines>` is the number of actions/lines to repeat. `<times>` is the number of times to repeat the actions/lines.
1629+
**Info** | Used to repeat a set of actions a specified number of times. `<lines>` is the number of actions/lines to repeat. When counting lines, multi-line inputs are considered one line and comments are not considered. `<times>` is the number of times to repeat the actions/lines.
15511630
**Format** | `Loop <lines> <times>`
15521631
**Example** | `Loop 8 10`
15531632

@@ -1589,7 +1668,7 @@ The `<optional_skip>` value allows you to specify the number of lines to skip if
15891668
#### Skip
15901669
| | |
15911670
------------ | -------------
1592-
**Info** | Used to skip over the next `<number>` of lines in an event.
1671+
**Info** | Used to skip over the next `<number>` of lines in an event. When skipping lines, multi-line inputs are considered one line and comments are not considered.
15931672
**Format** | `Skip <number>`
15941673
**Example** | `Skip 3`
15951674

@@ -3860,6 +3939,26 @@ _Note: Bit voting is not currently supported, however Twitch provides these valu
38603939
**Example** | `Twitch AddBlockedTerm "bad word"`
38613940
**Example w/ Aliases** | `Twitch AddBlockedTerm "phrase to block" "bad term"`
38623941

3942+
***
3943+
3944+
#### Twitch AdSchedule
3945+
| | |
3946+
------------ | -------------
3947+
**Info** | Used to retrieve upcoming scheduled ad, snooze, and pre-roll related information.
3948+
**Format** | `Twitch AdSchedule`
3949+
**Example** | `Twitch AdSchedule`
3950+
3951+
##### Parameters
3952+
| | |
3953+
------------ | -------------
3954+
**data** | The complete response from the Twitch Ad Schedule API.
3955+
**next_ad_time** | The number of seconds until the next scheduled ad.
3956+
**next_ad_duration** | The duration (in seconds) of the next scheduled ad.
3957+
**preroll_free_time** | The amount (in seconds) of pre-roll free time remaining for the channel.
3958+
**next_snooze_time** | The number of seconds until the broadcaster receives an additional ad snooze.
3959+
**snooze_count** | The number of snoozes available for the broadcaster.
3960+
3961+
38633962
***
38643963

38653964
#### Twitch Announcement
@@ -4841,6 +4940,7 @@ _Note: Due to a Twitch API restriction, in order for Kruiz Control to interact w
48414940
**data** | The complete response from the Twitch User API.
48424941
**user** | The user's display name.
48434942
**description** | The user's channel description.
4943+
**profile_image** | The URL to the user's profile image.
48444944

48454945
***
48464946

js/controller.js

Lines changed: 37 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,17 @@ class Controller {
121121
/**
122122
* Setup async queue for given trigger id
123123
* @param {string} triggerId id of the trigger to run
124-
* @param {object} triggerParams initial parameters for this event
124+
* @param {object} initialTriggerParams initial parameters for this event
125125
* @param {string} actionsToInsert actions to add at the start of the event
126126
*/
127-
async handleData(triggerId, triggerParams, actionsToInsert) {
128-
triggerParams = triggerParams || {};
129-
triggerParams['_kc_event_id_'] = uuidv4();
127+
async handleData(triggerId, initialTriggerParams, actionsToInsert) {
128+
initialTriggerParams = initialTriggerParams || {};
129+
var variables = await this.getParser('Variable').getVariables();
130+
var triggerParams = {
131+
"_kc_event_id_": uuidv4,
132+
...variables,
133+
...initialTriggerParams
134+
};
130135
actionsToInsert = actionsToInsert || [];
131136

132137
if (typeof(this.triggerAsyncMap[triggerId]) !== "undefined") {
@@ -523,40 +528,38 @@ class Controller {
523528
var triggerSequence = [];
524529
data = data.trim();
525530
var lines = data.split(/\r\n|\n/);
531+
var allLineData = Parser.parseCommands(lines);
526532

527533
// Parse all lines
528-
for (var i = 0; i < lines.length; i++) {
529-
var line = lines[i].trim();
530-
if (!line.startsWith('#')) {
531-
var lineData = Parser.splitLine(line);
532-
var dataLength = lineData.length;
533-
534-
// Get new trigger value
535-
if (dataLength > 0 && !currentParser) {
536-
currentParser = this.getTrigger(lineData[0]);
537-
triggerSequence = [lineData];
538-
}
539-
// Combine trigger data together
540-
else if (dataLength > 0 && currentParser) {
541-
triggerSequence.push(lineData);
534+
for (var i = 0; i < allLineData.length; i++) {
535+
var lineData = allLineData[i];
536+
var dataLength = lineData.length;
537+
538+
// Get new trigger value
539+
if (dataLength > 0 && !currentParser) {
540+
currentParser = this.getTrigger(lineData[0]);
541+
triggerSequence = [lineData];
542+
}
543+
// Combine trigger data together
544+
else if (dataLength > 0 && currentParser) {
545+
triggerSequence.push(lineData);
546+
}
547+
// Clear trigger if found empty line
548+
else if (dataLength === 0 && currentParser) {
549+
var parser = this.getParser(currentParser)
550+
if (parser) {
551+
parser.addTriggerData(triggerSequence[0][0], triggerSequence[0], this.triggerCount);
552+
triggerIds.push(this.triggerCount);
553+
this.triggerData[this.triggerCount] = triggerSequence.slice(1);
554+
this.triggerCount = this.triggerCount + 1;
542555
}
543-
// Clear trigger if found empty line
544-
else if (dataLength === 0 && currentParser) {
545-
var parser = this.getParser(currentParser)
546-
if (parser) {
547-
parser.addTriggerData(triggerSequence[0][0], triggerSequence[0], this.triggerCount);
548-
triggerIds.push(this.triggerCount);
549-
this.triggerData[this.triggerCount] = triggerSequence.slice(1);
550-
this.triggerCount = this.triggerCount + 1;
551-
}
552556

553-
currentParser = null;
554-
triggerSequence = [];
555-
}
556-
// Ensure clear trigger data if no trigger
557-
else if (!currentParser) {
558-
triggerSequence = [];
559-
}
557+
currentParser = null;
558+
triggerSequence = [];
559+
}
560+
// Ensure clear trigger data if no trigger
561+
else if (!currentParser) {
562+
triggerSequence = [];
560563
}
561564
}
562565
// Add data if no trailing newline in file

js/parser.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,57 @@ class Parser {
1414
return items;
1515
}
1616

17+
/**
18+
* Parse the file contents into a list of commands.
19+
* Primarily to account for multi-line strings in trigger files.
20+
* @param {array} lines file content containing commands
21+
*/
22+
static parseCommands(lines) {
23+
var compiledLineData = [];
24+
for (var i = 0; i < lines.length; i++) {
25+
var line = lines[i].trim();
26+
if (!line.startsWith('#')) {
27+
var [isParsed, lineData] = Parser.tryParseCommand(line);
28+
29+
// If failed to parse, look for a multi-line input
30+
if (!isParsed) {
31+
var j = i;
32+
var compiledLine = lines[i];
33+
while(!isParsed && j < lines.length) {
34+
j++;
35+
var compiledLine = `${compiledLine}\n${lines[j]}`;
36+
[isParsed, lineData] = Parser.tryParseCommand(compiledLine);
37+
}
38+
39+
// If no multi-line string found, simply split the line
40+
if (!isParsed) {
41+
lineData = line.split(' ');
42+
} else {
43+
// Skip all lines in the multi-line string
44+
i = j;
45+
}
46+
}
47+
48+
compiledLineData.push(lineData);
49+
}
50+
}
51+
52+
return compiledLineData;
53+
}
54+
55+
/**
56+
* Try to parse the input string using the shlex parsing library.
57+
* @param {string} data input string to parse for commands
58+
*/
59+
static tryParseCommand(data) {
60+
try {
61+
var commandData = shlexSplit(data);
62+
return [true, commandData];
63+
} catch (err) {
64+
return [false, null];
65+
}
66+
}
67+
1768
/**
1869
* Get the action from the input line information.
1970
* @param {array} lineData input to grab the action

js/twitch/twitch-api.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,14 +238,24 @@ class TwitchAPI {
238238
});
239239
}
240240

241-
async startCommercial(broadcaster_id, length) {
241+
async startCommercial(data) {
242242
await this.callTwitchApiJson({
243243
method: 'POST',
244244
endpoint: 'https://api.twitch.tv/helix/channels/commercial',
245245
data
246246
});
247247
}
248248

249+
async getAdSchedule(broadcaster_id) {
250+
return await this.callTwitchApi({
251+
method: 'GET',
252+
endpoint: 'https://api.twitch.tv/helix/channels/ads',
253+
params: {
254+
broadcaster_id
255+
}
256+
});
257+
}
258+
249259
async getBitsLeaderboard(params) {
250260
return await this.callTwitchApi({
251261
method: 'GET',

0 commit comments

Comments
 (0)