Skip to content

Commit 8c185e9

Browse files
authored
Beta 2 - QoL (#479)
* prepare Recipe "TriggerRandom" Payload to accept "actions by tag" * QoL: Recipe Tooltips - Show ActionList entries with Icon+Name * Refactor the Action Assignment Dialog * QoL: if new action dialog is opened with a type - we can skip the type selection * reset checkedMap on a single action assigning mode * ActionList Config - able to choose by Tag - or - choose multiple in one dialog * dont use a play length on media that doesnt need it * new recipe command block - full item as button * connection list now hides an invalid "token valid date" * obs connection now doesn't react on settings changes other than obs + log twitch auth validation * fix some deepsource issues
1 parent 430dfbb commit 8c185e9

File tree

106 files changed

+1199
-579
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

106 files changed

+1199
-579
lines changed

CHANGELOG.md

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,42 @@
11
## 2022.1 to be released
22

3+
### Feature
4+
5+
* [ ] Show Errors in the Dashboard - incl. a way to create a GitHub Issue from that
6+
* [ ] Tell the Streamer with warnings / dialogs that the Token will expire in X Days
7+
* [ ] Ability to re-authenticate even when you are not in the normal ports
8+
* [ ] Twitch Auth: Improve custom scopes handling
9+
* [ ] Recipe: more Twitch Command Blocks: Announce, Clear Chat, Start Commercial, Create Stream Marker, Slow Mode, Chat Settings
10+
* [ ] Recipe: more Obs Command Blocks: TBD
11+
* [ ] if easy/fast todo: Support for new OBS-websocket(.js) v5
12+
13+
### Misc
14+
15+
* [ ] Added a Twitch Raid Script Example
16+
* [ ] Recipe Example: Panic Button
17+
18+
## 2022.1-beta2
19+
20+
### Feature
21+
22+
* [x] Recipe "Trigger random action" - now you can select actions based on a Tag
23+
* [x] Recipe "Trigger random action" - now you can select multiple actions at the same time
24+
25+
### Changes
26+
27+
* [x] Recipe "Trigger random action" - now shows the Actions in a vertical list instead of comma separated
28+
* [x] Action Settings: Added a hint why a screen time is needed or can stay empty
29+
* [x] When the Twitch Token is close to be invalid, show a warning in console
30+
31+
### Quality of Life
32+
33+
* [x] When creating a new action, the dialog will jump already into the Action Settings
34+
* [x] Added a few Tooltips in the Recipe Dialog
35+
* [x] Recipe new Command Block full entry is now a button
36+
* [x] When you authenticate it'll be automatically saved
37+
38+
## 2022.1-beta1
39+
340
### Breaking Changes
441

542
* [x] The Headless Mode will not open the browser on start anymore, use `--open=true` for that
@@ -54,7 +91,7 @@
5491
* [x] The Arrange View was redesigned by `@owehmer`
5592
* [x] "HTML" is now renamed to "Widgets"
5693
* [x] "Media" is now renamed to "Actions"
57-
* [ ] Overhaul of the Media Creation Dialog(s)
94+
* [x] Overhaul of the Media Creation Dialog(s)
5895

5996

6097
## 2021.2.1

projects/action-variables-ui/src/lib/action-variable-input/action-variable-input.component.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
2-
import { DialogService } from "../../../../../src/app/shared/dialogs/dialog.service";
3-
import { ClipAssigningMode } from "@memebox/contracts";
4-
import { BehaviorSubject, combineLatest } from "rxjs";
5-
import { AppQueries } from "@memebox/app-state";
6-
import { map } from "rxjs/operators";
7-
import { ActionVariableTypes } from "@memebox/action-variables";
1+
import {Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges} from '@angular/core';
2+
import {DialogService} from "../../../../../src/app/shared/dialogs/dialog.service";
3+
import {ActionAssigningMode} from "@memebox/contracts";
4+
import {BehaviorSubject, combineLatest} from "rxjs";
5+
import {AppQueries} from "@memebox/app-state";
6+
import {map} from "rxjs/operators";
7+
import {ActionVariableTypes} from "@memebox/action-variables";
88

99
@Component({
1010
selector: 'app-action-variable-input',
@@ -59,9 +59,9 @@ export class ActionVariableInputComponent implements OnInit, OnChanges {
5959
}
6060

6161
async selectSingleMedia() {
62-
const actionId = await this.dialogService.showActionSelectionDialogAsync({
63-
mode: ClipAssigningMode.Single,
64-
selectedItemId: this.visibleActionIdList$.value[0] ?? null,
62+
const [actionId] = await this.dialogService.showActionSelectionDialogAsync({
63+
mode: ActionAssigningMode.Single,
64+
selectedActionIdList: this.visibleActionIdList$.value,
6565
dialogTitle: 'Action Variable',
6666
showMetaItems: true,
6767

projects/app-state/src/lib/services/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export * from '../services.module';
1+
export * from './config.service';
22
export * from './snackbar.service';
33
export * from './network-interfaces.service';
44
export * from './memebox-websocket.service';

projects/app-state/src/lib/state/app.service.ts

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ export class AppService {
234234
this.snackbar.normal('Media saved!');
235235
}
236236

237-
public async addOrUpdateScreenClip(screenId: string, screenClip: Partial<ScreenMedia>) {
237+
public async addOrUpdateScreenMedia(screenId: string, screenClip: Partial<ScreenMedia>) {
238238
screenClip = fillDefaultsScreenClip(screenClip);
239239

240240
// add the action to api & await
@@ -249,6 +249,47 @@ export class AppService {
249249

250250
this.snackbar.normal(`Media ${wasAlreadyAdded ? 'Settings updated' : 'added to screen'}!`);
251251
}
252+
public async addOrUpdateAssignedScreenMediaInBulk(
253+
screenId: string,
254+
addedScreenMediaIdList: string[],
255+
deletedScreenMediaIdList: string[],
256+
) {
257+
// TODO create Endpoint to update this completely in the backend
258+
259+
for (const mediaId of deletedScreenMediaIdList) {
260+
// send the api call
261+
await this.memeboxApi.delete(`${ENDPOINTS.SCREEN}/${screenId}/${ENDPOINTS.OBS_CLIPS}/${mediaId}`);
262+
}
263+
264+
const addedScreenMedia: ScreenMedia[] = [];
265+
266+
for (const mediaId of addedScreenMediaIdList) {
267+
const screenMedia: ScreenMedia = {
268+
id: mediaId,
269+
visibility: VisibilityEnum.Play
270+
};
271+
// add the action to api & await
272+
await this.memeboxApi.put(
273+
`${ENDPOINTS.SCREEN}/${screenId}/${ENDPOINTS.OBS_CLIPS}/${mediaId}`,
274+
screenMedia
275+
);
276+
addedScreenMedia.push(screenMedia);
277+
}
278+
279+
// add to the state
280+
this.appStore.update(state => {
281+
for (const mediaId of deletedScreenMediaIdList) {
282+
delete state.screen[screenId].clips[mediaId];
283+
}
284+
285+
for (const media of addedScreenMedia) {
286+
addOrUpdateScreenClip(state, screenId, media);
287+
}
288+
});
289+
290+
// todo rename those snackbars
291+
this.snackbar.normal(`Updated assigned Screen Items`);
292+
}
252293

253294
// TODO rename action and screenclip settings
254295
public async addOrUpdateScreenActionInBulk(screenId: string, changedActions: Partial<ScreenMedia>[]) {
@@ -268,7 +309,7 @@ export class AppService {
268309
this.snackbar.normal(`Screen Media Settings updated!`);
269310
}
270311

271-
public async deleteScreenClip(screenId: string, id: string) {
312+
public async deleteScreenMedia(screenId: string, id: string) {
272313
// send the api call
273314
await this.memeboxApi.delete(`${ENDPOINTS.SCREEN}/${screenId}/${ENDPOINTS.OBS_CLIPS}/${id}`);
274315

projects/contracts/src/lib/dialogs-contracts.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
export enum ClipAssigningMode {
2+
export enum ActionAssigningMode {
33
Multiple,
44
Single
55
}

projects/contracts/src/lib/types.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,12 @@ export interface Tag extends HasId {
225225
color: string;
226226
}
227227

228+
export interface UserDataState {
229+
actions: Dictionary<Action>;
230+
screen: Dictionary<Screen>;
231+
tags: Dictionary<Tag>;
232+
}
233+
228234
/**
229235
* Settings.json - State
230236
*
@@ -266,6 +272,9 @@ export interface Config {
266272

267273
export interface TwitchConfig {
268274
channel: string;
275+
/**
276+
* @deprecated might need to be deleted
277+
*/
269278
enableLog?: boolean;
270279
bot?: TwitchBotConfig;
271280
token: string|null;
@@ -341,7 +350,7 @@ export interface ChangedInfo {
341350
id?: string;
342351
targetScreenId?: string;
343352
dataType: 'everything'|'action'|'tags'|'screens'|'screen-action-config'
344-
|'settings'|'twitch-events'|'timers'|'twitch-setting';
353+
|'settings'|'twitch-events'|'timers'|'twitch-setting'|'obs-settings';
345354
actionType?: ActionType;
346355
changeType: 'added'|'changed'|'removed';
347356
}
@@ -396,3 +405,12 @@ export interface ObsSourceFilterEntry {
396405
name: string;
397406
settings: Record<string, unknown>;
398407
}
408+
409+
410+
export function getUserDataState (settings: SettingsState): UserDataState {
411+
return {
412+
actions: settings.clips,
413+
screen: settings.screen,
414+
tags: settings.tags
415+
}
416+
}

projects/recipe-core/src/lib/command-blocks.memebox.ts

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ import {
55
RecipeCommandConfigActionPayload
66
} from "./recipe.types";
77
import {map, take} from "rxjs/operators";
8-
import {generateRandomCharacters} from "./utils";
9-
import {combineLatest} from "rxjs";
8+
import {generateRandomCharacters, listActionsOfActionListPayload} from "./utils";
109
import {ACTION_TYPE_INFORMATION} from "@memebox/contracts";
1110

1211
function createMemeboxApiVariable(
@@ -104,14 +103,14 @@ export function registerMemeboxCommandBlocks (
104103
entries: []
105104
});
106105
},
107-
toScriptCode: (step, context) => {
106+
toScriptCode: (step, context, userData) => {
108107
const actionPayload = step.payload.action as RecipeCommandConfigActionPayload;
109108

110109
const actionOverrides = actionPayload.overrides;
111110

112111
return `${createMemeboxApiVariable(actionPayload)}
113112
.triggerWhile(async (helpers_${step.payload._suffix}) => {
114-
${generateCodeByStep(step, context)}
113+
${generateCodeByStep(step, context, userData)}
115114
}
116115
${actionOverrides ? ',' + JSON.stringify(actionOverrides) : ''});`;
117116
},
@@ -157,36 +156,38 @@ export function registerMemeboxCommandBlocks (
157156
}
158157
],
159158
awaitCodeHandledInternally: true,
160-
toScriptCode: (step) => {
159+
toScriptCode: (step, context, userData) => {
161160
const awaitCode = step.awaited ? 'await ': '';
162161

162+
const actionsToChooseFrom = listActionsOfActionListPayload(
163+
step.payload.actions as RecipeCommandConfigActionListPayload,
164+
userData
165+
);
166+
163167
return `
164168
${awaitCode} (() => {
165-
const actionsToChooseFrom = [${
166-
(step.payload.actions as RecipeCommandConfigActionListPayload)
167-
.map(action => JSON.stringify(action))
168-
.join(',')
169-
}];
169+
const actionsToChooseFrom = [${actionsToChooseFrom
170+
.map(action => JSON.stringify(action))
171+
.join(',')}];
170172
171173
return memebox.triggerRandom(actionsToChooseFrom);
172174
})();
173175
`;
174176
},
175177
commandEntryLabelAsync: async (queries, payload) => {
176-
const actionPayload = payload.actions as RecipeCommandConfigActionPayload[];
178+
const actionListPayload = (payload.actions as RecipeCommandConfigActionListPayload);
177179

178-
const namesOfActions = await combineLatest(
179-
actionPayload.map(a => queries.getActionById$(a.actionId).pipe(
180-
map(actionInfo => actionInfo?.name ?? 'unknown action'),
180+
if (actionListPayload.actionsByTag) {
181+
const tags = await queries.tagList$.pipe(
181182
take(1)
182-
))
183-
)
184-
.pipe(
185-
map(allNames => allNames.join(','))
186-
)
187-
.toPromise();
188-
189-
return 'trigger random: '+ namesOfActions;
183+
).toPromise();
184+
const tagName = tags.find(t => t.id === actionListPayload.actionsByTag)?.name
185+
?? `\r\nUnknown Tag: ${actionListPayload.actionsByTag}`;
186+
187+
return `trigger any action with the tag: ${tagName}`;
188+
}
189+
190+
return `trigger any of the following: ${actionListPayload.selectedActions.length}`;
190191
},
191192
};
192193

projects/recipe-core/src/lib/generateCodeByRecipe.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ import {uuid} from "@gewd/utils";
1010
import {registerMemeboxCommandBlocks} from "./command-blocks.memebox";
1111
import {registerObsCommandBlocks} from "./command-blocks.obs";
1212
import {registerTwitchCommandBlocks} from "./command-blocks.twitch";
13+
import {UserDataState} from "@memebox/contracts";
1314

1415
export interface RecipeStepConfigArgument {
1516
name: string;
1617
label: string;
17-
type: string;
18+
type: string; // todo change to the enum
1819
}
1920

2021
export const RecipeCommandBlockGroups: Record<string, RecipeCommandSelectionGroup> = {
@@ -51,6 +52,7 @@ export const RecipeCommandRegistry: RecipeCommandBlockRegistry = {
5152
commandEntryLabelAsync: (queries, payload, parentStep) => {
5253
return Promise.resolve(`sleep: ${payload.seconds} seconds`);
5354
},
55+
entryIcon: () => 'hourglass_top'
5456
},
5557
"sleepMs": {
5658
pickerLabel: "Wait for Milliseconds",
@@ -66,11 +68,12 @@ export const RecipeCommandRegistry: RecipeCommandBlockRegistry = {
6668
commandEntryLabelAsync: (queries, payload, parentStep) => {
6769
return Promise.resolve(`sleep: ${payload.ms}ms`);
6870
},
71+
entryIcon: () => 'hourglass_top'
6972
}
7073
};
7174

7275

73-
function generateCodeByStep (step: RecipeEntry, context: RecipeContext) {
76+
function generateCodeByStepAsync (step: RecipeEntry, context: RecipeContext, userData: UserDataState): string {
7477
const result: string[] = [];
7578

7679
for (const subStepInfo of step.subCommandBlocks) {
@@ -88,7 +91,9 @@ function generateCodeByStep (step: RecipeEntry, context: RecipeContext) {
8891
result.push('await ');
8992
}
9093

91-
result.push(entryDefinition.toScriptCode(subEntry, context).trim());
94+
const createdStepCode = entryDefinition.toScriptCode(subEntry, context, userData);
95+
96+
result.push(createdStepCode.trim());
9297

9398
// result.push(`logger.log('Post: ${subEntry.commandType}');`);
9499
} else {
@@ -102,13 +107,13 @@ function generateCodeByStep (step: RecipeEntry, context: RecipeContext) {
102107
}
103108

104109
export function generateCodeByRecipe(
105-
recipeContext: RecipeContext
110+
recipeContext: RecipeContext, userData: UserDataState
106111
): string {
107112
const result: string[] = [];
108113

109114
const rootEntry = recipeContext.entries[recipeContext.rootEntry];
110115

111-
result.push(generateCodeByStep(rootEntry, recipeContext));
116+
result.push(generateCodeByStepAsync(rootEntry, recipeContext, userData));
112117

113118
return result.join('\r\n');
114119
}
@@ -127,6 +132,6 @@ export function generateRecipeEntryCommandCall (
127132
};
128133
}
129134

130-
registerMemeboxCommandBlocks(RecipeCommandRegistry, generateCodeByStep);
135+
registerMemeboxCommandBlocks(RecipeCommandRegistry, generateCodeByStepAsync);
131136
registerObsCommandBlocks(RecipeCommandRegistry);
132137
registerTwitchCommandBlocks(RecipeCommandRegistry);

0 commit comments

Comments
 (0)