@lumiastream/ui 0.5.2 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/LSButton.js +1 -1
- package/dist/LSCheckbox.js +1 -1
- package/dist/LSColorPicker.js +1 -1
- package/dist/LSDatePicker.js +1 -1
- package/dist/LSFontPicker.js +1 -1
- package/dist/LSInput.js +1 -1
- package/dist/LSMultiSelect.js +1 -1
- package/dist/LSRadio.js +1 -1
- package/dist/LSSelect.js +1 -1
- package/dist/LSSliderInput.js +1 -1
- package/dist/LSTextField.js +1 -1
- package/dist/LSVariableInputField.js +1 -1
- package/dist/components.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +869 -466
- package/dist/se-import.d.ts +9 -3
- package/dist/se-import.js +868 -465
- package/package.json +1 -1
package/dist/se-import.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/se-import/index.ts
|
|
2
|
-
import { nanoid as
|
|
2
|
+
import { nanoid as nanoid8 } from "nanoid";
|
|
3
3
|
|
|
4
4
|
// src/se-import/translate.ts
|
|
5
5
|
var SE_TO_LUMIA_PLACEHOLDER = {
|
|
@@ -1064,12 +1064,26 @@ function mapImage(widget, ctx) {
|
|
|
1064
1064
|
);
|
|
1065
1065
|
const innerWidth = widget.image?.css?.width;
|
|
1066
1066
|
const innerHeight = widget.image?.css?.height;
|
|
1067
|
+
const outerWidthExplicit = isExplicitPxSize(widget.css?.width);
|
|
1068
|
+
const outerHeightExplicit = isExplicitPxSize(widget.css?.height);
|
|
1067
1069
|
const bounds = unit.layer.bounds;
|
|
1068
|
-
if (innerWidth === "auto") bounds.autoWidth = true;
|
|
1069
|
-
if (innerHeight === "auto") bounds.autoHeight = true;
|
|
1070
|
+
if (innerWidth === "auto" && !outerWidthExplicit) bounds.autoWidth = true;
|
|
1071
|
+
if (innerHeight === "auto" && !outerHeightExplicit) bounds.autoHeight = true;
|
|
1070
1072
|
return unit;
|
|
1071
1073
|
}
|
|
1074
|
+
function isExplicitPxSize(value) {
|
|
1075
|
+
if (value == null) return false;
|
|
1076
|
+
if (typeof value === "number") return Number.isFinite(value) && value > 0;
|
|
1077
|
+
if (typeof value !== "string") return false;
|
|
1078
|
+
const s = value.trim().toLowerCase();
|
|
1079
|
+
if (s === "" || s === "auto") return false;
|
|
1080
|
+
if (s.endsWith("%")) return false;
|
|
1081
|
+
const parsed = parseFloat(s);
|
|
1082
|
+
return Number.isFinite(parsed) && parsed > 0;
|
|
1083
|
+
}
|
|
1072
1084
|
function mapVideo(widget, ctx) {
|
|
1085
|
+
const innerWidth = widget.video?.css?.width;
|
|
1086
|
+
const isInnerAutoWidth = innerWidth === "auto";
|
|
1073
1087
|
const unit = buildUnit(
|
|
1074
1088
|
widget,
|
|
1075
1089
|
"video",
|
|
@@ -1078,12 +1092,19 @@ function mapVideo(widget, ctx) {
|
|
|
1078
1092
|
src: widget.video?.src ?? "",
|
|
1079
1093
|
volume: widget.video?.volume ?? 0.5,
|
|
1080
1094
|
loop: true,
|
|
1081
|
-
muted: false
|
|
1095
|
+
muted: false,
|
|
1096
|
+
...isInnerAutoWidth ? { objectFit: "contain" } : {}
|
|
1082
1097
|
}
|
|
1083
1098
|
},
|
|
1084
1099
|
ctx
|
|
1085
1100
|
);
|
|
1086
|
-
unit.layer.bounds
|
|
1101
|
+
const bounds = unit.layer.bounds;
|
|
1102
|
+
if (isInnerAutoWidth) {
|
|
1103
|
+
bounds.autoWidth = true;
|
|
1104
|
+
bounds.autoHeight = true;
|
|
1105
|
+
} else {
|
|
1106
|
+
bounds.autoHeight = true;
|
|
1107
|
+
}
|
|
1087
1108
|
return unit;
|
|
1088
1109
|
}
|
|
1089
1110
|
var LUMIA_SNOW_WEBM = "https://storage.lumiastream.com/overlays/global/seasonal/snow.webm";
|
|
@@ -1142,118 +1163,157 @@ function mapReadout(widget, fallbackVar, ctx) {
|
|
|
1142
1163
|
|
|
1143
1164
|
// src/se-import/mappers/alert.ts
|
|
1144
1165
|
import { LumiaAlertConfigs } from "@lumiastream/lumia-types";
|
|
1166
|
+
import { nanoid as nanoid2 } from "nanoid";
|
|
1167
|
+
|
|
1168
|
+
// src/se-import/import-utils.ts
|
|
1169
|
+
function pxToNumber(raw, fallback) {
|
|
1170
|
+
if (typeof raw === "number" && Number.isFinite(raw)) return raw;
|
|
1171
|
+
if (typeof raw !== "string") return fallback;
|
|
1172
|
+
const trimmed = raw.trim();
|
|
1173
|
+
if (!trimmed) return fallback;
|
|
1174
|
+
if (trimmed.endsWith("px")) {
|
|
1175
|
+
const n2 = parseFloat(trimmed.slice(0, -2));
|
|
1176
|
+
return Number.isFinite(n2) ? n2 : fallback;
|
|
1177
|
+
}
|
|
1178
|
+
const n = parseFloat(trimmed);
|
|
1179
|
+
return Number.isFinite(n) ? n : fallback;
|
|
1180
|
+
}
|
|
1181
|
+
function parseDurationMs(raw, fallbackMs) {
|
|
1182
|
+
if (typeof raw === "number" && Number.isFinite(raw)) return raw;
|
|
1183
|
+
if (typeof raw !== "string") return fallbackMs;
|
|
1184
|
+
const trimmed = raw.trim();
|
|
1185
|
+
if (!trimmed) return fallbackMs;
|
|
1186
|
+
if (trimmed.endsWith("ms")) {
|
|
1187
|
+
const n2 = parseFloat(trimmed.slice(0, -2));
|
|
1188
|
+
return Number.isFinite(n2) ? n2 : fallbackMs;
|
|
1189
|
+
}
|
|
1190
|
+
if (trimmed.endsWith("s")) {
|
|
1191
|
+
const n2 = parseFloat(trimmed.slice(0, -1));
|
|
1192
|
+
return Number.isFinite(n2) ? n2 * 1e3 : fallbackMs;
|
|
1193
|
+
}
|
|
1194
|
+
const n = parseFloat(trimmed);
|
|
1195
|
+
return Number.isFinite(n) ? n : fallbackMs;
|
|
1196
|
+
}
|
|
1197
|
+
function buildImportDescription(head, sourceUrl) {
|
|
1198
|
+
if (typeof sourceUrl === "string" && sourceUrl.trim().length > 0) {
|
|
1199
|
+
return `${head}
|
|
1200
|
+
Source: ${sourceUrl.trim()}`;
|
|
1201
|
+
}
|
|
1202
|
+
return head;
|
|
1203
|
+
}
|
|
1145
1204
|
|
|
1146
1205
|
// src/se-import/mappers/provider-alerts.ts
|
|
1206
|
+
import { LumiaAlertValues } from "@lumiastream/lumia-types";
|
|
1147
1207
|
var ALERT_BOX_KEYS = {
|
|
1148
1208
|
twitch: {
|
|
1149
|
-
follower: [
|
|
1150
|
-
subscriber: [
|
|
1151
|
-
tip: [
|
|
1152
|
-
cheer: [
|
|
1153
|
-
raid: [
|
|
1154
|
-
merch: [
|
|
1155
|
-
purchase: [
|
|
1156
|
-
charityCampaignDonation: [
|
|
1209
|
+
follower: [LumiaAlertValues.TWITCH_FOLLOWER],
|
|
1210
|
+
subscriber: [LumiaAlertValues.TWITCH_SUBSCRIBER],
|
|
1211
|
+
tip: [LumiaAlertValues.LUMIASTREAM_DONATION, LumiaAlertValues.STREAMELEMENTS_DONATION],
|
|
1212
|
+
cheer: [LumiaAlertValues.TWITCH_BITS],
|
|
1213
|
+
raid: [LumiaAlertValues.TWITCH_RAID],
|
|
1214
|
+
merch: [LumiaAlertValues.FOURTHWALL_SHOPORDER],
|
|
1215
|
+
purchase: [LumiaAlertValues.FOURTHWALL_SHOPORDER],
|
|
1216
|
+
charityCampaignDonation: [LumiaAlertValues.TWITCH_CHARITY_DONATION]
|
|
1157
1217
|
},
|
|
1158
1218
|
kick: {
|
|
1159
|
-
follower: [
|
|
1160
|
-
subscriber: [
|
|
1161
|
-
tip: [
|
|
1162
|
-
cheer: [
|
|
1163
|
-
raid: [
|
|
1164
|
-
host: [
|
|
1165
|
-
merch: [
|
|
1166
|
-
purchase: [
|
|
1219
|
+
follower: [LumiaAlertValues.KICK_FOLLOWER],
|
|
1220
|
+
subscriber: [LumiaAlertValues.KICK_SUBSCRIBER],
|
|
1221
|
+
tip: [LumiaAlertValues.LUMIASTREAM_DONATION, LumiaAlertValues.STREAMELEMENTS_DONATION],
|
|
1222
|
+
cheer: [LumiaAlertValues.KICK_KICKS],
|
|
1223
|
+
raid: [LumiaAlertValues.KICK_HOST],
|
|
1224
|
+
host: [LumiaAlertValues.KICK_HOST],
|
|
1225
|
+
merch: [LumiaAlertValues.FOURTHWALL_SHOPORDER],
|
|
1226
|
+
purchase: [LumiaAlertValues.FOURTHWALL_SHOPORDER]
|
|
1167
1227
|
},
|
|
1168
1228
|
youtube: {
|
|
1169
|
-
follower: [
|
|
1170
|
-
subscriber: [
|
|
1171
|
-
tip: [
|
|
1172
|
-
cheer: [
|
|
1173
|
-
merch: [
|
|
1174
|
-
purchase: [
|
|
1229
|
+
follower: [LumiaAlertValues.YOUTUBE_SUBSCRIBER],
|
|
1230
|
+
subscriber: [LumiaAlertValues.YOUTUBE_MEMBER],
|
|
1231
|
+
tip: [LumiaAlertValues.LUMIASTREAM_DONATION, LumiaAlertValues.STREAMELEMENTS_DONATION],
|
|
1232
|
+
cheer: [LumiaAlertValues.YOUTUBE_SUPERCHAT],
|
|
1233
|
+
merch: [LumiaAlertValues.FOURTHWALL_SHOPORDER],
|
|
1234
|
+
purchase: [LumiaAlertValues.FOURTHWALL_SHOPORDER]
|
|
1175
1235
|
}
|
|
1176
1236
|
};
|
|
1177
1237
|
var KAPPAGEN_KEYS = {
|
|
1178
1238
|
twitch: {
|
|
1179
|
-
follower:
|
|
1180
|
-
subscriber:
|
|
1181
|
-
cheer:
|
|
1182
|
-
raid:
|
|
1183
|
-
tip:
|
|
1239
|
+
follower: LumiaAlertValues.TWITCH_FOLLOWER,
|
|
1240
|
+
subscriber: LumiaAlertValues.TWITCH_SUBSCRIBER,
|
|
1241
|
+
cheer: LumiaAlertValues.TWITCH_BITS,
|
|
1242
|
+
raid: LumiaAlertValues.TWITCH_RAID,
|
|
1243
|
+
tip: LumiaAlertValues.LUMIASTREAM_DONATION
|
|
1184
1244
|
},
|
|
1185
1245
|
kick: {
|
|
1186
|
-
follower:
|
|
1187
|
-
subscriber:
|
|
1188
|
-
cheer:
|
|
1189
|
-
raid:
|
|
1190
|
-
tip:
|
|
1246
|
+
follower: LumiaAlertValues.KICK_FOLLOWER,
|
|
1247
|
+
subscriber: LumiaAlertValues.KICK_SUBSCRIBER,
|
|
1248
|
+
cheer: LumiaAlertValues.KICK_KICKS,
|
|
1249
|
+
raid: LumiaAlertValues.KICK_HOST,
|
|
1250
|
+
tip: LumiaAlertValues.LUMIASTREAM_DONATION
|
|
1191
1251
|
},
|
|
1192
1252
|
youtube: {
|
|
1193
|
-
follower:
|
|
1194
|
-
subscriber:
|
|
1195
|
-
cheer:
|
|
1196
|
-
tip:
|
|
1253
|
+
follower: LumiaAlertValues.YOUTUBE_SUBSCRIBER,
|
|
1254
|
+
subscriber: LumiaAlertValues.YOUTUBE_MEMBER,
|
|
1255
|
+
cheer: LumiaAlertValues.YOUTUBE_SUPERCHAT,
|
|
1256
|
+
tip: LumiaAlertValues.LUMIASTREAM_DONATION
|
|
1197
1257
|
}
|
|
1198
1258
|
};
|
|
1199
1259
|
var STREAMBOSS_LISTENER_KEYS = {
|
|
1200
1260
|
twitch: {
|
|
1201
|
-
"follower-latest": [
|
|
1202
|
-
"subscriber-latest": [
|
|
1203
|
-
"tip-latest": [
|
|
1204
|
-
"cheer-latest": [
|
|
1205
|
-
"raid-latest": [
|
|
1261
|
+
"follower-latest": [LumiaAlertValues.TWITCH_FOLLOWER],
|
|
1262
|
+
"subscriber-latest": [LumiaAlertValues.TWITCH_SUBSCRIBER],
|
|
1263
|
+
"tip-latest": [LumiaAlertValues.LUMIASTREAM_DONATION, LumiaAlertValues.STREAMELEMENTS_DONATION],
|
|
1264
|
+
"cheer-latest": [LumiaAlertValues.TWITCH_BITS],
|
|
1265
|
+
"raid-latest": [LumiaAlertValues.TWITCH_RAID]
|
|
1206
1266
|
},
|
|
1207
1267
|
kick: {
|
|
1208
|
-
"follower-latest": [
|
|
1209
|
-
"subscriber-latest": [
|
|
1210
|
-
"tip-latest": [
|
|
1211
|
-
"cheer-latest": [
|
|
1212
|
-
"raid-latest": [
|
|
1268
|
+
"follower-latest": [LumiaAlertValues.KICK_FOLLOWER],
|
|
1269
|
+
"subscriber-latest": [LumiaAlertValues.KICK_SUBSCRIBER],
|
|
1270
|
+
"tip-latest": [LumiaAlertValues.LUMIASTREAM_DONATION, LumiaAlertValues.STREAMELEMENTS_DONATION],
|
|
1271
|
+
"cheer-latest": [LumiaAlertValues.KICK_KICKS],
|
|
1272
|
+
"raid-latest": [LumiaAlertValues.KICK_HOST]
|
|
1213
1273
|
},
|
|
1214
1274
|
youtube: {
|
|
1215
|
-
"follower-latest": [
|
|
1216
|
-
"subscriber-latest": [
|
|
1217
|
-
"tip-latest": [
|
|
1218
|
-
"cheer-latest": [
|
|
1275
|
+
"follower-latest": [LumiaAlertValues.YOUTUBE_SUBSCRIBER],
|
|
1276
|
+
"subscriber-latest": [LumiaAlertValues.YOUTUBE_MEMBER],
|
|
1277
|
+
"tip-latest": [LumiaAlertValues.LUMIASTREAM_DONATION, LumiaAlertValues.STREAMELEMENTS_DONATION],
|
|
1278
|
+
"cheer-latest": [LumiaAlertValues.YOUTUBE_SUPERCHAT]
|
|
1219
1279
|
}
|
|
1220
1280
|
};
|
|
1221
1281
|
var CURATED_ALERTS = {
|
|
1222
1282
|
twitch: [
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1283
|
+
LumiaAlertValues.TWITCH_FOLLOWER,
|
|
1284
|
+
LumiaAlertValues.TWITCH_SUBSCRIBER,
|
|
1285
|
+
LumiaAlertValues.TWITCH_GIFT_SUBSCRIPTION,
|
|
1286
|
+
LumiaAlertValues.TWITCH_BITS,
|
|
1287
|
+
LumiaAlertValues.TWITCH_BITS_COMBO,
|
|
1288
|
+
LumiaAlertValues.TWITCH_RAID,
|
|
1289
|
+
LumiaAlertValues.TWITCH_POINTS,
|
|
1290
|
+
LumiaAlertValues.TWITCH_REDEMPTION,
|
|
1291
|
+
LumiaAlertValues.TWITCH_CHARITY_DONATION,
|
|
1292
|
+
LumiaAlertValues.TWITCH_HYPETRAIN_STARTED,
|
|
1293
|
+
LumiaAlertValues.TWITCH_CLIP,
|
|
1294
|
+
LumiaAlertValues.TWITCH_SHOUTOUT_RECEIVE,
|
|
1295
|
+
LumiaAlertValues.TWITCH_WATCH_STREAK,
|
|
1296
|
+
LumiaAlertValues.TWITCH_FIRST_CHATTER,
|
|
1297
|
+
LumiaAlertValues.TWITCH_EXTENSION
|
|
1238
1298
|
],
|
|
1239
1299
|
kick: [
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1300
|
+
LumiaAlertValues.KICK_FOLLOWER,
|
|
1301
|
+
LumiaAlertValues.KICK_SUBSCRIBER,
|
|
1302
|
+
LumiaAlertValues.KICK_GIFT_SUBSCRIPTION,
|
|
1303
|
+
LumiaAlertValues.KICK_KICKS,
|
|
1304
|
+
LumiaAlertValues.KICK_HOST,
|
|
1305
|
+
LumiaAlertValues.KICK_POINTS,
|
|
1306
|
+
LumiaAlertValues.KICK_FIRST_CHATTER
|
|
1247
1307
|
],
|
|
1248
1308
|
youtube: [
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1309
|
+
LumiaAlertValues.YOUTUBE_SUBSCRIBER,
|
|
1310
|
+
LumiaAlertValues.YOUTUBE_MEMBER,
|
|
1311
|
+
LumiaAlertValues.YOUTUBE_GIFT_MEMBERS,
|
|
1312
|
+
LumiaAlertValues.YOUTUBE_SUPERCHAT,
|
|
1313
|
+
LumiaAlertValues.YOUTUBE_SUPERSTICKER,
|
|
1314
|
+
LumiaAlertValues.YOUTUBE_GIFTS,
|
|
1315
|
+
LumiaAlertValues.YOUTUBE_LIKE,
|
|
1316
|
+
LumiaAlertValues.YOUTUBE_FIRST_CHATTER
|
|
1257
1317
|
]
|
|
1258
1318
|
};
|
|
1259
1319
|
function curatedAlertsFor(provider = "twitch") {
|
|
@@ -1321,8 +1381,12 @@ function buildAlertEvent(seEvent, seEventType) {
|
|
|
1321
1381
|
const shadowEnabled = text.enableShadow !== false;
|
|
1322
1382
|
const importedTextShadow = css["text-shadow"] ?? "rgba(0, 0, 0, 0.8) 1px 1px 1px";
|
|
1323
1383
|
const textShadow = shadowEnabled ? importedTextShadow : "none";
|
|
1324
|
-
const
|
|
1325
|
-
const pushTextUp =
|
|
1384
|
+
const allowPush = seLayoutUsesPushText(seEvent.layout);
|
|
1385
|
+
const pushTextUp = allowPush ? pxToNumber(css["margin-top"], 0) : 0;
|
|
1386
|
+
const pushTextLeft = allowPush ? pxToNumber(css["margin-left"], 0) : 0;
|
|
1387
|
+
const usesColumnLayout = !seEvent.layout || seEvent.layout === "column";
|
|
1388
|
+
const usesRowLayout = seEvent.layout === "row";
|
|
1389
|
+
const tightLayout = allowPush && (usesColumnLayout || usesRowLayout);
|
|
1326
1390
|
const variations = (seEvent.variations ?? []).map((variation) => buildAlertVariation(variation, seEventType, seEvent)).filter((v) => v != null);
|
|
1327
1391
|
const defaultDuration = (seEventType && SE_DEFAULT_DURATION_BY_EVENT[seEventType]) ?? 8;
|
|
1328
1392
|
return {
|
|
@@ -1349,7 +1413,7 @@ function buildAlertEvent(seEvent, seEventType) {
|
|
|
1349
1413
|
showBrandIcon: true
|
|
1350
1414
|
},
|
|
1351
1415
|
settings: { duration: (seEvent.duration ?? defaultDuration) * 1e3 },
|
|
1352
|
-
layout: { value: translateLayout(seEvent.layout), css: {}, customCss: "", pushTextUp, pushTextLeft:
|
|
1416
|
+
layout: { value: translateLayout(seEvent.layout), css: {}, customCss: "", pushTextUp, pushTextLeft, tight: tightLayout },
|
|
1353
1417
|
text: {
|
|
1354
1418
|
css: {
|
|
1355
1419
|
fontFamily: css["font-family"] ?? "Roboto",
|
|
@@ -1358,6 +1422,10 @@ function buildAlertEvent(seEvent, seEventType) {
|
|
|
1358
1422
|
fontWeight: css["font-weight"] ?? "bold",
|
|
1359
1423
|
textShadow,
|
|
1360
1424
|
textAlign: css["text-align"] ?? "center"
|
|
1425
|
+
// SE's per-event `margin-top` / `margin-left` are routed to
|
|
1426
|
+
// `layout.pushTextUp` / `layout.pushTextLeft` above (not
|
|
1427
|
+
// stamped on `text.css`) so they land in the alert editor's
|
|
1428
|
+
// dedicated sliders. See the long comment near `pushTextUp`.
|
|
1361
1429
|
},
|
|
1362
1430
|
messageCss,
|
|
1363
1431
|
content: { value: translateSeText(text.message ?? "") }
|
|
@@ -1427,6 +1495,15 @@ function buildAlertVariation(v, seEventType, parentSettings) {
|
|
|
1427
1495
|
const mergedSettings = deepMergeSeSettings(parentSettings ? parentInheritable : void 0, v.settings);
|
|
1428
1496
|
const base = buildAlertEvent(mergedSettings, seEventType);
|
|
1429
1497
|
return {
|
|
1498
|
+
// Stable per-variation ID. Lumia's alert editor (Settings.tsx) auto-
|
|
1499
|
+
// stamps a nanoid on first open for any variation missing an id, but
|
|
1500
|
+
// that leaves a window where the imported overlay's variations have
|
|
1501
|
+
// no stable key — list components rendering them key on
|
|
1502
|
+
// `variation.id || variation.name || idx` and adjacent variations
|
|
1503
|
+
// with the same name collide. Stamping at import time gives every
|
|
1504
|
+
// variation a stable identity from save #1 without waiting for the
|
|
1505
|
+
// editor's first mount.
|
|
1506
|
+
id: nanoid2(),
|
|
1430
1507
|
name: v.name ?? "Variation",
|
|
1431
1508
|
on: v.enabled !== false,
|
|
1432
1509
|
randomChance: v.chance ?? 100,
|
|
@@ -1510,7 +1587,7 @@ function mapSingleAlert(widget, lumiaAlertKey, ctx) {
|
|
|
1510
1587
|
css: { ...topCss, ...innerCss }
|
|
1511
1588
|
};
|
|
1512
1589
|
}
|
|
1513
|
-
const built = buildAlertEvent(merged);
|
|
1590
|
+
const built = buildAlertEvent(merged, void 0);
|
|
1514
1591
|
const events = {
|
|
1515
1592
|
[lumiaAlertKey]: built
|
|
1516
1593
|
};
|
|
@@ -1656,7 +1733,7 @@ function mapGoal(widget, ctx) {
|
|
|
1656
1733
|
}
|
|
1657
1734
|
|
|
1658
1735
|
// src/se-import/mappers/custom.ts
|
|
1659
|
-
import { nanoid as
|
|
1736
|
+
import { nanoid as nanoid3 } from "nanoid";
|
|
1660
1737
|
var SOURCE_TO_LUMIA_FIELD_TYPE = {
|
|
1661
1738
|
text: "input",
|
|
1662
1739
|
number: "number",
|
|
@@ -1746,7 +1823,7 @@ function mapCustom(widget, ctx) {
|
|
|
1746
1823
|
// imports — codeId is the scoping key for variables, storage, and
|
|
1747
1824
|
// event listeners. Mint a fresh nanoid so every imported widget
|
|
1748
1825
|
// has its own scope.
|
|
1749
|
-
codeId:
|
|
1826
|
+
codeId: nanoid3(),
|
|
1750
1827
|
html: v.html ?? "",
|
|
1751
1828
|
css: v.css ?? "",
|
|
1752
1829
|
js: v.js ?? "",
|
|
@@ -1883,6 +1960,63 @@ var TIPJAR_DEFAULT_MODULE = {
|
|
|
1883
1960
|
version: 1,
|
|
1884
1961
|
content: TIPJAR_DEFAULT_CONTENT_FIELDS
|
|
1885
1962
|
};
|
|
1963
|
+
var EVENTLIST_DEFAULT_CONTENT_FIELDS = {
|
|
1964
|
+
version: 2,
|
|
1965
|
+
eventListType: {},
|
|
1966
|
+
theme: "basic",
|
|
1967
|
+
themeConfig: {},
|
|
1968
|
+
borderRadius: "10px",
|
|
1969
|
+
condensedText: true,
|
|
1970
|
+
src: "",
|
|
1971
|
+
// Category blacklist — events whose Lumia type appears here are
|
|
1972
|
+
// hidden. SL `show_<type>: false` maps to inserting the equivalent
|
|
1973
|
+
// Lumia category here.
|
|
1974
|
+
filters: [],
|
|
1975
|
+
sites: [],
|
|
1976
|
+
maxItemsToShow: 20,
|
|
1977
|
+
removeAfter: 0,
|
|
1978
|
+
reverse: false,
|
|
1979
|
+
horizontal: false,
|
|
1980
|
+
animations: {
|
|
1981
|
+
enterAnimation: "fadeIn",
|
|
1982
|
+
exitAnimation: "fadeOut",
|
|
1983
|
+
enterAnimationDuration: 1e3,
|
|
1984
|
+
exitAnimationDuration: 1e3,
|
|
1985
|
+
enterAnimationDelay: 0,
|
|
1986
|
+
exitAnimationDelay: 0
|
|
1987
|
+
},
|
|
1988
|
+
showDetailedText: true,
|
|
1989
|
+
hideAlertMessage: false,
|
|
1990
|
+
showAlertIcon: true,
|
|
1991
|
+
showSiteIcon: false,
|
|
1992
|
+
showUserAvatar: false,
|
|
1993
|
+
fadeOutAfterDelay: false,
|
|
1994
|
+
fadeOutDelayTime: 5,
|
|
1995
|
+
image: "",
|
|
1996
|
+
itemGap: 16,
|
|
1997
|
+
audio: {
|
|
1998
|
+
enter: "",
|
|
1999
|
+
volume: 1
|
|
2000
|
+
}
|
|
2001
|
+
};
|
|
2002
|
+
var EVENTLIST_DEFAULT_MODULE = {
|
|
2003
|
+
version: 2,
|
|
2004
|
+
content: EVENTLIST_DEFAULT_CONTENT_FIELDS,
|
|
2005
|
+
css: {
|
|
2006
|
+
borderRadius: "0px",
|
|
2007
|
+
borderStyle: "solid",
|
|
2008
|
+
borderWidth: "0px",
|
|
2009
|
+
borderColor: "transparent",
|
|
2010
|
+
fontSize: 16,
|
|
2011
|
+
lineHeight: 1.2,
|
|
2012
|
+
textAlign: "left",
|
|
2013
|
+
fontFamily: "Roboto",
|
|
2014
|
+
fontWeight: "normal",
|
|
2015
|
+
color: "#ffffff",
|
|
2016
|
+
textShadow: "",
|
|
2017
|
+
background: "transparent"
|
|
2018
|
+
}
|
|
2019
|
+
};
|
|
1886
2020
|
|
|
1887
2021
|
// src/se-import/mappers/misc.ts
|
|
1888
2022
|
function mapChatboxTheme(seTheme) {
|
|
@@ -3832,11 +3966,6 @@ function rewriteAssetURLs(overlay, mapping) {
|
|
|
3832
3966
|
};
|
|
3833
3967
|
}
|
|
3834
3968
|
var MAX_MIRROR_ASSET_BYTES = 100 * 1024 * 1024;
|
|
3835
|
-
function looksLikeCorsError2(err) {
|
|
3836
|
-
if (!(err instanceof TypeError)) return false;
|
|
3837
|
-
const msg = (err.message ?? "").toLowerCase();
|
|
3838
|
-
return msg.includes("failed to fetch") || msg.includes("networkerror") || msg.includes("network error") || msg.includes("cors") || msg.includes("access-control") || err.message.length > 0;
|
|
3839
|
-
}
|
|
3840
3969
|
async function mirrorOneAsset(url, upload, signal, proxyAssetFetch) {
|
|
3841
3970
|
const blob = await fetchAssetBlob(url, signal, proxyAssetFetch);
|
|
3842
3971
|
if (signal?.aborted) throw new DOMException("Aborted", "AbortError");
|
|
@@ -3868,7 +3997,7 @@ async function fetchAssetBlob(url, signal, proxyAssetFetch) {
|
|
|
3868
3997
|
return res.blob();
|
|
3869
3998
|
}
|
|
3870
3999
|
if (signal?.aborted) throw new DOMException("Aborted", "AbortError");
|
|
3871
|
-
if (proxyAssetFetch &&
|
|
4000
|
+
if (proxyAssetFetch && looksLikeCorsError(directErr)) {
|
|
3872
4001
|
try {
|
|
3873
4002
|
return await proxyAssetFetch(url);
|
|
3874
4003
|
} catch (proxyErr) {
|
|
@@ -3919,7 +4048,7 @@ function guessMime(name) {
|
|
|
3919
4048
|
}
|
|
3920
4049
|
|
|
3921
4050
|
// src/se-import/transplant.ts
|
|
3922
|
-
import { nanoid as
|
|
4051
|
+
import { nanoid as nanoid4 } from "nanoid";
|
|
3923
4052
|
function cloneModuleForTransplant(srcModule, newId) {
|
|
3924
4053
|
const clonedContent = srcModule.content ? structuredClone(srcModule.content) : srcModule.content;
|
|
3925
4054
|
if (srcModule.settings?.type === "custom" && clonedContent) {
|
|
@@ -3937,7 +4066,7 @@ function transplantLayer(source, sourceLayerId) {
|
|
|
3937
4066
|
const srcLayer = layers.find((l) => l.id === sourceLayerId);
|
|
3938
4067
|
const srcModule = modules[sourceLayerId];
|
|
3939
4068
|
if (!srcLayer || !srcModule) return null;
|
|
3940
|
-
const rootNewId =
|
|
4069
|
+
const rootNewId = nanoid4();
|
|
3941
4070
|
if (srcLayer.type !== "group") {
|
|
3942
4071
|
const layer = { ...srcLayer, id: rootNewId };
|
|
3943
4072
|
const module = cloneModuleForTransplant(srcModule, rootNewId);
|
|
@@ -3955,7 +4084,7 @@ function transplantLayer(source, sourceLayerId) {
|
|
|
3955
4084
|
if (seen.has(child.id)) continue;
|
|
3956
4085
|
seen.add(child.id);
|
|
3957
4086
|
descendants.push(child);
|
|
3958
|
-
idRemap.set(child.id,
|
|
4087
|
+
idRemap.set(child.id, nanoid4());
|
|
3959
4088
|
if (child.type === "group") queue.push(child.id);
|
|
3960
4089
|
}
|
|
3961
4090
|
}
|
|
@@ -6441,7 +6570,74 @@ function readSLProvider(response) {
|
|
|
6441
6570
|
}
|
|
6442
6571
|
|
|
6443
6572
|
// src/sl-import/mappers/alert-box.ts
|
|
6444
|
-
import { nanoid as
|
|
6573
|
+
import { nanoid as nanoid6 } from "nanoid";
|
|
6574
|
+
import { LumiaAlertValues as LumiaAlertValues2 } from "@lumiastream/lumia-types";
|
|
6575
|
+
|
|
6576
|
+
// src/se-import/import-envelope.ts
|
|
6577
|
+
import { nanoid as nanoid5 } from "nanoid";
|
|
6578
|
+
function buildModuleEnvelope(opts) {
|
|
6579
|
+
const id = opts.id ?? nanoid5();
|
|
6580
|
+
const locked = opts.locked ?? false;
|
|
6581
|
+
const visible = opts.visible ?? true;
|
|
6582
|
+
const layer = {
|
|
6583
|
+
id,
|
|
6584
|
+
...opts.parentGroupId !== void 0 ? { group: opts.parentGroupId } : {},
|
|
6585
|
+
...opts.type_layer ? { type: opts.type_layer } : {},
|
|
6586
|
+
state: {
|
|
6587
|
+
visible,
|
|
6588
|
+
locked,
|
|
6589
|
+
...opts.expanded !== void 0 ? { expanded: opts.expanded } : {}
|
|
6590
|
+
},
|
|
6591
|
+
bounds: {
|
|
6592
|
+
x: opts.bounds.x,
|
|
6593
|
+
y: opts.bounds.y,
|
|
6594
|
+
width: opts.bounds.width,
|
|
6595
|
+
height: opts.bounds.height,
|
|
6596
|
+
scale: [1, 1],
|
|
6597
|
+
...opts.zIndex !== void 0 ? { zIndex: opts.zIndex } : {}
|
|
6598
|
+
}
|
|
6599
|
+
};
|
|
6600
|
+
const module = {
|
|
6601
|
+
id,
|
|
6602
|
+
version: opts.version ?? 1,
|
|
6603
|
+
loaded: true,
|
|
6604
|
+
settings: { type: opts.type, title: opts.title, locked },
|
|
6605
|
+
lights: opts.lights ?? [],
|
|
6606
|
+
css: opts.css ?? {},
|
|
6607
|
+
content: opts.content ?? {},
|
|
6608
|
+
variables: opts.variables ?? {},
|
|
6609
|
+
events: opts.events ?? {},
|
|
6610
|
+
...opts.alert !== void 0 ? { alert: opts.alert } : {}
|
|
6611
|
+
};
|
|
6612
|
+
return { id, layer, module };
|
|
6613
|
+
}
|
|
6614
|
+
var IMPORT_META_KEY = "importMeta";
|
|
6615
|
+
function stampImportMetaMerge(module, meta) {
|
|
6616
|
+
const existing = module.content?.[IMPORT_META_KEY] ?? {};
|
|
6617
|
+
module.content = {
|
|
6618
|
+
...module.content ?? {},
|
|
6619
|
+
[IMPORT_META_KEY]: {
|
|
6620
|
+
importedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6621
|
+
...existing,
|
|
6622
|
+
...meta
|
|
6623
|
+
}
|
|
6624
|
+
};
|
|
6625
|
+
}
|
|
6626
|
+
function customHtmlReviewItem(moduleId, importSourceType, settings, reason) {
|
|
6627
|
+
return {
|
|
6628
|
+
moduleId,
|
|
6629
|
+
// ReviewItem's `seWidget` is typed against SEWidget but the review
|
|
6630
|
+
// UI just reads `.type` and `.settings`. Cast through unknown is
|
|
6631
|
+
// the only place we touch the shape mismatch; widening the
|
|
6632
|
+
// ReviewItem type is a future cleanup.
|
|
6633
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6634
|
+
seWidget: { type: importSourceType, settings },
|
|
6635
|
+
status: "template",
|
|
6636
|
+
reason
|
|
6637
|
+
};
|
|
6638
|
+
}
|
|
6639
|
+
|
|
6640
|
+
// src/sl-import/mappers/alert-box.ts
|
|
6445
6641
|
var SL_EVENT_ROUTING = {
|
|
6446
6642
|
// Platform-native — provider routes (Twitch / Kick / YouTube).
|
|
6447
6643
|
follow: { pickProviderKeys: "follower" },
|
|
@@ -6453,47 +6649,35 @@ var SL_EVENT_ROUTING = {
|
|
|
6453
6649
|
// `subscriber` here is YouTube subscribe (free); `sponsor` is YouTube
|
|
6454
6650
|
// channel membership; `fanfunding` is YouTube superchat. SL ships these
|
|
6455
6651
|
// even on Twitch-primary accounts so we always map them.
|
|
6456
|
-
subscriber: { keys: [
|
|
6457
|
-
sponsor: { keys: [
|
|
6458
|
-
fanfunding: { keys: [
|
|
6459
|
-
super_sticker: { keys: [
|
|
6652
|
+
subscriber: { keys: [LumiaAlertValues2.YOUTUBE_SUBSCRIBER] },
|
|
6653
|
+
sponsor: { keys: [LumiaAlertValues2.YOUTUBE_MEMBER] },
|
|
6654
|
+
fanfunding: { keys: [LumiaAlertValues2.YOUTUBE_SUPERCHAT] },
|
|
6655
|
+
super_sticker: { keys: [LumiaAlertValues2.YOUTUBE_SUPERSTICKER] },
|
|
6460
6656
|
// Donation / tip channels — Lumia ships dedicated alert keys for each
|
|
6461
6657
|
// integration. `donation` itself fans out to `streamlabs-donation` AND
|
|
6462
6658
|
// `lumiastream-donation` so the imported alert fires regardless of which
|
|
6463
6659
|
// channel the donation actually came in on.
|
|
6464
|
-
donation: { keys: [
|
|
6465
|
-
eldonation: { keys: [
|
|
6466
|
-
tiltifydonation: { keys: [
|
|
6467
|
-
donordrivedonation: { keys: [
|
|
6468
|
-
justgivingdonation: { keys: [
|
|
6469
|
-
pledge: { keys: [
|
|
6660
|
+
donation: { keys: [LumiaAlertValues2.STREAMLABS_DONATION, LumiaAlertValues2.LUMIASTREAM_DONATION] },
|
|
6661
|
+
eldonation: { keys: [LumiaAlertValues2.EXTRALIFE_DONATION] },
|
|
6662
|
+
tiltifydonation: { keys: [LumiaAlertValues2.TILTIFY_DONATION] },
|
|
6663
|
+
donordrivedonation: { keys: [LumiaAlertValues2.DONORDRIVE_DONATION] },
|
|
6664
|
+
justgivingdonation: { keys: [LumiaAlertValues2.STREAMLABS_DONATION] },
|
|
6665
|
+
pledge: { keys: [LumiaAlertValues2.PATREON_PLEDGE] },
|
|
6470
6666
|
// Charity / merch / loyalty / prime gifting — SL-flavored channels with
|
|
6471
6667
|
// matching Lumia keys.
|
|
6472
|
-
streamlabscharitydonation: { keys: [
|
|
6473
|
-
twitchcharitydonation: { keys: [
|
|
6474
|
-
merch: { keys: [
|
|
6475
|
-
loyalty_store_redemption: { keys: [
|
|
6476
|
-
prime_sub_gift: { keys: [
|
|
6477
|
-
treat: { keys: [
|
|
6668
|
+
streamlabscharitydonation: { keys: [LumiaAlertValues2.STREAMLABS_CHARITY] },
|
|
6669
|
+
twitchcharitydonation: { keys: [LumiaAlertValues2.TWITCH_CHARITY_DONATION] },
|
|
6670
|
+
merch: { keys: [LumiaAlertValues2.STREAMLABS_MERCH] },
|
|
6671
|
+
loyalty_store_redemption: { keys: [LumiaAlertValues2.STREAMLABS_REDEMPTION] },
|
|
6672
|
+
prime_sub_gift: { keys: [LumiaAlertValues2.STREAMLABS_PRIMEGIFT] },
|
|
6673
|
+
treat: { keys: [LumiaAlertValues2.TREATSTREAM_TREAT] },
|
|
6478
6674
|
// TikTok-flavored (jewel gift is TikTok-ish in concept).
|
|
6479
|
-
jewel_gift: { keys: [
|
|
6675
|
+
jewel_gift: { keys: [LumiaAlertValues2.TIKTOK_GIFT] }
|
|
6480
6676
|
};
|
|
6481
6677
|
function getField(settings, prefix, field) {
|
|
6482
6678
|
const key = `${prefix}_${field}`;
|
|
6483
6679
|
return settings[key];
|
|
6484
6680
|
}
|
|
6485
|
-
function pxToNumber(raw, fallback) {
|
|
6486
|
-
if (typeof raw === "number" && Number.isFinite(raw)) return raw;
|
|
6487
|
-
if (typeof raw !== "string") return fallback;
|
|
6488
|
-
const trimmed = raw.trim();
|
|
6489
|
-
if (!trimmed) return fallback;
|
|
6490
|
-
if (trimmed.endsWith("px")) {
|
|
6491
|
-
const n2 = parseFloat(trimmed.slice(0, -2));
|
|
6492
|
-
return Number.isFinite(n2) ? n2 : fallback;
|
|
6493
|
-
}
|
|
6494
|
-
const n = parseFloat(trimmed);
|
|
6495
|
-
return Number.isFinite(n) ? n : fallback;
|
|
6496
|
-
}
|
|
6497
6681
|
function translateLayout2(slLayout) {
|
|
6498
6682
|
switch (slLayout) {
|
|
6499
6683
|
case "above":
|
|
@@ -6523,13 +6707,7 @@ function buildBaseAlertEvent(settings, prefix, defaultMessage) {
|
|
|
6523
6707
|
const fontWeight = getField(settings, prefix, "font_weight") ?? 600;
|
|
6524
6708
|
const fontColor = getField(settings, prefix, "font_color") ?? "#FFFFFF";
|
|
6525
6709
|
const highlightColor = getField(settings, prefix, "font_color2") ?? "#32C3A6";
|
|
6526
|
-
const
|
|
6527
|
-
getField(settings, prefix, "message_font_size"),
|
|
6528
|
-
20
|
|
6529
|
-
);
|
|
6530
|
-
const messageFontFamily = getField(settings, prefix, "message_font") ?? fontFamily;
|
|
6531
|
-
const messageFontWeight = getField(settings, prefix, "message_font_weight") ?? 400;
|
|
6532
|
-
const messageFontColor = getField(settings, prefix, "message_font_color") ?? "#FFFFFF";
|
|
6710
|
+
const secondaryMessage = readSecondaryMessageConfig(settings, prefix, fontFamily);
|
|
6533
6711
|
const imageHref = absolutizeSLUrl(getField(settings, prefix, "image_href"));
|
|
6534
6712
|
const soundHref = absolutizeSLUrl(getField(settings, prefix, "sound_href"));
|
|
6535
6713
|
const soundVolume = getField(settings, prefix, "sound_volume") ?? 50;
|
|
@@ -6548,7 +6726,7 @@ function buildBaseAlertEvent(settings, prefix, defaultMessage) {
|
|
|
6548
6726
|
accentColor: null,
|
|
6549
6727
|
highlightColor,
|
|
6550
6728
|
firstMessageTemplate: translateSeText(messageTemplate),
|
|
6551
|
-
secondMessageTemplate: "",
|
|
6729
|
+
secondMessageTemplate: secondaryMessage?.template ?? "",
|
|
6552
6730
|
thirdMessageTemplate: "",
|
|
6553
6731
|
showAvatar: false,
|
|
6554
6732
|
showAmount: true,
|
|
@@ -6571,12 +6749,10 @@ function buildBaseAlertEvent(settings, prefix, defaultMessage) {
|
|
|
6571
6749
|
textShadow: "rgba(0, 0, 0, 0.8) 1px 1px 1px",
|
|
6572
6750
|
textAlign: "center"
|
|
6573
6751
|
},
|
|
6574
|
-
messageCss
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
fontWeight: messageFontWeight
|
|
6579
|
-
},
|
|
6752
|
+
// `messageCss` only matters when secondMessageTemplate is set;
|
|
6753
|
+
// leave it empty when SL didn't ship a secondary-message block
|
|
6754
|
+
// so Lumia's renderer falls back to its own default styling.
|
|
6755
|
+
messageCss: secondaryMessage?.css ?? {},
|
|
6580
6756
|
content: { value: translateSeText(messageTemplate) }
|
|
6581
6757
|
},
|
|
6582
6758
|
media: {
|
|
@@ -6611,14 +6787,39 @@ function buildBaseAlertEvent(settings, prefix, defaultMessage) {
|
|
|
6611
6787
|
tts: {
|
|
6612
6788
|
enabled: getField(settings, prefix, "tts_enabled") ?? false,
|
|
6613
6789
|
voice: getField(settings, prefix, "tts_language") ?? "Brian",
|
|
6614
|
-
volume: clampVolume(
|
|
6615
|
-
getField(settings, prefix, "tts_volume") ?? 75
|
|
6616
|
-
),
|
|
6790
|
+
volume: clampVolume(getField(settings, prefix, "tts_volume") ?? 75),
|
|
6617
6791
|
minAmount: getField(settings, prefix, "tts_min_amount") ?? 0
|
|
6618
6792
|
},
|
|
6619
6793
|
variations: []
|
|
6620
6794
|
};
|
|
6621
6795
|
}
|
|
6796
|
+
var SECONDARY_MESSAGE_PREFIX_OVERRIDE = {
|
|
6797
|
+
sub: "resub"
|
|
6798
|
+
};
|
|
6799
|
+
function readSecondaryMessageConfig(settings, prefix, primaryFontFamily) {
|
|
6800
|
+
const secondaryPrefix = SECONDARY_MESSAGE_PREFIX_OVERRIDE[prefix] ?? prefix;
|
|
6801
|
+
const showKey = `show_${secondaryPrefix}_message`;
|
|
6802
|
+
const enabled = settings[showKey];
|
|
6803
|
+
if (enabled !== true) return null;
|
|
6804
|
+
const fontFamily = getField(settings, secondaryPrefix, "message_font") ?? primaryFontFamily;
|
|
6805
|
+
const fontSize = pxToNumber(getField(settings, secondaryPrefix, "message_font_size"), 20);
|
|
6806
|
+
const fontWeight = getField(settings, secondaryPrefix, "message_font_weight") ?? 400;
|
|
6807
|
+
const fontColor = getField(settings, secondaryPrefix, "message_font_color") ?? "#FFFFFF";
|
|
6808
|
+
return {
|
|
6809
|
+
// `{message}` is the SE/SL chat-message token (mapped to Lumia's
|
|
6810
|
+
// `{{message}}` in translate.ts). It resolves at render time from
|
|
6811
|
+
// the alert payload's `message` field — populated for every event
|
|
6812
|
+
// where SL ships a secondary-message line (donations, resubs,
|
|
6813
|
+
// cheers, charity, merch, etc.).
|
|
6814
|
+
template: translateSeText("{message}"),
|
|
6815
|
+
css: {
|
|
6816
|
+
fontFamily,
|
|
6817
|
+
fontSize,
|
|
6818
|
+
color: fontColor,
|
|
6819
|
+
fontWeight
|
|
6820
|
+
}
|
|
6821
|
+
};
|
|
6822
|
+
}
|
|
6622
6823
|
function clampVolume(slVolume) {
|
|
6623
6824
|
if (typeof slVolume !== "number" || !Number.isFinite(slVolume)) return 0.5;
|
|
6624
6825
|
return Math.max(0, Math.min(1, slVolume / 100));
|
|
@@ -6628,11 +6829,20 @@ function translateSLVariationCondition(v) {
|
|
|
6628
6829
|
const numericData = typeof data === "number" ? data : Number(data);
|
|
6629
6830
|
switch (v.condition) {
|
|
6630
6831
|
case "RANDOM":
|
|
6631
|
-
return {
|
|
6832
|
+
return {
|
|
6833
|
+
conditionType: "RANDOM",
|
|
6834
|
+
condition: Number.isFinite(numericData) ? numericData : 100
|
|
6835
|
+
};
|
|
6632
6836
|
case "MIN_BITS_USED":
|
|
6633
|
-
return {
|
|
6837
|
+
return {
|
|
6838
|
+
conditionType: "GREATER_NUMBER",
|
|
6839
|
+
condition: Number.isFinite(numericData) ? numericData : 0
|
|
6840
|
+
};
|
|
6634
6841
|
case "EXACT_BITS_USED":
|
|
6635
|
-
return {
|
|
6842
|
+
return {
|
|
6843
|
+
conditionType: "EQUAL_NUMBER",
|
|
6844
|
+
condition: Number.isFinite(numericData) ? numericData : 0
|
|
6845
|
+
};
|
|
6636
6846
|
case "MIN_MONTHS_SUBSCRIBED":
|
|
6637
6847
|
return {
|
|
6638
6848
|
conditionType: "SUBSCRIBED_MONTHS_GREATER",
|
|
@@ -6697,6 +6907,14 @@ function buildVariationEvent(v, parentBase) {
|
|
|
6697
6907
|
if (s.hideAnimation) inherited.animations.alertExitAnimation = s.hideAnimation;
|
|
6698
6908
|
if (s.layout) inherited.layout.value = translateLayout2(s.layout);
|
|
6699
6909
|
return {
|
|
6910
|
+
// Reuse SL's own `uuid` when present so re-importing the same SL
|
|
6911
|
+
// alert-box keeps the variation identity stable across import
|
|
6912
|
+
// runs. SL always emits a uuid in their config (every fixture we've
|
|
6913
|
+
// seen has one); fall back to nanoid for the edge case of a
|
|
6914
|
+
// hand-crafted / older payload that omits it. Matches the SE
|
|
6915
|
+
// alert mapper's variation-id pattern — see Settings.tsx auto-fill
|
|
6916
|
+
// note there for why a stable id matters from save #1.
|
|
6917
|
+
id: typeof v.uuid === "string" && v.uuid.length > 0 ? v.uuid : nanoid6(),
|
|
6700
6918
|
name: v.name ?? "Variation",
|
|
6701
6919
|
on: v.paused !== true,
|
|
6702
6920
|
randomChance: 100,
|
|
@@ -6762,11 +6980,7 @@ function buildSLAlertBox(settings, options = {}) {
|
|
|
6762
6980
|
for (const [prefix, routing] of Object.entries(SL_EVENT_ROUTING)) {
|
|
6763
6981
|
const lumiaKeys = routing.pickProviderKeys ? alertBoxKeysFor(routing.pickProviderKeys, provider) : routing.keys ?? [];
|
|
6764
6982
|
if (lumiaKeys.length === 0) continue;
|
|
6765
|
-
const built = buildBaseAlertEvent(
|
|
6766
|
-
settings,
|
|
6767
|
-
prefix,
|
|
6768
|
-
DEFAULT_MESSAGES[prefix] ?? "{name}"
|
|
6769
|
-
);
|
|
6983
|
+
const built = buildBaseAlertEvent(settings, prefix, DEFAULT_MESSAGES[prefix] ?? "{name}");
|
|
6770
6984
|
if (!built) continue;
|
|
6771
6985
|
const variationKey = VARIATION_KEY_FOR_PREFIX[prefix];
|
|
6772
6986
|
const variations = variationKey ? settings[variationKey] : void 0;
|
|
@@ -6783,53 +6997,32 @@ function buildSLAlertBox(settings, options = {}) {
|
|
|
6783
6997
|
channelsImported.push(prefix);
|
|
6784
6998
|
if (firstEvent == null) firstEvent = built;
|
|
6785
6999
|
}
|
|
6786
|
-
const id = nanoid4();
|
|
6787
|
-
const layer = {
|
|
6788
|
-
id,
|
|
6789
|
-
state: { visible: true, locked: false },
|
|
6790
|
-
bounds: { x: 100, y: 100, width: 700, height: 600, scale: [1, 1] }
|
|
6791
|
-
};
|
|
6792
7000
|
const baseAlert = firstEvent ? stripEventOnlyFields(firstEvent) : {};
|
|
6793
|
-
const module = {
|
|
6794
|
-
|
|
6795
|
-
|
|
6796
|
-
|
|
6797
|
-
settings: { type: "alert", title: "Streamlabs Alerts", locked: false },
|
|
6798
|
-
lights: [],
|
|
6799
|
-
css: {},
|
|
6800
|
-
content: {},
|
|
6801
|
-
variables: {},
|
|
6802
|
-
events: {},
|
|
7001
|
+
const { layer, module } = buildModuleEnvelope({
|
|
7002
|
+
type: "alert",
|
|
7003
|
+
title: "Streamlabs Alerts",
|
|
7004
|
+
bounds: { x: 100, y: 100, width: 700, height: 600 },
|
|
6803
7005
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6804
7006
|
alert: { ...baseAlert, events }
|
|
6805
|
-
};
|
|
7007
|
+
});
|
|
6806
7008
|
return { layer, module, channelsImported };
|
|
6807
7009
|
}
|
|
6808
7010
|
function stripEventOnlyFields(event) {
|
|
6809
|
-
const {
|
|
7011
|
+
const {
|
|
7012
|
+
on: _on,
|
|
7013
|
+
variations: _variations,
|
|
7014
|
+
matchEmptyCondition: _mec,
|
|
7015
|
+
...base
|
|
7016
|
+
} = event;
|
|
6810
7017
|
return base;
|
|
6811
7018
|
}
|
|
6812
7019
|
|
|
6813
7020
|
// src/sl-import/mappers/tip-jar.ts
|
|
6814
|
-
import { nanoid as nanoid5 } from "nanoid";
|
|
6815
|
-
function pxToNumber2(raw, fallback) {
|
|
6816
|
-
if (typeof raw === "number" && Number.isFinite(raw)) return raw;
|
|
6817
|
-
if (typeof raw !== "string") return fallback;
|
|
6818
|
-
const trimmed = raw.trim();
|
|
6819
|
-
if (!trimmed) return fallback;
|
|
6820
|
-
if (trimmed.endsWith("px")) {
|
|
6821
|
-
const n2 = parseFloat(trimmed.slice(0, -2));
|
|
6822
|
-
return Number.isFinite(n2) ? n2 : fallback;
|
|
6823
|
-
}
|
|
6824
|
-
const n = parseFloat(trimmed);
|
|
6825
|
-
return Number.isFinite(n) ? n : fallback;
|
|
6826
|
-
}
|
|
6827
7021
|
function buildSLTipJar(settings) {
|
|
6828
|
-
const id = nanoid5();
|
|
6829
7022
|
const backgroundColor = settings.background?.color ?? "transparent";
|
|
6830
7023
|
const textColor = settings.text?.color ?? "#FFFFFF";
|
|
6831
7024
|
const fontFamily = settings.text?.font ?? "Open Sans";
|
|
6832
|
-
const fontSize =
|
|
7025
|
+
const fontSize = pxToNumber(settings.text?.size, 32);
|
|
6833
7026
|
const types = settings.types ?? {};
|
|
6834
7027
|
const tipsConfig = types.tips ?? {};
|
|
6835
7028
|
const slEvents = {
|
|
@@ -6845,17 +7038,11 @@ function buildSLTipJar(settings) {
|
|
|
6845
7038
|
...TIPJAR_DEFAULT_MODULE.content.display,
|
|
6846
7039
|
showEventMessages: settings.text?.show !== false
|
|
6847
7040
|
};
|
|
6848
|
-
const layer = {
|
|
6849
|
-
|
|
6850
|
-
|
|
6851
|
-
bounds: { x: 100, y: 100, width: 600, height: 700
|
|
6852
|
-
};
|
|
6853
|
-
const module = {
|
|
6854
|
-
id,
|
|
7041
|
+
const { layer, module } = buildModuleEnvelope({
|
|
7042
|
+
type: "tipjar",
|
|
7043
|
+
title: "Streamlabs Tip Jar",
|
|
7044
|
+
bounds: { x: 100, y: 100, width: 600, height: 700 },
|
|
6855
7045
|
version: TIPJAR_DEFAULT_MODULE.version,
|
|
6856
|
-
loaded: true,
|
|
6857
|
-
settings: { type: "tipjar", title: "Streamlabs Tip Jar", locked: false },
|
|
6858
|
-
lights: [],
|
|
6859
7046
|
css: {
|
|
6860
7047
|
fontFamily,
|
|
6861
7048
|
fontSize,
|
|
@@ -6876,12 +7063,7 @@ function buildSLTipJar(settings) {
|
|
|
6876
7063
|
source: "streamlabs",
|
|
6877
7064
|
widgetType: "tip_jar",
|
|
6878
7065
|
importedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6879
|
-
// SL jar type doesn't have a 1:1 mapping to Lumia's preset
|
|
6880
|
-
// vocabulary (cup-01, cup-02, …). Stashed for review.
|
|
6881
7066
|
slJarType: settings.jar?.type ?? null,
|
|
6882
|
-
// SL tier coin tiers — Lumia's sprite tiers are per-event and
|
|
6883
|
-
// configured in the sprite editor; the user re-creates these
|
|
6884
|
-
// manually. Stored here so they're not lost.
|
|
6885
7067
|
slTipTiers: Array.isArray(tipsConfig.tiers) ? tipsConfig.tiers.map((t) => ({
|
|
6886
7068
|
minimumAmount: t.minimum_amount,
|
|
6887
7069
|
imageSrc: t.image_src ?? null
|
|
@@ -6889,15 +7071,12 @@ function buildSLTipJar(settings) {
|
|
|
6889
7071
|
slMinimumTipAmount: tipsConfig.minimum_amount ?? null,
|
|
6890
7072
|
slHadCustomHtml: settings.custom_html_enabled === true
|
|
6891
7073
|
}
|
|
6892
|
-
}
|
|
6893
|
-
|
|
6894
|
-
events: {}
|
|
6895
|
-
};
|
|
7074
|
+
}
|
|
7075
|
+
});
|
|
6896
7076
|
return { layer, module };
|
|
6897
7077
|
}
|
|
6898
7078
|
|
|
6899
7079
|
// src/sl-import/mappers/goal.ts
|
|
6900
|
-
import { nanoid as nanoid6 } from "nanoid";
|
|
6901
7080
|
var GOAL_SOURCE_MAP = {
|
|
6902
7081
|
follower_goal: "follower",
|
|
6903
7082
|
sub_goal: "subscriber",
|
|
@@ -6910,69 +7089,262 @@ var GOAL_TITLE_MAP = {
|
|
|
6910
7089
|
donation_goal: "Donation Goal",
|
|
6911
7090
|
bit_goal: "Bits Goal"
|
|
6912
7091
|
};
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
|
|
6917
|
-
|
|
6918
|
-
|
|
6919
|
-
const n2 = parseFloat(trimmed.slice(0, -2));
|
|
6920
|
-
return Number.isFinite(n2) ? n2 : fallback;
|
|
6921
|
-
}
|
|
6922
|
-
const n = parseFloat(trimmed);
|
|
6923
|
-
return Number.isFinite(n) ? n : fallback;
|
|
6924
|
-
}
|
|
7092
|
+
var GOAL_CURRENT_TEMPLATE = {
|
|
7093
|
+
follower_goal: "{{twitch_total_follower_count}}",
|
|
7094
|
+
sub_goal: "{{twitch_total_subscriber_count}}",
|
|
7095
|
+
donation_goal: "{{total_donation_amount}}",
|
|
7096
|
+
bit_goal: "{{twitch_total_bits_count}}"
|
|
7097
|
+
};
|
|
6925
7098
|
function buildSLGoal(settings, widgetType) {
|
|
6926
|
-
const id = nanoid6();
|
|
6927
7099
|
const goalSource = GOAL_SOURCE_MAP[widgetType] ?? "follower";
|
|
6928
7100
|
const defaultTitle = GOAL_TITLE_MAP[widgetType] ?? "Goal";
|
|
7101
|
+
const currentTemplate = GOAL_CURRENT_TEMPLATE[widgetType] ?? "";
|
|
7102
|
+
const requiresReview = settings.custom_enabled === true;
|
|
6929
7103
|
const title = typeof settings.title === "string" ? settings.title : defaultTitle;
|
|
6930
7104
|
const goalAmount = typeof settings.goal === "number" ? settings.goal : 100;
|
|
6931
7105
|
const currentAmount = typeof settings.current === "number" ? settings.current : 0;
|
|
6932
7106
|
const startingAmount = typeof settings.starting_amount === "number" ? settings.starting_amount : 0;
|
|
6933
|
-
const endsAt = typeof settings.ends_at === "string" ? settings.ends_at :
|
|
7107
|
+
const endsAt = typeof settings.ends_at === "string" ? settings.ends_at : "";
|
|
6934
7108
|
const barColor = settings.bar_color ?? "#32C3A6";
|
|
6935
|
-
const
|
|
7109
|
+
const barBgColor = settings.bar_bg_color ?? "#181818";
|
|
7110
|
+
const widgetBgColor = settings.background_color ?? "transparent";
|
|
6936
7111
|
const textColor = settings.text_color ?? "#FFFFFF";
|
|
6937
7112
|
const barTextColor = settings.bar_text_color ?? textColor;
|
|
6938
7113
|
const fontFamily = settings.font ?? "Open Sans";
|
|
6939
|
-
const
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
|
|
6943
|
-
|
|
6944
|
-
|
|
6945
|
-
|
|
6946
|
-
version: 1,
|
|
6947
|
-
loaded: true,
|
|
6948
|
-
settings: { type: "goal", title, locked: false },
|
|
6949
|
-
lights: [],
|
|
7114
|
+
const fontSize = pxToNumber(settings.font_size, 24);
|
|
7115
|
+
const barThickness = pxToNumber(settings.bar_thickness, 48);
|
|
7116
|
+
const layerHeight = Math.max(60, barThickness + 32);
|
|
7117
|
+
const { layer, module } = buildModuleEnvelope({
|
|
7118
|
+
type: "goal",
|
|
7119
|
+
title,
|
|
7120
|
+
bounds: { x: 100, y: 100, width: 740, height: layerHeight },
|
|
6950
7121
|
css: {
|
|
6951
7122
|
fontFamily,
|
|
6952
7123
|
color: textColor,
|
|
6953
|
-
background:
|
|
7124
|
+
background: widgetBgColor,
|
|
7125
|
+
fontSize
|
|
6954
7126
|
},
|
|
7127
|
+
// Use Lumia's canonical goal field names — `targetGoal` (string),
|
|
7128
|
+
// `current` (template string), `display`, `filledColor` /
|
|
7129
|
+
// `unfilledColor`. The prior schema used invented field names
|
|
7130
|
+
// (`goalAmount`, `barColor`) that the renderer ignored.
|
|
6955
7131
|
content: {
|
|
6956
|
-
|
|
6957
|
-
|
|
6958
|
-
|
|
6959
|
-
|
|
6960
|
-
|
|
6961
|
-
|
|
6962
|
-
|
|
6963
|
-
|
|
6964
|
-
|
|
6965
|
-
|
|
6966
|
-
|
|
7132
|
+
version: 1,
|
|
7133
|
+
type: "bar",
|
|
7134
|
+
label: title,
|
|
7135
|
+
subLabel: "",
|
|
7136
|
+
display: "{{current}} / {{goal}}",
|
|
7137
|
+
current: currentAmount > 0 ? String(currentAmount) : currentTemplate,
|
|
7138
|
+
targetGoal: String(goalAmount),
|
|
7139
|
+
image: "",
|
|
7140
|
+
audio: {
|
|
7141
|
+
decrement: "",
|
|
7142
|
+
increment: "",
|
|
7143
|
+
goal: "",
|
|
7144
|
+
goalFailed: "",
|
|
7145
|
+
volume: 1
|
|
7146
|
+
},
|
|
7147
|
+
endDate: endsAt,
|
|
7148
|
+
goalAnimation: "",
|
|
7149
|
+
goalAnimationLoop: true,
|
|
7150
|
+
unfilledColor: barBgColor,
|
|
7151
|
+
filledColor: barColor,
|
|
7152
|
+
alignItemsToEdges: false,
|
|
7153
|
+
border: "solid 1px transparent",
|
|
7154
|
+
borderRadius: "40px",
|
|
7155
|
+
highlightColor: "inherit",
|
|
7156
|
+
importMeta: {
|
|
7157
|
+
source: "streamlabs",
|
|
7158
|
+
widgetType,
|
|
7159
|
+
importedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7160
|
+
goalSource,
|
|
7161
|
+
slLayout: settings.layout ?? null,
|
|
7162
|
+
slBarTextColor: barTextColor,
|
|
7163
|
+
slBarThickness: barThickness,
|
|
7164
|
+
slStartingAmount: startingAmount,
|
|
7165
|
+
slHadCustomHtml: settings.custom_enabled === true
|
|
7166
|
+
}
|
|
7167
|
+
}
|
|
7168
|
+
});
|
|
7169
|
+
return { layer, module, requiresReview };
|
|
7170
|
+
}
|
|
7171
|
+
|
|
7172
|
+
// src/sl-import/mappers/chat-box.ts
|
|
7173
|
+
function buildSitesArray(settings) {
|
|
7174
|
+
const defaultSites = [...CHATBOX_DEFAULT_MODULE.content.sites];
|
|
7175
|
+
const drop = /* @__PURE__ */ new Set();
|
|
7176
|
+
if (settings.show_bttv_emotes === false) drop.add("bttv");
|
|
7177
|
+
if (settings.show_franker_emotes === false) drop.add("ffz");
|
|
7178
|
+
if (settings.show_7tv_emotes === false) drop.add("seventv");
|
|
7179
|
+
if (settings.twitch_enabled === false) drop.add("twitch");
|
|
7180
|
+
if (settings.youtube_enabled === false) drop.add("youtube");
|
|
7181
|
+
if (settings.facebook_enabled === false) drop.add("facebook");
|
|
7182
|
+
if (settings.tiktok_enabled === false) drop.add("tiktok");
|
|
7183
|
+
if (settings.kick_enabled === false) drop.add("kick");
|
|
7184
|
+
if (drop.size === 0) return defaultSites;
|
|
7185
|
+
return defaultSites.filter((s) => !drop.has(s));
|
|
7186
|
+
}
|
|
7187
|
+
function buildSLChatBox(settings) {
|
|
7188
|
+
const requiresReview = settings.custom_enabled === true;
|
|
7189
|
+
const backgroundColor = settings.background_color ?? "transparent";
|
|
7190
|
+
const textColor = settings.text_color ?? "#FFFFFF";
|
|
7191
|
+
const textSize = pxToNumber(settings.text_size, 16);
|
|
7192
|
+
const fadeOutAfterDelay = settings.always_show_messages !== true;
|
|
7193
|
+
const fadeOutDelayTime = fadeOutAfterDelay ? Math.max(1, Math.round((settings.message_hide_delay ?? 15e3) / 1e3)) : 0;
|
|
7194
|
+
const sites = buildSitesArray(settings);
|
|
7195
|
+
const { layer, module } = buildModuleEnvelope({
|
|
7196
|
+
type: "chatbox",
|
|
7197
|
+
title: "Streamlabs Chat Box",
|
|
7198
|
+
bounds: { x: 100, y: 100, width: 375, height: 470 },
|
|
7199
|
+
version: CHATBOX_DEFAULT_MODULE.version,
|
|
7200
|
+
css: {
|
|
7201
|
+
background: backgroundColor,
|
|
7202
|
+
color: textColor,
|
|
7203
|
+
fontSize: textSize
|
|
6967
7204
|
},
|
|
6968
|
-
|
|
6969
|
-
|
|
6970
|
-
|
|
6971
|
-
|
|
7205
|
+
content: {
|
|
7206
|
+
// Spread canonical defaults FIRST so the renderer's dereferences
|
|
7207
|
+
// (chatboxStreamingSite.<platform>.themeConfig, animations,
|
|
7208
|
+
// chatboxStreamingSite.<platform>.message, etc.) all exist.
|
|
7209
|
+
...CHATBOX_DEFAULT_MODULE.content,
|
|
7210
|
+
// Then override the bits SL controls.
|
|
7211
|
+
sites,
|
|
7212
|
+
fadeOutAfterDelay,
|
|
7213
|
+
fadeOutDelayTime,
|
|
7214
|
+
// SL keeps history forever by default — `always_show_messages`
|
|
7215
|
+
// implies the streamer wants a permanent scrollback. Lumia
|
|
7216
|
+
// exposes that as `permanent: true`.
|
|
7217
|
+
permanent: settings.always_show_messages === true,
|
|
7218
|
+
// Preserve the SL-specific provenance for the review step.
|
|
7219
|
+
importMeta: {
|
|
7220
|
+
source: "streamlabs",
|
|
7221
|
+
widgetType: "chat_box",
|
|
7222
|
+
importedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7223
|
+
slTheme: settings.theme ?? null,
|
|
7224
|
+
slHadCustomHtml: settings.custom_enabled === true,
|
|
7225
|
+
slHidesCommonBots: settings.hide_common_chat_bots === true,
|
|
7226
|
+
slHidesCommands: settings.hide_commands === true,
|
|
7227
|
+
slMutedChatters: settings.muted_chatters ?? "",
|
|
7228
|
+
slMessageShowDelayMs: settings.message_show_delay ?? 0
|
|
7229
|
+
}
|
|
7230
|
+
}
|
|
7231
|
+
});
|
|
7232
|
+
return { layer, module, requiresReview };
|
|
7233
|
+
}
|
|
7234
|
+
|
|
7235
|
+
// src/sl-import/mappers/event-list.ts
|
|
7236
|
+
var SL_SHOW_FLAG_TO_LUMIA_FILTER = {
|
|
7237
|
+
show_follows: "follower",
|
|
7238
|
+
show_subscriptions: "subscribers",
|
|
7239
|
+
show_resubs: "subscribers",
|
|
7240
|
+
show_sub_gifts: "gifts",
|
|
7241
|
+
show_subscribers: "subscribers",
|
|
7242
|
+
show_sponsors: "subscribers",
|
|
7243
|
+
// YouTube channel members
|
|
7244
|
+
show_sponsor_gifts: "gifts",
|
|
7245
|
+
show_bits: "bits",
|
|
7246
|
+
show_donations: "donation",
|
|
7247
|
+
show_pledges: "donation",
|
|
7248
|
+
// Patreon
|
|
7249
|
+
show_eldonations: "donation",
|
|
7250
|
+
show_tiltifydonations: "donation",
|
|
7251
|
+
show_donordrivedonations: "donation",
|
|
7252
|
+
show_justgivingdonations: "donation",
|
|
7253
|
+
show_streamlabscharitydonations: "donation",
|
|
7254
|
+
show_twitchcharitydonations: "donation",
|
|
7255
|
+
show_twitch_charity: "donation",
|
|
7256
|
+
show_treats: "donation",
|
|
7257
|
+
// TreatStream
|
|
7258
|
+
show_merch: "purchases",
|
|
7259
|
+
show_raids: "raids",
|
|
7260
|
+
show_hosts: "raids",
|
|
7261
|
+
show_redemptions: "redemption",
|
|
7262
|
+
show_fanfundings: "superchats",
|
|
7263
|
+
// YouTube Super Chat
|
|
7264
|
+
show_super_stickers: "superstickers",
|
|
7265
|
+
show_jewel_gifts: "stars"
|
|
7266
|
+
// TikTok-flavored, closest analogue
|
|
7267
|
+
};
|
|
7268
|
+
function buildFilters(settings) {
|
|
7269
|
+
const drop = /* @__PURE__ */ new Set();
|
|
7270
|
+
for (const [slFlag, lumiaCategory] of Object.entries(SL_SHOW_FLAG_TO_LUMIA_FILTER)) {
|
|
7271
|
+
if (settings[slFlag] === false) {
|
|
7272
|
+
drop.add(lumiaCategory);
|
|
7273
|
+
}
|
|
7274
|
+
}
|
|
7275
|
+
return Array.from(drop);
|
|
7276
|
+
}
|
|
7277
|
+
function buildSLEventList(settings) {
|
|
7278
|
+
const requiresReview = settings.custom_enabled === true;
|
|
7279
|
+
const backgroundColor = settings.background_color ?? "transparent";
|
|
7280
|
+
const textColor = settings.text_color ?? "#FFFFFF";
|
|
7281
|
+
const textSize = pxToNumber(settings.text_size, 16);
|
|
7282
|
+
const fontFamily = settings.font_family ?? "Roboto";
|
|
7283
|
+
const maxEvents = typeof settings.max_events === "number" && settings.max_events > 0 ? settings.max_events : EVENTLIST_DEFAULT_MODULE.content.maxItemsToShow;
|
|
7284
|
+
const enterAnimation = settings.show_animation ?? "fadeIn";
|
|
7285
|
+
const exitAnimation = settings.hide_animation ?? "fadeOut";
|
|
7286
|
+
const animationDuration = typeof settings.animation_speed === "number" ? settings.animation_speed : 1e3;
|
|
7287
|
+
const filters = buildFilters(settings);
|
|
7288
|
+
const { layer, module } = buildModuleEnvelope({
|
|
7289
|
+
type: "eventlist",
|
|
7290
|
+
title: "Streamlabs Event List",
|
|
7291
|
+
bounds: { x: 100, y: 100, width: 375, height: 470 },
|
|
7292
|
+
version: EVENTLIST_DEFAULT_MODULE.version,
|
|
7293
|
+
css: {
|
|
7294
|
+
...EVENTLIST_DEFAULT_MODULE.css,
|
|
7295
|
+
background: backgroundColor,
|
|
7296
|
+
color: textColor,
|
|
7297
|
+
fontSize: textSize,
|
|
7298
|
+
fontFamily
|
|
7299
|
+
},
|
|
7300
|
+
content: {
|
|
7301
|
+
// Spread canonical defaults FIRST so the renderer's dereferences
|
|
7302
|
+
// don't crash on missing nested objects.
|
|
7303
|
+
...EVENTLIST_DEFAULT_MODULE.content,
|
|
7304
|
+
maxItemsToShow: maxEvents,
|
|
7305
|
+
// SL's `flip_y` corresponds to Lumia's `reverse` (newest item
|
|
7306
|
+
// at the bottom vs the top). SL's `flip_x` flips the alignment
|
|
7307
|
+
// to right; Lumia covers that via css.textAlign but doesn't
|
|
7308
|
+
// have a per-module horizontal flip — stash as importMeta for
|
|
7309
|
+
// the review step.
|
|
7310
|
+
reverse: settings.flip_y === true,
|
|
7311
|
+
// SL's `keep_history: false` means events disappear after the
|
|
7312
|
+
// fade time; map to `fadeOutAfterDelay: true` with the fade
|
|
7313
|
+
// time SL configured.
|
|
7314
|
+
fadeOutAfterDelay: settings.keep_history === false,
|
|
7315
|
+
fadeOutDelayTime: typeof settings.fade_time === "number" && settings.fade_time > 0 ? Math.max(1, Math.round(settings.fade_time / 1e3)) : EVENTLIST_DEFAULT_MODULE.content.fadeOutDelayTime,
|
|
7316
|
+
animations: {
|
|
7317
|
+
...EVENTLIST_DEFAULT_MODULE.content.animations,
|
|
7318
|
+
enterAnimation,
|
|
7319
|
+
exitAnimation,
|
|
7320
|
+
enterAnimationDuration: animationDuration,
|
|
7321
|
+
exitAnimationDuration: animationDuration
|
|
7322
|
+
},
|
|
7323
|
+
filters,
|
|
7324
|
+
importMeta: {
|
|
7325
|
+
source: "streamlabs",
|
|
7326
|
+
widgetType: "event_list",
|
|
7327
|
+
importedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7328
|
+
slTheme: settings.theme ?? null,
|
|
7329
|
+
slThemeColor: settings.theme_color ?? null,
|
|
7330
|
+
slFlipX: settings.flip_x === true,
|
|
7331
|
+
slHadCustomHtml: settings.custom_enabled === true,
|
|
7332
|
+
// Per-event-type minimums SL filters by — Lumia's eventlist
|
|
7333
|
+
// has no equivalent thresholding; preserve so the streamer
|
|
7334
|
+
// can recreate via the alert module's variation conditions.
|
|
7335
|
+
slHostViewerMinimum: settings.host_viewer_minimum ?? 0,
|
|
7336
|
+
slBitsMinimum: settings.bits_minimum ?? 0,
|
|
7337
|
+
slRaidRaiderMinimum: settings.raid_raider_minimum ?? 0
|
|
7338
|
+
}
|
|
7339
|
+
}
|
|
7340
|
+
});
|
|
7341
|
+
return { layer, module, requiresReview };
|
|
6972
7342
|
}
|
|
6973
7343
|
|
|
6974
7344
|
// src/sl-import/sl-dispatch.ts
|
|
6975
|
-
|
|
7345
|
+
function buildSLDescription(widgetType, sourceUrl) {
|
|
7346
|
+
return buildImportDescription(`Imported from Streamlabs ${widgetType}`, sourceUrl);
|
|
7347
|
+
}
|
|
6976
7348
|
var GOAL_WIDGET_TYPES = /* @__PURE__ */ new Set([
|
|
6977
7349
|
"follower_goal",
|
|
6978
7350
|
"sub_goal",
|
|
@@ -6980,8 +7352,6 @@ var GOAL_WIDGET_TYPES = /* @__PURE__ */ new Set([
|
|
|
6980
7352
|
"bit_goal"
|
|
6981
7353
|
]);
|
|
6982
7354
|
var PLACEHOLDER_WIDGET_TYPES = /* @__PURE__ */ new Set([
|
|
6983
|
-
"chat_box",
|
|
6984
|
-
"event_list",
|
|
6985
7355
|
"donation_ticker",
|
|
6986
7356
|
"stream_boss",
|
|
6987
7357
|
"credits",
|
|
@@ -6991,8 +7361,6 @@ var PLACEHOLDER_WIDGET_TYPES = /* @__PURE__ */ new Set([
|
|
|
6991
7361
|
"streamlabels"
|
|
6992
7362
|
]);
|
|
6993
7363
|
var PLACEHOLDER_REASONS = {
|
|
6994
|
-
chat_box: "Lumia has a native chatbox module \u2014 set it up directly rather than importing the SL config.",
|
|
6995
|
-
event_list: "Lumia has a native eventlist module \u2014 set it up directly rather than importing the SL config.",
|
|
6996
7364
|
donation_ticker: "No native Lumia equivalent yet \u2014 imported as a placeholder text layer.",
|
|
6997
7365
|
stream_boss: "Lumia has a native streamboss module \u2014 set it up directly rather than importing the SL config.",
|
|
6998
7366
|
credits: "Lumia has a native credits module \u2014 set it up directly rather than importing the SL config.",
|
|
@@ -7001,19 +7369,14 @@ var PLACEHOLDER_REASONS = {
|
|
|
7001
7369
|
sub_train: "No native Lumia equivalent yet \u2014 imported as a placeholder text layer.",
|
|
7002
7370
|
streamlabels: "Use Lumia template variables (e.g. {{twitch_last_follower}}) inside a Text module instead of importing the SL streamlabels config."
|
|
7003
7371
|
};
|
|
7372
|
+
var CUSTOM_HTML_REVIEW_REASON = "The Streamlabs widget used custom HTML/CSS/JS that Lumia cannot host. The native Lumia module is the right starting point \u2014 recreate the styling there. The original SL settings are stashed under module.content.importMeta for reference.";
|
|
7004
7373
|
function stampImportMeta(module, widgetType, role, extra = {}) {
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
role,
|
|
7012
|
-
importedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7013
|
-
...existing,
|
|
7014
|
-
...extra
|
|
7015
|
-
}
|
|
7016
|
-
};
|
|
7374
|
+
stampImportMetaMerge(module, {
|
|
7375
|
+
source: "streamlabs",
|
|
7376
|
+
widgetType,
|
|
7377
|
+
role,
|
|
7378
|
+
...extra
|
|
7379
|
+
});
|
|
7017
7380
|
}
|
|
7018
7381
|
function buildPlaceholder(widgetType) {
|
|
7019
7382
|
const id = nanoid7();
|
|
@@ -7045,7 +7408,7 @@ function buildPlaceholder(widgetType) {
|
|
|
7045
7408
|
};
|
|
7046
7409
|
return { layer, module };
|
|
7047
7410
|
}
|
|
7048
|
-
function importStreamlabsWidget(response, widgetType) {
|
|
7411
|
+
function importStreamlabsWidget(response, widgetType, options = {}) {
|
|
7049
7412
|
if (!isSLWidgetConfigResponse(response)) {
|
|
7050
7413
|
throw new Error(
|
|
7051
7414
|
"Streamlabs response is missing the expected `settings` envelope. The widget may be private or the response format may have changed."
|
|
@@ -7095,9 +7458,61 @@ function importStreamlabsWidget(response, widgetType) {
|
|
|
7095
7458
|
coverage.mappings.push({
|
|
7096
7459
|
seType: `streamlabs:${widgetType}`,
|
|
7097
7460
|
lumiaType: "goal",
|
|
7098
|
-
status: "direct",
|
|
7461
|
+
status: built.requiresReview ? "partial" : "direct",
|
|
7099
7462
|
count: 1
|
|
7100
7463
|
});
|
|
7464
|
+
if (built.requiresReview) {
|
|
7465
|
+
reviewItems.push(
|
|
7466
|
+
customHtmlReviewItem(
|
|
7467
|
+
built.module.id,
|
|
7468
|
+
`streamlabs-${widgetType}`,
|
|
7469
|
+
response.settings,
|
|
7470
|
+
CUSTOM_HTML_REVIEW_REASON
|
|
7471
|
+
)
|
|
7472
|
+
);
|
|
7473
|
+
}
|
|
7474
|
+
} else if (widgetType === "chat_box") {
|
|
7475
|
+
const built = buildSLChatBox(response.settings);
|
|
7476
|
+
stampImportMeta(built.module, widgetType, "chatbox");
|
|
7477
|
+
layers.push(built.layer);
|
|
7478
|
+
modules[built.layer.id] = built.module;
|
|
7479
|
+
coverage.mappings.push({
|
|
7480
|
+
seType: "streamlabs:chat_box",
|
|
7481
|
+
lumiaType: "chatbox",
|
|
7482
|
+
status: built.requiresReview ? "partial" : "direct",
|
|
7483
|
+
count: 1
|
|
7484
|
+
});
|
|
7485
|
+
if (built.requiresReview) {
|
|
7486
|
+
reviewItems.push(
|
|
7487
|
+
customHtmlReviewItem(
|
|
7488
|
+
built.module.id,
|
|
7489
|
+
"streamlabs-chat_box",
|
|
7490
|
+
response.settings,
|
|
7491
|
+
CUSTOM_HTML_REVIEW_REASON
|
|
7492
|
+
)
|
|
7493
|
+
);
|
|
7494
|
+
}
|
|
7495
|
+
} else if (widgetType === "event_list") {
|
|
7496
|
+
const built = buildSLEventList(response.settings);
|
|
7497
|
+
stampImportMeta(built.module, widgetType, "eventlist");
|
|
7498
|
+
layers.push(built.layer);
|
|
7499
|
+
modules[built.layer.id] = built.module;
|
|
7500
|
+
coverage.mappings.push({
|
|
7501
|
+
seType: "streamlabs:event_list",
|
|
7502
|
+
lumiaType: "eventlist",
|
|
7503
|
+
status: built.requiresReview ? "partial" : "direct",
|
|
7504
|
+
count: 1
|
|
7505
|
+
});
|
|
7506
|
+
if (built.requiresReview) {
|
|
7507
|
+
reviewItems.push(
|
|
7508
|
+
customHtmlReviewItem(
|
|
7509
|
+
built.module.id,
|
|
7510
|
+
"streamlabs-event_list",
|
|
7511
|
+
response.settings,
|
|
7512
|
+
CUSTOM_HTML_REVIEW_REASON
|
|
7513
|
+
)
|
|
7514
|
+
);
|
|
7515
|
+
}
|
|
7101
7516
|
} else if (PLACEHOLDER_WIDGET_TYPES.has(widgetType)) {
|
|
7102
7517
|
const placeholder = buildPlaceholder(widgetType);
|
|
7103
7518
|
const reason = PLACEHOLDER_REASONS[widgetType] ?? "No native Lumia mapping yet.";
|
|
@@ -7146,7 +7561,7 @@ function importStreamlabsWidget(response, widgetType) {
|
|
|
7146
7561
|
uuid: "",
|
|
7147
7562
|
listen_id: "",
|
|
7148
7563
|
name: overlayName,
|
|
7149
|
-
description:
|
|
7564
|
+
description: buildSLDescription(widgetType, options.sourceUrl),
|
|
7150
7565
|
settings: {
|
|
7151
7566
|
metadata: { width: 1920, height: 1080 },
|
|
7152
7567
|
layers,
|
|
@@ -8730,7 +9145,12 @@ function SEImportWizard({
|
|
|
8730
9145
|
);
|
|
8731
9146
|
}
|
|
8732
9147
|
importedOverlays.push({
|
|
8733
|
-
result: importSEBootstrap(bootstrap
|
|
9148
|
+
result: importSEBootstrap(bootstrap, {
|
|
9149
|
+
// JWT-flow imports don't come from a pasted URL; synthesize
|
|
9150
|
+
// the SE dashboard URL so the description still carries a
|
|
9151
|
+
// useful traceback. Same shape SE editor links use.
|
|
9152
|
+
sourceUrl: `https://streamelements.com/dashboard/overlays/${overlayId}/editor`
|
|
9153
|
+
}),
|
|
8734
9154
|
summary
|
|
8735
9155
|
});
|
|
8736
9156
|
}
|
|
@@ -8775,7 +9195,9 @@ function SEImportWizard({
|
|
|
8775
9195
|
"StreamElements returned a payload that doesn't look like an overlay bootstrap."
|
|
8776
9196
|
);
|
|
8777
9197
|
}
|
|
8778
|
-
const imported = importSEBootstrap(bootstrap
|
|
9198
|
+
const imported = importSEBootstrap(bootstrap, {
|
|
9199
|
+
sourceUrl: `https://streamelements.com/dashboard/overlays/${overlayId}/editor`
|
|
9200
|
+
});
|
|
8779
9201
|
setBatchImports([{ result: imported, summary }]);
|
|
8780
9202
|
setResult(imported);
|
|
8781
9203
|
setAssetUrls(findSEAssetURLs(imported.overlay));
|
|
@@ -8863,7 +9285,9 @@ function SEImportWizard({
|
|
|
8863
9285
|
"Streamlabs returned a response that does not look like a widget config payload."
|
|
8864
9286
|
);
|
|
8865
9287
|
}
|
|
8866
|
-
const imported = importStreamlabsWidget(raw, slParts.widgetType
|
|
9288
|
+
const imported = importStreamlabsWidget(raw, slParts.widgetType, {
|
|
9289
|
+
sourceUrl: url
|
|
9290
|
+
});
|
|
8867
9291
|
setBatchImports([]);
|
|
8868
9292
|
setResult(imported);
|
|
8869
9293
|
setAssetUrls(findSEAssetURLs(imported.overlay));
|
|
@@ -8904,7 +9328,7 @@ function SEImportWizard({
|
|
|
8904
9328
|
"StreamElements returned a response that does not look like an Element widget payload."
|
|
8905
9329
|
);
|
|
8906
9330
|
}
|
|
8907
|
-
const imported = importElementOverlay(raw);
|
|
9331
|
+
const imported = importElementOverlay(raw, { sourceUrl: url });
|
|
8908
9332
|
setBatchImports([]);
|
|
8909
9333
|
setResult(imported);
|
|
8910
9334
|
setAssetUrls(findSEAssetURLs(imported.overlay));
|
|
@@ -8952,7 +9376,7 @@ function SEImportWizard({
|
|
|
8952
9376
|
...parts,
|
|
8953
9377
|
proxyFetch: bindings.proxyFetch
|
|
8954
9378
|
});
|
|
8955
|
-
const imported = importSEBootstrap(bootstrap);
|
|
9379
|
+
const imported = importSEBootstrap(bootstrap, { sourceUrl: url });
|
|
8956
9380
|
setBatchImports([]);
|
|
8957
9381
|
setResult(imported);
|
|
8958
9382
|
setAssetUrls(findSEAssetURLs(imported.overlay));
|
|
@@ -9611,7 +10035,7 @@ function extractErrorMessage(err) {
|
|
|
9611
10035
|
}
|
|
9612
10036
|
|
|
9613
10037
|
// src/se-import/element-dispatch.ts
|
|
9614
|
-
import {
|
|
10038
|
+
import { LumiaAlertValues as LumiaAlertValues3 } from "@lumiastream/lumia-types";
|
|
9615
10039
|
|
|
9616
10040
|
// src/se-import/element-types.ts
|
|
9617
10041
|
function isSEElementResponse(value) {
|
|
@@ -9855,34 +10279,8 @@ function translateAnimationName(name, fallback) {
|
|
|
9855
10279
|
if (PINNED_ANIMATION_MAP[name]) return PINNED_ANIMATION_MAP[name];
|
|
9856
10280
|
return name.replace(/-([a-z])/g, (_m, c) => c.toUpperCase());
|
|
9857
10281
|
}
|
|
9858
|
-
|
|
9859
|
-
|
|
9860
|
-
if (typeof raw !== "string") return fallbackMs;
|
|
9861
|
-
const trimmed = raw.trim();
|
|
9862
|
-
if (!trimmed) return fallbackMs;
|
|
9863
|
-
if (trimmed.endsWith("ms")) {
|
|
9864
|
-
const n2 = parseFloat(trimmed.slice(0, -2));
|
|
9865
|
-
return Number.isFinite(n2) ? n2 : fallbackMs;
|
|
9866
|
-
}
|
|
9867
|
-
if (trimmed.endsWith("s")) {
|
|
9868
|
-
const n2 = parseFloat(trimmed.slice(0, -1));
|
|
9869
|
-
return Number.isFinite(n2) ? n2 * 1e3 : fallbackMs;
|
|
9870
|
-
}
|
|
9871
|
-
const n = parseFloat(trimmed);
|
|
9872
|
-
return Number.isFinite(n) ? n : fallbackMs;
|
|
9873
|
-
}
|
|
9874
|
-
function parsePx2(raw) {
|
|
9875
|
-
if (typeof raw === "number" && Number.isFinite(raw)) return raw;
|
|
9876
|
-
if (typeof raw !== "string") return NaN;
|
|
9877
|
-
const trimmed = raw.trim();
|
|
9878
|
-
if (!trimmed) return NaN;
|
|
9879
|
-
if (trimmed.endsWith("px")) {
|
|
9880
|
-
const n2 = parseFloat(trimmed.slice(0, -2));
|
|
9881
|
-
return Number.isFinite(n2) ? n2 : NaN;
|
|
9882
|
-
}
|
|
9883
|
-
const n = parseFloat(trimmed);
|
|
9884
|
-
return Number.isFinite(n) ? n : NaN;
|
|
9885
|
-
}
|
|
10282
|
+
var parseAnimationDurationMs = parseDurationMs;
|
|
10283
|
+
var parsePx2 = (raw) => pxToNumber(raw, NaN);
|
|
9886
10284
|
function findFieldByType(fields, type) {
|
|
9887
10285
|
if (!fields) return void 0;
|
|
9888
10286
|
for (const f of Object.values(fields)) {
|
|
@@ -9958,6 +10356,47 @@ function buildAnimations(title) {
|
|
|
9958
10356
|
const visibleDurationMs = enterDelay + enterDuration + staticDuration + exitDuration;
|
|
9959
10357
|
return { animations, visibleDurationMs: visibleDurationMs || DEFAULT_DURATION_MS };
|
|
9960
10358
|
}
|
|
10359
|
+
function resolveFieldBoundsInCanvas(style, canvas, textContent) {
|
|
10360
|
+
if (!style) return null;
|
|
10361
|
+
const x = parsePx2(style.left);
|
|
10362
|
+
const y = parsePx2(style.top);
|
|
10363
|
+
const hasXY = Number.isFinite(x) || Number.isFinite(y);
|
|
10364
|
+
if (!hasXY && style.width == null && style.height == null) return null;
|
|
10365
|
+
const sx = Number.isFinite(x) ? x : 0;
|
|
10366
|
+
const sy = Number.isFinite(y) ? y : 0;
|
|
10367
|
+
let width = parsePx2(style.width);
|
|
10368
|
+
let height = parsePx2(style.height);
|
|
10369
|
+
if (!Number.isFinite(width)) width = Math.max(1, canvas.width - sx);
|
|
10370
|
+
if (!Number.isFinite(height)) {
|
|
10371
|
+
if (typeof textContent === "string") {
|
|
10372
|
+
const lineCount = (textContent.match(/\n/g)?.length ?? 0) + 1;
|
|
10373
|
+
const lhPx = parsePx2(style.lineHeight) || parsePx2(style["line-height"]);
|
|
10374
|
+
const fsPx = parsePx2(style.fontSize);
|
|
10375
|
+
let effectiveLh = lhPx;
|
|
10376
|
+
if (!Number.isFinite(effectiveLh) || effectiveLh < 8) {
|
|
10377
|
+
effectiveLh = Number.isFinite(fsPx) ? fsPx * 1.3 : 24 * 1.3;
|
|
10378
|
+
}
|
|
10379
|
+
height = Math.max(1, lineCount * effectiveLh);
|
|
10380
|
+
} else {
|
|
10381
|
+
height = Math.max(1, canvas.height - sy);
|
|
10382
|
+
}
|
|
10383
|
+
}
|
|
10384
|
+
return { x: sx, y: sy, width, height };
|
|
10385
|
+
}
|
|
10386
|
+
function unionBounds(boxes) {
|
|
10387
|
+
if (boxes.length === 0) return null;
|
|
10388
|
+
let minX = Infinity;
|
|
10389
|
+
let minY = Infinity;
|
|
10390
|
+
let maxX = -Infinity;
|
|
10391
|
+
let maxY = -Infinity;
|
|
10392
|
+
for (const b of boxes) {
|
|
10393
|
+
minX = Math.min(minX, b.x);
|
|
10394
|
+
minY = Math.min(minY, b.y);
|
|
10395
|
+
maxX = Math.max(maxX, b.x + b.width);
|
|
10396
|
+
maxY = Math.max(maxY, b.y + b.height);
|
|
10397
|
+
}
|
|
10398
|
+
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
10399
|
+
}
|
|
9961
10400
|
function buildElementAlertEvent(state, options = {}) {
|
|
9962
10401
|
const compositeFields = state.settings?.compositeFields;
|
|
9963
10402
|
const titleField = findFieldByType(compositeFields, "text");
|
|
@@ -9975,6 +10414,31 @@ function buildElementAlertEvent(state, options = {}) {
|
|
|
9975
10414
|
const titleStyle = titleField?.style;
|
|
9976
10415
|
const highlightColor = titleField?.highlightedStyle?.color ?? null;
|
|
9977
10416
|
const { animations, visibleDurationMs } = buildAnimations(titleField);
|
|
10417
|
+
const canvas = options.canvas ?? { width: 1920, height: 1080 };
|
|
10418
|
+
const mediaBounds = resolveFieldBoundsInCanvas(mainAsset?.style, canvas);
|
|
10419
|
+
const textBounds = resolveFieldBoundsInCanvas(titleStyle, canvas, rawMessage);
|
|
10420
|
+
const collected = [];
|
|
10421
|
+
if (mediaBounds) collected.push(mediaBounds);
|
|
10422
|
+
if (textBounds) collected.push(textBounds);
|
|
10423
|
+
let layerBounds = unionBounds(collected);
|
|
10424
|
+
if (!layerBounds) {
|
|
10425
|
+
layerBounds = {
|
|
10426
|
+
x: Math.round(canvas.width * 0.6),
|
|
10427
|
+
y: Math.round(canvas.height * 0.15),
|
|
10428
|
+
width: 400,
|
|
10429
|
+
height: 300
|
|
10430
|
+
};
|
|
10431
|
+
}
|
|
10432
|
+
let pushTextUp = 0;
|
|
10433
|
+
let pushTextLeft = 0;
|
|
10434
|
+
if (textBounds) {
|
|
10435
|
+
const desiredTextTopInLayer = textBounds.y - layerBounds.y;
|
|
10436
|
+
const naturalTextTopInLayer = Math.max(0, (layerBounds.height - textBounds.height) / 2);
|
|
10437
|
+
pushTextUp = Math.round(desiredTextTopInLayer - naturalTextTopInLayer);
|
|
10438
|
+
const desiredTextLeftInLayer = textBounds.x - layerBounds.x;
|
|
10439
|
+
const naturalTextLeftInLayer = Math.max(0, (layerBounds.width - textBounds.width) / 2);
|
|
10440
|
+
pushTextLeft = Math.round(desiredTextLeftInLayer - naturalTextLeftInLayer);
|
|
10441
|
+
}
|
|
9978
10442
|
const event = {
|
|
9979
10443
|
on: true,
|
|
9980
10444
|
// `'custom'` lowercase is load-bearing in Lumia's AlertBoxHandler —
|
|
@@ -9993,7 +10457,11 @@ function buildElementAlertEvent(state, options = {}) {
|
|
|
9993
10457
|
showBrandIcon: true
|
|
9994
10458
|
},
|
|
9995
10459
|
settings: { duration: visibleDurationMs },
|
|
9996
|
-
|
|
10460
|
+
// `textOver` matches SE Element's text-on-video render pattern.
|
|
10461
|
+
// `imageOver` / `column` / `row` would all stack the text outside
|
|
10462
|
+
// the media, which is the bug this layout fixes (text rendered
|
|
10463
|
+
// below the alert graphic instead of overlaid on it).
|
|
10464
|
+
layout: { value: "textOver", css: {}, customCss: "", pushTextUp, pushTextLeft },
|
|
9997
10465
|
text: {
|
|
9998
10466
|
css: titleCss(titleStyle),
|
|
9999
10467
|
messageCss: {},
|
|
@@ -10015,44 +10483,13 @@ function buildElementAlertEvent(state, options = {}) {
|
|
|
10015
10483
|
},
|
|
10016
10484
|
variations: []
|
|
10017
10485
|
};
|
|
10018
|
-
|
|
10019
|
-
let bounds;
|
|
10020
|
-
if (style) {
|
|
10021
|
-
const x = parsePx2(style.left);
|
|
10022
|
-
const y = parsePx2(style.top);
|
|
10023
|
-
const width = parsePx2(style.width);
|
|
10024
|
-
const height = parsePx2(style.height);
|
|
10025
|
-
if (Number.isFinite(x) && Number.isFinite(y) && Number.isFinite(width)) {
|
|
10026
|
-
bounds = {
|
|
10027
|
-
x,
|
|
10028
|
-
y,
|
|
10029
|
-
width,
|
|
10030
|
-
// Height isn't always present on video Main Assets (the video
|
|
10031
|
-
// aspect-ratios itself from the source). Fall back to a
|
|
10032
|
-
// reasonable default that matches SE's preview row.
|
|
10033
|
-
height: Number.isFinite(height) ? height : Math.round(width * 0.75)
|
|
10034
|
-
};
|
|
10035
|
-
}
|
|
10036
|
-
}
|
|
10037
|
-
return { event, bounds };
|
|
10486
|
+
return { event, bounds: layerBounds };
|
|
10038
10487
|
}
|
|
10039
10488
|
|
|
10040
10489
|
// src/se-import/mappers/element-scene.ts
|
|
10041
|
-
import { nanoid as nanoid8 } from "nanoid";
|
|
10042
10490
|
var TEXT_FALLBACK = { width: 400, height: 50 };
|
|
10043
10491
|
var IMAGE_FALLBACK = { width: 300, height: 100 };
|
|
10044
|
-
|
|
10045
|
-
if (typeof raw === "number" && Number.isFinite(raw)) return raw;
|
|
10046
|
-
if (typeof raw !== "string") return NaN;
|
|
10047
|
-
const trimmed = raw.trim();
|
|
10048
|
-
if (!trimmed) return NaN;
|
|
10049
|
-
if (trimmed.endsWith("px")) {
|
|
10050
|
-
const n2 = parseFloat(trimmed.slice(0, -2));
|
|
10051
|
-
return Number.isFinite(n2) ? n2 : NaN;
|
|
10052
|
-
}
|
|
10053
|
-
const n = parseFloat(trimmed);
|
|
10054
|
-
return Number.isFinite(n) ? n : NaN;
|
|
10055
|
-
}
|
|
10492
|
+
var parsePx3 = (raw) => pxToNumber(raw, NaN);
|
|
10056
10493
|
function styleToBounds(style, type, canvas) {
|
|
10057
10494
|
const x = Number.isFinite(parsePx3(style?.left)) ? parsePx3(style?.left) : 0;
|
|
10058
10495
|
const y = Number.isFinite(parsePx3(style?.top)) ? parsePx3(style?.top) : 0;
|
|
@@ -10088,33 +10525,17 @@ function styleToBounds(style, type, canvas) {
|
|
|
10088
10525
|
}
|
|
10089
10526
|
return { x, y, width, height };
|
|
10090
10527
|
}
|
|
10091
|
-
function
|
|
10092
|
-
|
|
10093
|
-
|
|
10094
|
-
|
|
10095
|
-
|
|
10096
|
-
bounds: {
|
|
10097
|
-
x: bounds.x,
|
|
10098
|
-
y: bounds.y,
|
|
10099
|
-
width: bounds.width,
|
|
10100
|
-
height: bounds.height,
|
|
10101
|
-
scale: [1, 1],
|
|
10102
|
-
zIndex
|
|
10103
|
-
}
|
|
10104
|
-
};
|
|
10105
|
-
}
|
|
10106
|
-
function buildModule(id, type, title, content, css = {}) {
|
|
10107
|
-
return {
|
|
10108
|
-
id,
|
|
10109
|
-
version: 1,
|
|
10110
|
-
loaded: true,
|
|
10111
|
-
settings: { type, title, locked: false },
|
|
10112
|
-
lights: [],
|
|
10113
|
-
css,
|
|
10528
|
+
function buildChild(groupId, zIndex, bounds, type, title, content, css = {}) {
|
|
10529
|
+
const { layer, module } = buildModuleEnvelope({
|
|
10530
|
+
type,
|
|
10531
|
+
title,
|
|
10532
|
+
bounds,
|
|
10114
10533
|
content,
|
|
10115
|
-
|
|
10116
|
-
|
|
10117
|
-
|
|
10534
|
+
css,
|
|
10535
|
+
parentGroupId: groupId,
|
|
10536
|
+
zIndex
|
|
10537
|
+
});
|
|
10538
|
+
return { layer, module };
|
|
10118
10539
|
}
|
|
10119
10540
|
function textStyleToCss(style) {
|
|
10120
10541
|
const s = style ?? {};
|
|
@@ -10129,80 +10550,69 @@ function textStyleToCss(style) {
|
|
|
10129
10550
|
return out;
|
|
10130
10551
|
}
|
|
10131
10552
|
function mapCompositeField(name, field, groupId, zIndex, provider, canvas) {
|
|
10132
|
-
const id = nanoid8();
|
|
10133
10553
|
switch (field.type) {
|
|
10134
10554
|
case "video": {
|
|
10135
|
-
const bounds = styleToBounds(field.style, "video", canvas);
|
|
10136
|
-
const layer = buildLayer(id, groupId, bounds, zIndex);
|
|
10137
10555
|
const src = pickFieldMediaHref(field.media, "video/");
|
|
10138
10556
|
const volume = typeof field.volume === "number" ? field.volume : 1;
|
|
10139
|
-
|
|
10140
|
-
|
|
10141
|
-
|
|
10142
|
-
|
|
10143
|
-
|
|
10144
|
-
|
|
10145
|
-
|
|
10146
|
-
|
|
10557
|
+
return buildChild(
|
|
10558
|
+
groupId,
|
|
10559
|
+
zIndex,
|
|
10560
|
+
styleToBounds(field.style, "video", canvas),
|
|
10561
|
+
"video",
|
|
10562
|
+
name,
|
|
10563
|
+
{ src, volume, loop: true, autoplay: true, muted: volume === 0 }
|
|
10564
|
+
);
|
|
10147
10565
|
}
|
|
10148
10566
|
case "image": {
|
|
10149
|
-
const bounds = styleToBounds(field.style, "image", canvas);
|
|
10150
|
-
const layer = buildLayer(id, groupId, bounds, zIndex);
|
|
10151
10567
|
const src = pickFieldMediaHref(field.media, "image/");
|
|
10152
|
-
|
|
10153
|
-
|
|
10568
|
+
return buildChild(
|
|
10569
|
+
groupId,
|
|
10570
|
+
zIndex,
|
|
10571
|
+
styleToBounds(field.style, "image", canvas),
|
|
10572
|
+
"image",
|
|
10573
|
+
name,
|
|
10574
|
+
{ src }
|
|
10575
|
+
);
|
|
10154
10576
|
}
|
|
10155
10577
|
case "text": {
|
|
10156
|
-
const bounds = styleToBounds(field.style, "text", canvas);
|
|
10157
|
-
const layer = buildLayer(id, groupId, bounds, zIndex);
|
|
10158
10578
|
const raw = field.text?.[0]?.content ?? "";
|
|
10159
10579
|
const value = substituteElementTokens(raw, { provider });
|
|
10160
|
-
|
|
10161
|
-
|
|
10580
|
+
return buildChild(
|
|
10581
|
+
groupId,
|
|
10582
|
+
zIndex,
|
|
10583
|
+
styleToBounds(field.style, "text", canvas),
|
|
10162
10584
|
"text",
|
|
10163
10585
|
name,
|
|
10164
10586
|
{ value, highlightColor: "inherit" },
|
|
10165
10587
|
textStyleToCss(field.style)
|
|
10166
10588
|
);
|
|
10167
|
-
return { layer, module };
|
|
10168
10589
|
}
|
|
10169
10590
|
case "audio": {
|
|
10170
|
-
const layer = buildLayer(id, groupId, { x: 0, y: 0, width: 1, height: 1 }, zIndex);
|
|
10171
10591
|
const src = pickFieldMediaHref(field.media, "audio/");
|
|
10172
10592
|
const volume = typeof field.volume === "number" ? field.volume : 0.5;
|
|
10173
|
-
|
|
10174
|
-
|
|
10593
|
+
return buildChild(
|
|
10594
|
+
groupId,
|
|
10595
|
+
zIndex,
|
|
10596
|
+
{ x: 0, y: 0, width: 1, height: 1 },
|
|
10597
|
+
"audio",
|
|
10598
|
+
name,
|
|
10599
|
+
{ src, volume, loop: false }
|
|
10600
|
+
);
|
|
10175
10601
|
}
|
|
10176
10602
|
default:
|
|
10177
10603
|
return null;
|
|
10178
10604
|
}
|
|
10179
10605
|
}
|
|
10180
10606
|
function buildElementScene(state, options) {
|
|
10181
|
-
const groupId = nanoid8();
|
|
10182
10607
|
const groupTitle = typeof state.displayName === "string" && state.displayName || state.referenceId || "Scene";
|
|
10183
|
-
const groupLayer = {
|
|
10184
|
-
id: groupId,
|
|
10608
|
+
const { id: groupId, layer: groupLayer, module: groupModule } = buildModuleEnvelope({
|
|
10185
10609
|
type: "group",
|
|
10186
|
-
|
|
10187
|
-
bounds: {
|
|
10188
|
-
|
|
10189
|
-
|
|
10190
|
-
|
|
10191
|
-
|
|
10192
|
-
scale: [1, 1]
|
|
10193
|
-
},
|
|
10194
|
-
state: { visible: true, locked: false, expanded: false }
|
|
10195
|
-
};
|
|
10196
|
-
const groupModule = {
|
|
10197
|
-
id: groupId,
|
|
10198
|
-
loaded: true,
|
|
10199
|
-
settings: { type: "group", title: groupTitle },
|
|
10200
|
-
lights: [],
|
|
10201
|
-
css: {},
|
|
10202
|
-
content: {},
|
|
10203
|
-
variables: {},
|
|
10204
|
-
events: {}
|
|
10205
|
-
};
|
|
10610
|
+
title: groupTitle,
|
|
10611
|
+
bounds: { x: 0, y: 0, width: options.canvas.width, height: options.canvas.height },
|
|
10612
|
+
type_layer: "group",
|
|
10613
|
+
parentGroupId: null,
|
|
10614
|
+
expanded: false
|
|
10615
|
+
});
|
|
10206
10616
|
const children = [];
|
|
10207
10617
|
const fields = state.settings?.compositeFields ?? {};
|
|
10208
10618
|
let zIndex = 1;
|
|
@@ -10221,7 +10631,12 @@ function buildElementScene(state, options) {
|
|
|
10221
10631
|
}
|
|
10222
10632
|
|
|
10223
10633
|
// src/se-import/element-dispatch.ts
|
|
10224
|
-
|
|
10634
|
+
function buildElementDescription(widgetInstanceId, sourceUrl) {
|
|
10635
|
+
return buildImportDescription(
|
|
10636
|
+
`Imported from StreamElements Element widget ${widgetInstanceId}`,
|
|
10637
|
+
sourceUrl
|
|
10638
|
+
);
|
|
10639
|
+
}
|
|
10225
10640
|
function elementAlertKindToLumiaKeys(kind, provider) {
|
|
10226
10641
|
switch (kind) {
|
|
10227
10642
|
case "follower":
|
|
@@ -10240,9 +10655,9 @@ function elementAlertKindToLumiaKeys(kind, provider) {
|
|
|
10240
10655
|
return alertBoxKeysFor("charityCampaignDonation", provider);
|
|
10241
10656
|
case "subscriberGift":
|
|
10242
10657
|
case "communityGiftPurchase": {
|
|
10243
|
-
if (provider === "twitch") return [
|
|
10244
|
-
if (provider === "kick") return [
|
|
10245
|
-
if (provider === "youtube") return [
|
|
10658
|
+
if (provider === "twitch") return [LumiaAlertValues3.TWITCH_GIFT_SUBSCRIPTION];
|
|
10659
|
+
if (provider === "kick") return [LumiaAlertValues3.KICK_GIFT_SUBSCRIPTION];
|
|
10660
|
+
if (provider === "youtube") return [LumiaAlertValues3.YOUTUBE_GIFT_MEMBERS];
|
|
10246
10661
|
return alertBoxKeysFor("subscriber", provider);
|
|
10247
10662
|
}
|
|
10248
10663
|
default:
|
|
@@ -10257,7 +10672,7 @@ function buildCombinedAlertModule(alertStates, provider, canvas) {
|
|
|
10257
10672
|
for (const state of alertStates) {
|
|
10258
10673
|
const cls = classifyConfigState(state);
|
|
10259
10674
|
if (cls.kind !== "alert") continue;
|
|
10260
|
-
const { event, bounds: bounds2 } = buildElementAlertEvent(state, { provider });
|
|
10675
|
+
const { event, bounds: bounds2 } = buildElementAlertEvent(state, { provider, canvas });
|
|
10261
10676
|
const keys = elementAlertKindToLumiaKeys(cls.alertKind, provider);
|
|
10262
10677
|
if (keys.length === 0) continue;
|
|
10263
10678
|
for (const key of keys) {
|
|
@@ -10269,61 +10684,42 @@ function buildCombinedAlertModule(alertStates, provider, canvas) {
|
|
|
10269
10684
|
}
|
|
10270
10685
|
}
|
|
10271
10686
|
if (Object.keys(events).length === 0) return null;
|
|
10272
|
-
const id = nanoid9();
|
|
10273
10687
|
const bounds = firstBounds ?? {
|
|
10274
10688
|
x: Math.round(canvas.width * 0.6),
|
|
10275
10689
|
y: Math.round(canvas.height * 0.15),
|
|
10276
10690
|
width: 400,
|
|
10277
10691
|
height: 300
|
|
10278
10692
|
};
|
|
10279
|
-
const layer = {
|
|
10280
|
-
id,
|
|
10281
|
-
state: { visible: true, locked: false },
|
|
10282
|
-
bounds: {
|
|
10283
|
-
x: bounds.x,
|
|
10284
|
-
y: bounds.y,
|
|
10285
|
-
width: bounds.width,
|
|
10286
|
-
height: bounds.height,
|
|
10287
|
-
scale: [1, 1]
|
|
10288
|
-
}
|
|
10289
|
-
};
|
|
10290
10693
|
const baseAlert = firstEvent ? stripEventOnlyFields2(firstEvent) : {};
|
|
10291
|
-
const module = {
|
|
10292
|
-
|
|
10293
|
-
|
|
10294
|
-
|
|
10295
|
-
settings: { type: "alert", title: "Alerts (Element import)", locked: false },
|
|
10296
|
-
lights: [],
|
|
10297
|
-
css: {},
|
|
10298
|
-
content: {},
|
|
10299
|
-
variables: {},
|
|
10300
|
-
events: {},
|
|
10694
|
+
const { layer, module } = buildModuleEnvelope({
|
|
10695
|
+
type: "alert",
|
|
10696
|
+
title: "Alerts (Element import)",
|
|
10697
|
+
bounds,
|
|
10301
10698
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
10302
10699
|
alert: { ...baseAlert, events }
|
|
10303
|
-
};
|
|
10700
|
+
});
|
|
10304
10701
|
return { layer, module };
|
|
10305
10702
|
}
|
|
10306
10703
|
function stripEventOnlyFields2(event) {
|
|
10307
|
-
const {
|
|
10704
|
+
const {
|
|
10705
|
+
on: _on,
|
|
10706
|
+
variations: _variations,
|
|
10707
|
+
matchEmptyCondition: _mec,
|
|
10708
|
+
...base
|
|
10709
|
+
} = event;
|
|
10308
10710
|
return base;
|
|
10309
10711
|
}
|
|
10310
10712
|
function stampImportMeta2(module, state, role) {
|
|
10311
|
-
module
|
|
10312
|
-
|
|
10313
|
-
|
|
10314
|
-
|
|
10315
|
-
|
|
10316
|
-
|
|
10317
|
-
|
|
10318
|
-
displayName: state?.displayName,
|
|
10319
|
-
importedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
10320
|
-
}
|
|
10321
|
-
};
|
|
10713
|
+
stampImportMetaMerge(module, {
|
|
10714
|
+
source: "streamelements-element",
|
|
10715
|
+
role,
|
|
10716
|
+
referenceId: state?.referenceId,
|
|
10717
|
+
categoryId: state?.categoryId,
|
|
10718
|
+
displayName: state?.displayName
|
|
10719
|
+
});
|
|
10322
10720
|
}
|
|
10323
|
-
function importElementOverlay(response) {
|
|
10324
|
-
const configData = parseElementConfigData(
|
|
10325
|
-
response.widgetInstanceConfigVersion.configData
|
|
10326
|
-
);
|
|
10721
|
+
function importElementOverlay(response, options = {}) {
|
|
10722
|
+
const configData = parseElementConfigData(response.widgetInstanceConfigVersion.configData);
|
|
10327
10723
|
if (!configData) {
|
|
10328
10724
|
throw new Error(
|
|
10329
10725
|
"StreamElements Element response carries an invalid configData payload. The widget may be corrupted or the response format may have changed."
|
|
@@ -10393,7 +10789,10 @@ function importElementOverlay(response) {
|
|
|
10393
10789
|
uuid: "",
|
|
10394
10790
|
listen_id: "",
|
|
10395
10791
|
name: response.widgetInstance.displayName ? `[SE Element] ${response.widgetInstance.displayName}` : `Imported from StreamElements Element (${response.widgetInstance.widgetInstanceId})`,
|
|
10396
|
-
description:
|
|
10792
|
+
description: buildElementDescription(
|
|
10793
|
+
response.widgetInstance.widgetInstanceId,
|
|
10794
|
+
options.sourceUrl
|
|
10795
|
+
),
|
|
10397
10796
|
settings: {
|
|
10398
10797
|
metadata: { width: canvas.width, height: canvas.height },
|
|
10399
10798
|
layers,
|
|
@@ -10407,7 +10806,7 @@ function importElementOverlay(response) {
|
|
|
10407
10806
|
}
|
|
10408
10807
|
|
|
10409
10808
|
// src/se-import/index.ts
|
|
10410
|
-
var
|
|
10809
|
+
var IMPORT_META_KEY2 = "importMeta";
|
|
10411
10810
|
var REVIEW_REASONS = {
|
|
10412
10811
|
"se-widget-bit-boss": "No native Lumia equivalent \u2014 bit boss fight bar with HP/damage states.",
|
|
10413
10812
|
// `se-widget-hype-cup` intentionally omitted — it now routes to the native
|
|
@@ -10437,6 +10836,10 @@ function reasonFor(seType, status, flaggedOff) {
|
|
|
10437
10836
|
if (flaggedOff && FLAG_OFF_REASONS[seType]) return FLAG_OFF_REASONS[seType];
|
|
10438
10837
|
return REVIEW_REASONS[seType] ?? (status === "template" ? "Imported as a generic template stub." : "No native mapping yet \u2014 imported as a labelled text placeholder.");
|
|
10439
10838
|
}
|
|
10839
|
+
function buildSEBootstrapDescription(overlayId, sourceUrl) {
|
|
10840
|
+
const head = overlayId ? `Imported from StreamElements overlay ${overlayId}` : "Imported from StreamElements";
|
|
10841
|
+
return buildImportDescription(head, sourceUrl);
|
|
10842
|
+
}
|
|
10440
10843
|
function extractSEOverlayId(input) {
|
|
10441
10844
|
const trimmed = input.trim();
|
|
10442
10845
|
const m = trimmed.match(/[0-9a-f]{24}/i);
|
|
@@ -10491,7 +10894,7 @@ function isSEBootstrap(value) {
|
|
|
10491
10894
|
const o = v.overlay;
|
|
10492
10895
|
return Array.isArray(o.widgets);
|
|
10493
10896
|
}
|
|
10494
|
-
function importSEBootstrap(bootstrap) {
|
|
10897
|
+
function importSEBootstrap(bootstrap, options = {}) {
|
|
10495
10898
|
const seOverlay = bootstrap.overlay;
|
|
10496
10899
|
const widgets = seOverlay?.widgets ?? [];
|
|
10497
10900
|
const coverage = {
|
|
@@ -10514,7 +10917,7 @@ function importSEBootstrap(bootstrap) {
|
|
|
10514
10917
|
if (w.type !== "se-widget-group") continue;
|
|
10515
10918
|
const uid = w.variables?.uid;
|
|
10516
10919
|
if (typeof uid !== "string") continue;
|
|
10517
|
-
const lumiaGroupId =
|
|
10920
|
+
const lumiaGroupId = nanoid8();
|
|
10518
10921
|
seUidToLumiaGroupId[uid] = lumiaGroupId;
|
|
10519
10922
|
groupWidgetByUid[uid] = w;
|
|
10520
10923
|
}
|
|
@@ -10553,7 +10956,7 @@ function importSEBootstrap(bootstrap) {
|
|
|
10553
10956
|
lights: [],
|
|
10554
10957
|
css: {},
|
|
10555
10958
|
content: {
|
|
10556
|
-
[
|
|
10959
|
+
[IMPORT_META_KEY2]: {
|
|
10557
10960
|
source: "streamelements",
|
|
10558
10961
|
widgetType: w.type,
|
|
10559
10962
|
importedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -10591,7 +10994,7 @@ function importSEBootstrap(bootstrap) {
|
|
|
10591
10994
|
if (result.status === "placeholder" || result.status === "template") {
|
|
10592
10995
|
module.content = {
|
|
10593
10996
|
...module.content ?? {},
|
|
10594
|
-
[
|
|
10997
|
+
[IMPORT_META_KEY2]: {
|
|
10595
10998
|
source: "streamelements",
|
|
10596
10999
|
widgetType: w.type,
|
|
10597
11000
|
importedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -10631,7 +11034,7 @@ function importSEBootstrap(bootstrap) {
|
|
|
10631
11034
|
uuid: "",
|
|
10632
11035
|
listen_id: "",
|
|
10633
11036
|
name: seOverlay?.name ? `[SE] ${seOverlay.name}` : `Imported from StreamElements (${seOverlay?._id ?? ""})`,
|
|
10634
|
-
description: seOverlay?._id
|
|
11037
|
+
description: buildSEBootstrapDescription(seOverlay?._id, options.sourceUrl),
|
|
10635
11038
|
settings: {
|
|
10636
11039
|
metadata: {
|
|
10637
11040
|
width: seOverlay?.settings?.width ?? 1920,
|
|
@@ -10679,7 +11082,7 @@ function applyReviewAction(result, moduleId, action, payload) {
|
|
|
10679
11082
|
bounds: existingLayer.bounds,
|
|
10680
11083
|
state: existingLayer.state
|
|
10681
11084
|
};
|
|
10682
|
-
const importMeta2 = existing2.content?.[
|
|
11085
|
+
const importMeta2 = existing2.content?.[IMPORT_META_KEY2];
|
|
10683
11086
|
const mergedLights = (existing2.lights?.length ?? 0) > 0 ? existing2.lights : transplant.module.lights;
|
|
10684
11087
|
const mergedEvents = existing2.events && Object.keys(existing2.events).length > 0 ? { ...transplant.module.events, ...existing2.events } : transplant.module.events;
|
|
10685
11088
|
const mergedVariables = existing2.variables && Object.keys(existing2.variables).length > 0 ? { ...transplant.module.variables, ...existing2.variables } : transplant.module.variables;
|
|
@@ -10691,7 +11094,7 @@ function applyReviewAction(result, moduleId, action, payload) {
|
|
|
10691
11094
|
variables: mergedVariables,
|
|
10692
11095
|
content: {
|
|
10693
11096
|
...transplant.module.content ?? {},
|
|
10694
|
-
[
|
|
11097
|
+
[IMPORT_META_KEY2]: importMeta2
|
|
10695
11098
|
}
|
|
10696
11099
|
};
|
|
10697
11100
|
const rootOldNewId = transplant.layer.id;
|
|
@@ -10719,7 +11122,7 @@ function applyReviewAction(result, moduleId, action, payload) {
|
|
|
10719
11122
|
const existing = modules[moduleId];
|
|
10720
11123
|
const generated = payload;
|
|
10721
11124
|
if (!existing || !generated) return result;
|
|
10722
|
-
const importMeta = existing.content?.[
|
|
11125
|
+
const importMeta = existing.content?.[IMPORT_META_KEY2];
|
|
10723
11126
|
const replaced = {
|
|
10724
11127
|
...existing,
|
|
10725
11128
|
settings: { ...existing.settings ?? {}, type: "custom" },
|
|
@@ -10733,7 +11136,7 @@ function applyReviewAction(result, moduleId, action, payload) {
|
|
|
10733
11136
|
data: parseLooseJson(generated.data) ?? {},
|
|
10734
11137
|
configs: parseLooseJson(generated.configs) ?? [],
|
|
10735
11138
|
flavor: "ai-generated",
|
|
10736
|
-
[
|
|
11139
|
+
[IMPORT_META_KEY2]: importMeta
|
|
10737
11140
|
}
|
|
10738
11141
|
};
|
|
10739
11142
|
modules[moduleId] = replaced;
|