From 1df2c622b79d1a36521db9cc00a79817cc2bb6f8 Mon Sep 17 00:00:00 2001 From: dennisrijsdijk Date: Mon, 21 Oct 2024 21:25:45 +0200 Subject: [PATCH 1/5] feat: allow passing predicate for eventMetaKey --- src/backend/events/filters/filter-factory.ts | 28 +++++++++++++------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/backend/events/filters/filter-factory.ts b/src/backend/events/filters/filter-factory.ts index 7242a8b77..239b6c7f7 100644 --- a/src/backend/events/filters/filter-factory.ts +++ b/src/backend/events/filters/filter-factory.ts @@ -1,15 +1,20 @@ import { EventFilter } from "../../../types/events"; import { ComparisonType } from "../../../shared/filter-constants"; +type EventData = { + eventSourceId: string; + eventId: string; + eventMeta: Record; +} + +type FilterEvent = Omit; + type FilterConfig = { id: string; name: string; description: string; - events: Array<{ - eventSourceId: string; - eventId: string; - }>; - eventMetaKey: string; + events: Array; + eventMetaKey: string | ((eventData: EventData) => string); caseInsensitive?: boolean; }; @@ -59,6 +64,12 @@ function compareValue( } } +function getMetaKey(eventMetaKey: FilterConfig["eventMetaKey"], event: EventData): string { + if (typeof eventMetaKey === "function") { + return eventMetaKey(event); + } + return eventMetaKey; +} export function createTextFilter({ eventMetaKey, @@ -73,7 +84,7 @@ export function createTextFilter({ const { comparisonType, value } = filterSettings; const { eventMeta } = eventData; - let eventValue = eventMeta[eventMetaKey] ?? ""; + let eventValue = eventMeta[getMetaKey(eventMetaKey, eventData)] ?? ""; if (caseInsensitive) { eventValue = eventValue.toString().toLowerCase(); } @@ -99,7 +110,7 @@ export function createNumberFilter({ const { comparisonType, value } = filterSettings; const { eventMeta } = eventData; - const eventValue = eventMeta[eventMetaKey] ?? 0; + const eventValue = eventMeta[getMetaKey(eventMetaKey, eventData)] ?? 0; return compareValue(comparisonType, value, eventValue); } @@ -118,10 +129,9 @@ export function createTextOrNumberFilter({ const { comparisonType, value: filterValue } = filterSettings; const { eventMeta } = eventData; - const eventValue = eventMeta[eventMetaKey] ?? ""; + const eventValue = eventMeta[getMetaKey(eventMetaKey, eventData)] ?? ""; return compareValue(comparisonType, filterValue, eventValue); } }; } - From 45f953db11d6ed11f4fe6355d2c34cb1b0c25d78 Mon Sep 17 00:00:00 2001 From: dennisrijsdijk Date: Mon, 21 Oct 2024 21:53:14 +0200 Subject: [PATCH 2/5] feat: expand selection of comparison types --- src/backend/events/filters/filter-factory.ts | 53 +++++++++++++++++--- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/src/backend/events/filters/filter-factory.ts b/src/backend/events/filters/filter-factory.ts index 239b6c7f7..b883d1b99 100644 --- a/src/backend/events/filters/filter-factory.ts +++ b/src/backend/events/filters/filter-factory.ts @@ -22,18 +22,35 @@ const TEXT_COMPARISON_TYPES = [ ComparisonType.IS, ComparisonType.IS_NOT, ComparisonType.CONTAINS, - ComparisonType.MATCHES_REGEX + ComparisonType.DOESNT_CONTAIN, + ComparisonType.STARTS_WITH, + ComparisonType.DOESNT_STARTS_WITH, + ComparisonType.ENDS_WITH, + ComparisonType.DOESNT_END_WITH, + ComparisonType.MATCHES_REGEX_CS, + ComparisonType.DOESNT_MATCH_REGEX_CS, + ComparisonType.MATCHES_REGEX, + ComparisonType.DOESNT_MATCH_REGEX ]; -const NUMBER_COMPARISON_TYPES = [ - ComparisonType.IS, - ComparisonType.IS_NOT, +const NUMBER_UNIQUE_COMPARISON_TYPES = [ ComparisonType.LESS_THAN, ComparisonType.LESS_THAN_OR_EQUAL_TO, ComparisonType.GREATER_THAN, ComparisonType.GREATER_THAN_OR_EQUAL_TO ]; +const NUMBER_COMPARISON_TYPES = [ + ComparisonType.IS, + ComparisonType.IS_NOT, + ...NUMBER_UNIQUE_COMPARISON_TYPES +]; + +const NUMBER_TEXT_COMPARISON_TYPES = [ + ...TEXT_COMPARISON_TYPES, + ...NUMBER_UNIQUE_COMPARISON_TYPES +]; + function compareValue( comparisonType: ComparisonType, @@ -45,6 +62,18 @@ function compareValue( return actualValue === expectedValue; case ComparisonType.IS_NOT: return actualValue !== expectedValue; + case ComparisonType.CONTAINS: + return actualValue?.toString().includes(expectedValue?.toString() ?? ""); + case ComparisonType.DOESNT_CONTAIN: + return !actualValue?.toString().includes(expectedValue?.toString() ?? ""); + case ComparisonType.STARTS_WITH: + return actualValue?.toString().startsWith(expectedValue?.toString() ?? ""); + case ComparisonType.DOESNT_STARTS_WITH: + return !actualValue?.toString().startsWith(expectedValue?.toString() ?? ""); + case ComparisonType.ENDS_WITH: + return actualValue?.toString().endsWith(expectedValue?.toString() ?? ""); + case ComparisonType.DOESNT_END_WITH: + return !actualValue?.toString().endsWith(expectedValue?.toString() ?? ""); case ComparisonType.LESS_THAN: return actualValue < expectedValue; case ComparisonType.LESS_THAN_OR_EQUAL_TO: @@ -53,12 +82,22 @@ function compareValue( return actualValue > expectedValue; case ComparisonType.GREATER_THAN_OR_EQUAL_TO: return actualValue >= expectedValue; - case ComparisonType.CONTAINS: - return actualValue?.toString().includes(expectedValue?.toString() ?? ""); case ComparisonType.MATCHES_REGEX: { const regex = new RegExp(expectedValue?.toString() ?? "", "gi"); return regex.test(actualValue?.toString() ?? ""); } + case ComparisonType.DOESNT_MATCH_REGEX: { + const regex = new RegExp(expectedValue?.toString() ?? "", "gi"); + return !regex.test(actualValue?.toString() ?? ""); + } + case ComparisonType.MATCHES_REGEX_CS: { + const regex = new RegExp(expectedValue?.toString() ?? "", "g"); + return regex.test(actualValue?.toString() ?? ""); + } + case ComparisonType.DOESNT_MATCH_REGEX_CS: { + const regex = new RegExp(expectedValue?.toString() ?? "", "g"); + return !regex.test(actualValue?.toString() ?? ""); + } default: return false; } @@ -123,7 +162,7 @@ export function createTextOrNumberFilter({ }: Omit): Omit { return { ...config, - comparisonTypes: [...TEXT_COMPARISON_TYPES, ...NUMBER_COMPARISON_TYPES], + comparisonTypes: NUMBER_TEXT_COMPARISON_TYPES, valueType: "text", async predicate(filterSettings, eventData) { const { comparisonType, value: filterValue } = filterSettings; From c7a6965621ee04eb01e9c88630c57a1cd7663afa Mon Sep 17 00:00:00 2001 From: dennisrijsdijk Date: Sun, 27 Oct 2024 23:43:10 +0100 Subject: [PATCH 3/5] refactor: event filters --- .../events/filters/builtin-filter-loader.js | 45 ----------- .../events/filters/builtin-filter-loader.ts | 8 ++ .../events/filters/builtin/bits-badge-tier.js | 51 ------------ .../filters/builtin/chat-mode-duration.js | 55 ------------- .../filters/builtin/chat-mode-setting.js | 54 ------------- .../filters/builtin/cheer-bits-amount.js | 51 ------------ .../events/filters/builtin/currency.js | 43 ---------- .../filters/builtin/custom-variable-name.ts | 72 ----------------- .../events/filters/builtin/donation-amount.js | 55 ------------- .../events/filters/builtin/donation-from.js | 47 ----------- .../events/filters/builtin/effect-queue.js | 46 ----------- .../filters/builtin/firebot/currency.ts | 20 +++++ .../builtin/firebot/custom-variable-name.ts | 19 +++++ .../filters/builtin/firebot/effect-queue.ts | 22 ++++++ .../events/filters/builtin/firebot/index.ts | 33 ++++++++ .../builtin/{ => firebot}/metadata-key.ts | 6 +- .../builtin/{ => firebot}/metadata-value.ts | 6 +- .../new-currency-amount.ts} | 14 ++-- .../filters/builtin/firebot/new-rank.ts | 32 ++++++++ .../filters/builtin/firebot/new-view-time.ts | 13 ++++ .../previous-currency-amount.ts} | 10 +-- .../filters/builtin/firebot/previous-rank.ts | 32 ++++++++ .../builtin/firebot/previous-view-time.ts | 13 ++++ .../filters/builtin/firebot/rank-ladder.ts | 18 +++++ .../builtin/firebot/rank-transition-type.ts | 25 ++++++ .../viewer-ranks.ts} | 25 +++--- .../viewer-roles.ts} | 38 +++++---- .../events/filters/builtin/gift-count.js | 51 ------------ .../events/filters/builtin/gift-duration.js | 51 ------------ src/backend/events/filters/builtin/index.ts | 9 +++ .../events/filters/builtin/is-anonymous.js | 45 ----------- src/backend/events/filters/builtin/message.js | 75 ------------------ .../events/filters/builtin/new-rank.js | 54 ------------- .../events/filters/builtin/new-view-time.js | 51 ------------ .../events/filters/builtin/previous-rank.js | 54 ------------- .../filters/builtin/previous-view-time.js | 51 ------------ .../filters/builtin/raid-viewer-count.js | 51 ------------ .../events/filters/builtin/rank-ladder.js | 43 ---------- .../filters/builtin/rank-transition-type.js | 37 --------- .../events/filters/builtin/reward-name.js | 38 --------- src/backend/events/filters/builtin/reward.js | 53 ------------- .../events/filters/builtin/shared-chat.ts | 44 ----------- .../events/filters/builtin/stream-category.js | 37 --------- .../events/filters/builtin/sub-kind.js | 50 ------------ .../events/filters/builtin/sub-type.js | 71 ----------------- .../builtin/third-party/donation-amount.ts | 17 ++++ .../builtin/third-party/donation-from.ts | 18 +++++ .../filters/builtin/third-party/index.ts | 7 ++ .../filters/builtin/twitch/bits-badge-tier.ts | 13 ++++ .../builtin/twitch/chat-mode-duration.ts | 13 ++++ .../builtin/twitch/chat-mode-setting.ts | 23 ++++++ .../{chat-mode.js => twitch/chat-mode.ts} | 41 ++++------ .../builtin/twitch/cheer-bits-amount.ts | 13 ++++ .../filters/builtin/twitch/gift-count.ts | 13 ++++ .../filters/builtin/twitch/gift-duration.ts | 13 ++++ .../events/filters/builtin/twitch/index.ts | 37 +++++++++ .../filters/builtin/twitch/is-anonymous.ts | 25 ++++++ .../events/filters/builtin/twitch/message.ts | 14 ++++ .../builtin/twitch/raid-viewer-count.ts | 14 ++++ .../filters/builtin/twitch/reward-name.ts | 14 ++++ .../events/filters/builtin/twitch/reward.ts | 22 ++++++ .../filters/builtin/twitch/shared-chat.ts | 26 +++++++ .../filters/builtin/twitch/stream-category.ts | 15 ++++ .../events/filters/builtin/twitch/sub-kind.ts | 23 ++++++ .../events/filters/builtin/twitch/sub-type.ts | 35 +++++++++ .../{username.js => twitch/username.ts} | 38 ++------- src/backend/events/filters/filter-factory.ts | 78 ++++++++++++++++--- .../builtin/obs/filters/group-name-filter.ts | 2 +- .../builtin/obs/filters/scene-name-filter.ts | 2 +- src/backend/utility.js | 36 +++++++-- src/types/events.d.ts | 22 +++++- 71 files changed, 786 insertions(+), 1506 deletions(-) delete mode 100644 src/backend/events/filters/builtin-filter-loader.js create mode 100644 src/backend/events/filters/builtin-filter-loader.ts delete mode 100644 src/backend/events/filters/builtin/bits-badge-tier.js delete mode 100644 src/backend/events/filters/builtin/chat-mode-duration.js delete mode 100644 src/backend/events/filters/builtin/chat-mode-setting.js delete mode 100644 src/backend/events/filters/builtin/cheer-bits-amount.js delete mode 100644 src/backend/events/filters/builtin/currency.js delete mode 100644 src/backend/events/filters/builtin/custom-variable-name.ts delete mode 100644 src/backend/events/filters/builtin/donation-amount.js delete mode 100644 src/backend/events/filters/builtin/donation-from.js delete mode 100644 src/backend/events/filters/builtin/effect-queue.js create mode 100644 src/backend/events/filters/builtin/firebot/currency.ts create mode 100644 src/backend/events/filters/builtin/firebot/custom-variable-name.ts create mode 100644 src/backend/events/filters/builtin/firebot/effect-queue.ts create mode 100644 src/backend/events/filters/builtin/firebot/index.ts rename src/backend/events/filters/builtin/{ => firebot}/metadata-key.ts (65%) rename src/backend/events/filters/builtin/{ => firebot}/metadata-value.ts (66%) rename src/backend/events/filters/builtin/{new-currency-amount.js => firebot/new-currency-amount.ts} (56%) create mode 100644 src/backend/events/filters/builtin/firebot/new-rank.ts create mode 100644 src/backend/events/filters/builtin/firebot/new-view-time.ts rename src/backend/events/filters/builtin/{previous-currency-amount.js => firebot/previous-currency-amount.ts} (69%) create mode 100644 src/backend/events/filters/builtin/firebot/previous-rank.ts create mode 100644 src/backend/events/filters/builtin/firebot/previous-view-time.ts create mode 100644 src/backend/events/filters/builtin/firebot/rank-ladder.ts create mode 100644 src/backend/events/filters/builtin/firebot/rank-transition-type.ts rename src/backend/events/filters/builtin/{viewer-ranks.js => firebot/viewer-ranks.ts} (82%) rename src/backend/events/filters/builtin/{viewer-roles.js => firebot/viewer-roles.ts} (82%) delete mode 100644 src/backend/events/filters/builtin/gift-count.js delete mode 100644 src/backend/events/filters/builtin/gift-duration.js create mode 100644 src/backend/events/filters/builtin/index.ts delete mode 100644 src/backend/events/filters/builtin/is-anonymous.js delete mode 100644 src/backend/events/filters/builtin/message.js delete mode 100644 src/backend/events/filters/builtin/new-rank.js delete mode 100644 src/backend/events/filters/builtin/new-view-time.js delete mode 100644 src/backend/events/filters/builtin/previous-rank.js delete mode 100644 src/backend/events/filters/builtin/previous-view-time.js delete mode 100644 src/backend/events/filters/builtin/raid-viewer-count.js delete mode 100644 src/backend/events/filters/builtin/rank-ladder.js delete mode 100644 src/backend/events/filters/builtin/rank-transition-type.js delete mode 100644 src/backend/events/filters/builtin/reward-name.js delete mode 100644 src/backend/events/filters/builtin/reward.js delete mode 100644 src/backend/events/filters/builtin/shared-chat.ts delete mode 100644 src/backend/events/filters/builtin/stream-category.js delete mode 100644 src/backend/events/filters/builtin/sub-kind.js delete mode 100644 src/backend/events/filters/builtin/sub-type.js create mode 100644 src/backend/events/filters/builtin/third-party/donation-amount.ts create mode 100644 src/backend/events/filters/builtin/third-party/donation-from.ts create mode 100644 src/backend/events/filters/builtin/third-party/index.ts create mode 100644 src/backend/events/filters/builtin/twitch/bits-badge-tier.ts create mode 100644 src/backend/events/filters/builtin/twitch/chat-mode-duration.ts create mode 100644 src/backend/events/filters/builtin/twitch/chat-mode-setting.ts rename src/backend/events/filters/builtin/{chat-mode.js => twitch/chat-mode.ts} (57%) create mode 100644 src/backend/events/filters/builtin/twitch/cheer-bits-amount.ts create mode 100644 src/backend/events/filters/builtin/twitch/gift-count.ts create mode 100644 src/backend/events/filters/builtin/twitch/gift-duration.ts create mode 100644 src/backend/events/filters/builtin/twitch/index.ts create mode 100644 src/backend/events/filters/builtin/twitch/is-anonymous.ts create mode 100644 src/backend/events/filters/builtin/twitch/message.ts create mode 100644 src/backend/events/filters/builtin/twitch/raid-viewer-count.ts create mode 100644 src/backend/events/filters/builtin/twitch/reward-name.ts create mode 100644 src/backend/events/filters/builtin/twitch/reward.ts create mode 100644 src/backend/events/filters/builtin/twitch/shared-chat.ts create mode 100644 src/backend/events/filters/builtin/twitch/stream-category.ts create mode 100644 src/backend/events/filters/builtin/twitch/sub-kind.ts create mode 100644 src/backend/events/filters/builtin/twitch/sub-type.ts rename src/backend/events/filters/builtin/{username.js => twitch/username.ts} (56%) diff --git a/src/backend/events/filters/builtin-filter-loader.js b/src/backend/events/filters/builtin-filter-loader.js deleted file mode 100644 index 7dab5b353..000000000 --- a/src/backend/events/filters/builtin-filter-loader.js +++ /dev/null @@ -1,45 +0,0 @@ -"use strict"; - -const filterManager = require("./filter-manager"); - -exports.loadFilters = () => { - [ - 'bits-badge-tier', - 'chat-mode-duration', - 'chat-mode-setting', - 'chat-mode', - 'cheer-bits-amount', - 'currency', - 'custom-variable-name', - 'donation-amount', - 'donation-from', - 'effect-queue', - 'gift-count', - 'gift-duration', - 'is-anonymous', - 'message', - 'metadata-key', - 'metadata-value', - 'new-currency-amount', - 'new-rank', - 'new-view-time', - 'previous-currency-amount', - 'previous-rank', - 'previous-view-time', - 'raid-viewer-count', - 'rank-ladder', - 'rank-transition-type', - 'reward-name', - 'reward', - 'shared-chat', - 'stream-category', - 'sub-kind', - 'sub-type', - 'username', - 'viewer-ranks', - 'viewer-roles' - ].forEach((filename) => { - const definition = require(`./builtin/${filename}`); - filterManager.registerFilter(definition); - }); -}; \ No newline at end of file diff --git a/src/backend/events/filters/builtin-filter-loader.ts b/src/backend/events/filters/builtin-filter-loader.ts new file mode 100644 index 000000000..57ed1fde7 --- /dev/null +++ b/src/backend/events/filters/builtin-filter-loader.ts @@ -0,0 +1,8 @@ +import filterManager from "./filter-manager"; +import filters from "./builtin"; + +export function loadFilters() { + for (const definition of filters) { + filterManager.registerFilter(definition); + } +} \ No newline at end of file diff --git a/src/backend/events/filters/builtin/bits-badge-tier.js b/src/backend/events/filters/builtin/bits-badge-tier.js deleted file mode 100644 index 1adc248ed..000000000 --- a/src/backend/events/filters/builtin/bits-badge-tier.js +++ /dev/null @@ -1,51 +0,0 @@ -"use strict"; - -const { ComparisonType } = require("../../../../shared/filter-constants"); - -module.exports = { - id: "firebot:bits-badge-tier", - name: "Bits Badge Tier", - description: "Filter by the tier of the bits badge that was unlocked (100, 1000, 5000, etc.).", - events: [ - { eventSourceId: "twitch", eventId: "bits-badge-unlocked" } - ], - comparisonTypes: [ - ComparisonType.IS, - ComparisonType.IS_NOT, - ComparisonType.LESS_THAN, - ComparisonType.LESS_THAN_OR_EQUAL_TO, - ComparisonType.GREATER_THAN, - ComparisonType.GREATER_THAN_OR_EQUAL_TO - ], - valueType: "number", - predicate: (filterSettings, eventData) => { - - const { comparisonType, value } = filterSettings; - const { eventMeta } = eventData; - - const badgeTier = eventMeta.badgeTier || 0; - - switch (comparisonType) { - case ComparisonType.IS: { - return badgeTier === value; - } - case ComparisonType.IS_NOT: { - return badgeTier !== value; - } - case ComparisonType.LESS_THAN: { - return badgeTier < value; - } - case ComparisonType.LESS_THAN_OR_EQUAL_TO: { - return badgeTier <= value; - } - case ComparisonType.GREATER_THAN: { - return badgeTier > value; - } - case ComparisonType.GREATER_THAN_OR_EQUAL_TO: { - return badgeTier >= value; - } - default: - return false; - } - } -}; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/chat-mode-duration.js b/src/backend/events/filters/builtin/chat-mode-duration.js deleted file mode 100644 index 628fe4329..000000000 --- a/src/backend/events/filters/builtin/chat-mode-duration.js +++ /dev/null @@ -1,55 +0,0 @@ -"use strict"; - -const { ComparisonType } = require("../../../../shared/filter-constants"); - -module.exports = { - id: "firebot:chatmodeduration", - name: "Duration", - description: "Filter by a chat mode's duration (only for Slow (seconds) and Follower (minutes))", - events: [ - { eventSourceId: "twitch", eventId: "chat-mode-changed" } - ], - comparisonTypes: [ - ComparisonType.IS, - ComparisonType.IS_NOT, - ComparisonType.LESS_THAN, - ComparisonType.LESS_THAN_OR_EQUAL_TO, - ComparisonType.GREATER_THAN, - ComparisonType.GREATER_THAN_OR_EQUAL_TO - ], - valueType: "number", - predicate: (filterSettings, eventData) => { - - const { comparisonType, value } = filterSettings; - const { eventMeta } = eventData; - - const duration = eventMeta.duration; - - if (duration == null) { - return true; - } - - switch (comparisonType) { - case ComparisonType.IS: { - return duration === value; - } - case ComparisonType.IS_NOT: { - return duration !== value; - } - case ComparisonType.LESS_THAN: { - return duration < value; - } - case ComparisonType.LESS_THAN_OR_EQUAL_TO: { - return duration <= value; - } - case ComparisonType.GREATER_THAN: { - return duration > value; - } - case ComparisonType.GREATER_THAN_OR_EQUAL_TO: { - return duration >= value; - } - default: - return false; - } - } -}; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/chat-mode-setting.js b/src/backend/events/filters/builtin/chat-mode-setting.js deleted file mode 100644 index fd7839bd3..000000000 --- a/src/backend/events/filters/builtin/chat-mode-setting.js +++ /dev/null @@ -1,54 +0,0 @@ -"use strict"; - -const { ComparisonType } = require("../../../../shared/filter-constants"); - -module.exports = { - id: "firebot:chatmodesetting", - name: "Setting", - description: "Filter by a chat mode's setting", - events: [ - { eventSourceId: "twitch", eventId: "chat-mode-changed" } - ], - comparisonTypes: [ComparisonType.IS], - valueType: "preset", - presetValues: () => { - return [ - { - value: "enabled", - display: "Enabled" - }, - { - value: "disabled", - display: "Disabled" - } - ]; - }, - getSelectedValueDisplay: (filterSettings) => { - switch (filterSettings.value) { - case "enabled": - return "Enabled"; - case "disabled": - return "Disabled"; - default: - return "[Not set]"; - } - }, - predicate: async (filterSettings, eventData) => { - - const { value } = filterSettings; - const { eventMeta } = eventData; - - const chatModeStateEnabled = eventMeta.chatModeState === "enabled"; - - switch (value) { - case "enabled": { - return chatModeStateEnabled; - } - case "disabled": { - return !chatModeStateEnabled; - } - default: - return !chatModeStateEnabled; - } - } -}; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/cheer-bits-amount.js b/src/backend/events/filters/builtin/cheer-bits-amount.js deleted file mode 100644 index 8e34a68fd..000000000 --- a/src/backend/events/filters/builtin/cheer-bits-amount.js +++ /dev/null @@ -1,51 +0,0 @@ -"use strict"; - -const { ComparisonType } = require("../../../../shared/filter-constants"); - -module.exports = { - id: "firebot:cheerbitsamount", - name: "Cheer Bits Amount", - description: "Filter by the amount of bits in a Cheer", - events: [ - { eventSourceId: "twitch", eventId: "cheer" } - ], - comparisonTypes: [ - ComparisonType.IS, - ComparisonType.IS_NOT, - ComparisonType.LESS_THAN, - ComparisonType.LESS_THAN_OR_EQUAL_TO, - ComparisonType.GREATER_THAN, - ComparisonType.GREATER_THAN_OR_EQUAL_TO - ], - valueType: "number", - predicate: (filterSettings, eventData) => { - - const { comparisonType, value } = filterSettings; - const { eventMeta } = eventData; - - const bitsAmount = eventMeta.bits || 0; - - switch (comparisonType) { - case ComparisonType.IS: { - return bitsAmount === value; - } - case ComparisonType.IS_NOT: { - return bitsAmount !== value; - } - case ComparisonType.LESS_THAN: { - return bitsAmount < value; - } - case ComparisonType.LESS_THAN_OR_EQUAL_TO: { - return bitsAmount <= value; - } - case ComparisonType.GREATER_THAN: { - return bitsAmount > value; - } - case ComparisonType.GREATER_THAN_OR_EQUAL_TO: { - return bitsAmount >= value; - } - default: - return false; - } - } -}; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/currency.js b/src/backend/events/filters/builtin/currency.js deleted file mode 100644 index 2594cf857..000000000 --- a/src/backend/events/filters/builtin/currency.js +++ /dev/null @@ -1,43 +0,0 @@ -"use strict"; - -module.exports = { - id: "firebot:currency", - name: "Currency", - description: "Filter to a Currency", - events: [ - { eventSourceId: "firebot", eventId: "currency-update" } - ], - comparisonTypes: ["is", "is not"], - valueType: "preset", - presetValues: currencyService => { - return currencyService - .getCurrencies().map(c => ({value: c.id, display: c.name})); - }, - valueIsStillValid: (filterSettings, currencyService) => { - return new Promise(resolve => { - resolve(currencyService.getCurrencies().some(c => c.id === filterSettings.value)); - }); - }, - getSelectedValueDisplay: (filterSettings, currencyService) => { - return new Promise(resolve => { - resolve(currencyService.getCurrencies().find(c => c.id === filterSettings.value)?.name ?? "Unknown Currency"); - }); - }, - predicate: (filterSettings, eventData) => { - - const { comparisonType, value } = filterSettings; - const { eventMeta } = eventData; - - const actual = eventMeta.currencyId; - const expected = value; - - switch (comparisonType) { - case "is": - return actual === expected; - case "is not": - return actual !== expected; - default: - return false; - } - } -}; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/custom-variable-name.ts b/src/backend/events/filters/builtin/custom-variable-name.ts deleted file mode 100644 index 3d372cacc..000000000 --- a/src/backend/events/filters/builtin/custom-variable-name.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { ComparisonType } from "../../../../shared/filter-constants"; - -module.exports = { - id: "firebot:custom-variable-name", - name: "Custom Variable Name", - description: "Filter to a Custom Variable by Name", - events: [ - { eventSourceId: "firebot", eventId: "custom-variable-set" }, - { eventSourceId: "firebot", eventId: "custom-variable-expired" } - ], - comparisonTypes: [ - ComparisonType.IS, - ComparisonType.IS_NOT, - ComparisonType.CONTAINS, - ComparisonType.DOESNT_CONTAIN, - ComparisonType.STARTS_WITH, - ComparisonType.DOESNT_STARTS_WITH, - ComparisonType.ENDS_WITH, - ComparisonType.DOESNT_END_WITH, - ComparisonType.MATCHES_REGEX_CS, - ComparisonType.DOESNT_MATCH_REGEX_CS, - ComparisonType.MATCHES_REGEX, - ComparisonType.DOESNT_MATCH_REGEX - ], - valueType: "text", - predicate: (filterSettings, eventData) => { - - const { comparisonType, value } = filterSettings; - const { eventMeta } = eventData; - - // normalize - const actual = eventMeta.createdCustomVariableName ?? eventMeta.expiredCustomVariableName ?? ""; - const expected = value ?? ""; - - switch (comparisonType) { - case ComparisonType.IS: - return actual === expected; - case ComparisonType.IS_NOT: - return actual !== expected; - case ComparisonType.CONTAINS: - return actual.includes(expected); - case ComparisonType.DOESNT_CONTAIN: - return !actual.includes(expected); - case ComparisonType.STARTS_WITH: - return actual.startsWith(expected); - case ComparisonType.DOESNT_STARTS_WITH: - return !actual.startsWith(expected); - case ComparisonType.ENDS_WITH: - return actual.endsWith(expected); - case ComparisonType.DOESNT_END_WITH: - return !actual.endsWith(expected); - case ComparisonType.MATCHES_REGEX: { - const regex = new RegExp(expected, "gi"); - return regex.test(actual); - } - case ComparisonType.DOESNT_MATCH_REGEX: { - const regex = new RegExp(expected, "gi"); - return !regex.test(actual); - } - case ComparisonType.MATCHES_REGEX_CS: { - const regex = new RegExp(expected, "g"); - return regex.test(actual); - } - case ComparisonType.DOESNT_MATCH_REGEX_CS: { - const regex = new RegExp(expected, "g"); - return !regex.test(actual); - } - default: - return false; - } - } -}; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/donation-amount.js b/src/backend/events/filters/builtin/donation-amount.js deleted file mode 100644 index 06c69223b..000000000 --- a/src/backend/events/filters/builtin/donation-amount.js +++ /dev/null @@ -1,55 +0,0 @@ -"use strict"; - -const { ComparisonType } = require("../../../../shared/filter-constants"); - -module.exports = { - id: "firebot:donation-amount", - name: "Donation Amount", - description: "Filter by the amount of donation from StreamLabs/Tipeee/ExtraLife", - events: [ - { eventSourceId: "streamlabs", eventId: "donation" }, - { eventSourceId: "streamlabs", eventId: "eldonation" }, - { eventSourceId: "extralife", eventId: "donation" }, - { eventSourceId: "tipeeestream", eventId: "donation" }, - { eventSourceId: "streamelements", eventId: "donation" } - ], - comparisonTypes: [ - ComparisonType.IS, - ComparisonType.IS_NOT, - ComparisonType.LESS_THAN, - ComparisonType.LESS_THAN_OR_EQUAL_TO, - ComparisonType.GREATER_THAN, - ComparisonType.GREATER_THAN_OR_EQUAL_TO - ], - valueType: "number", - predicate: (filterSettings, eventData) => { - - const { comparisonType, value } = filterSettings; - const { eventMeta } = eventData; - - const donationAmount = eventMeta.donationAmount || 0; - - switch (comparisonType) { - case ComparisonType.IS: { - return donationAmount === value; - } - case ComparisonType.IS_NOT: { - return donationAmount !== value; - } - case ComparisonType.LESS_THAN: { - return donationAmount < value; - } - case ComparisonType.LESS_THAN_OR_EQUAL_TO: { - return donationAmount <= value; - } - case ComparisonType.GREATER_THAN: { - return donationAmount > value; - } - case ComparisonType.GREATER_THAN_OR_EQUAL_TO: { - return donationAmount >= value; - } - default: - return false; - } - } -}; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/donation-from.js b/src/backend/events/filters/builtin/donation-from.js deleted file mode 100644 index 7fb5a9607..000000000 --- a/src/backend/events/filters/builtin/donation-from.js +++ /dev/null @@ -1,47 +0,0 @@ -"use strict"; - -const { ComparisonType } = require("../../../../shared/filter-constants"); - -module.exports = { - id: "firebot:donationfrom", - name: "Donation From", - description: "Filter to a specific donation sender", - events: [ - { eventSourceId: "streamlabs", eventId: "donation" }, - { eventSourceId: "streamlabs", eventId: "eldonation" }, - { eventSourceId: "extralife", eventId: "donation" }, - { eventSourceId: "tipeeestream", eventId: "donation" }, - { eventSourceId: "streamelements", eventId: "donation" } - ], - comparisonTypes: [ComparisonType.IS, ComparisonType.IS_NOT, ComparisonType.CONTAINS, ComparisonType.MATCHES_REGEX], - valueType: "text", - /*presetValues: () => { - return new Promise(resolve => { - return [{value: 1, display: "one"}]; - }); - },*/ - predicate: (filterSettings, eventData) => { - - const { comparisonType, value } = filterSettings; - const { eventMeta } = eventData; - - // normalize usernames - const eventUsername = eventMeta.from ? eventMeta.from.toLowerCase() : ""; - const filterUsername = value ? value.toLowerCase() : ""; - - switch (comparisonType) { - case ComparisonType.IS: - return eventUsername === filterUsername; - case ComparisonType.IS_NOT: - return eventUsername !== filterUsername; - case ComparisonType.CONTAINS: - return eventUsername.includes(filterUsername); - case ComparisonType.MATCHES_REGEX: { - const regex = new RegExp(filterUsername, "gi"); - return regex.test(eventUsername); - } - default: - return false; - } - } -}; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/effect-queue.js b/src/backend/events/filters/builtin/effect-queue.js deleted file mode 100644 index b17d9c77a..000000000 --- a/src/backend/events/filters/builtin/effect-queue.js +++ /dev/null @@ -1,46 +0,0 @@ -"use strict"; - -module.exports = { - id: "firebot:effect-queue", - name: "Effect Queue", - description: "Filter to a Effect Queue", - events: [ - { eventSourceId: "firebot", eventId: "effect-queue-added" }, - { eventSourceId: "firebot", eventId: "effect-queue-cleared" }, - { eventSourceId: "firebot", eventId: "effect-queue-status" } - ], - comparisonTypes: ["is", "is not"], - valueType: "preset", - presetValues: (effectQueuesService) => { - return effectQueuesService.getEffectQueues().map((c) => ({ value: c.id, display: c.name })); - }, - valueIsStillValid: (filterSettings, effectQueuesService) => { - return new Promise((resolve) => { - resolve(effectQueuesService.getEffectQueues().some((c) => c.id === filterSettings.value)); - }); - }, - getSelectedValueDisplay: (filterSettings, effectQueuesService) => { - return new Promise((resolve) => { - resolve( - effectQueuesService.getEffectQueues().find((c) => c.id === filterSettings.value)?.name ?? - "Unknown Effect Queue" - ); - }); - }, - predicate: (filterSettings, eventData) => { - const { comparisonType, value } = filterSettings; - const { eventMeta } = eventData; - - const actual = eventMeta.effectQueueId; - const expected = value; - - switch (comparisonType) { - case "is": - return actual === expected; - case "is not": - return actual !== expected; - default: - return false; - } - } -}; diff --git a/src/backend/events/filters/builtin/firebot/currency.ts b/src/backend/events/filters/builtin/firebot/currency.ts new file mode 100644 index 000000000..5fe172827 --- /dev/null +++ b/src/backend/events/filters/builtin/firebot/currency.ts @@ -0,0 +1,20 @@ +import { createPresetFilter } from "../../filter-factory"; + +const filter = createPresetFilter({ + id: "firebot:currency", + name: "Currency", + description: "Filter to a Currency", + events: [ + { eventSourceId: "firebot", eventId: "currency-update" } + ], + eventMetaKey: "currencyId", + allowIsNot: true, + presetValues: async (currencyService: any) => { + return currencyService.getCurrencies().map(c => ({value: c.id, display: c.name})); + }, + valueIsStillValid: async (filterSettings, currencyService: any) => { + return currencyService.getCurrencies().some(c => c.id === filterSettings.value); + } +}); + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/firebot/custom-variable-name.ts b/src/backend/events/filters/builtin/firebot/custom-variable-name.ts new file mode 100644 index 000000000..709d97280 --- /dev/null +++ b/src/backend/events/filters/builtin/firebot/custom-variable-name.ts @@ -0,0 +1,19 @@ +import { createTextFilter } from "../../filter-factory"; + +const filter = createTextFilter({ + id: "firebot:custom-variable-name", + name: "Custom Variable Name", + description: "Filter to a Custom Variable by Name", + eventMetaKey: ({eventId}) => { + if (eventId === "custom-variable-set") { + return "createdCustomVariableName"; + } + return "expiredCustomVariableName"; + }, + events: [ + { eventSourceId: "firebot", eventId: "custom-variable-set" }, + { eventSourceId: "firebot", eventId: "custom-variable-expired" } + ] +}); + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/firebot/effect-queue.ts b/src/backend/events/filters/builtin/firebot/effect-queue.ts new file mode 100644 index 000000000..88046ef97 --- /dev/null +++ b/src/backend/events/filters/builtin/firebot/effect-queue.ts @@ -0,0 +1,22 @@ +import { createPresetFilter } from "../../filter-factory"; + +const filter = createPresetFilter({ + id: "firebot:effect-queue", + name: "Effect Queue", + description: "Filter to a Effect Queue", + events: [ + { eventSourceId: "firebot", eventId: "effect-queue-added" }, + { eventSourceId: "firebot", eventId: "effect-queue-cleared" }, + { eventSourceId: "firebot", eventId: "effect-queue-status" } + ], + eventMetaKey: "effectQueueId", + allowIsNot: true, + presetValues: async (effectQueuesService: any) => { + return effectQueuesService.getEffectQueues().map(c => ({ value: c.id, display: c.name })); + }, + valueIsStillValid: async (filterSettings, effectQueuesService: any) => { + return effectQueuesService.getEffectQueues().some(c => c.id === filterSettings.value); + } +}); + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/firebot/index.ts b/src/backend/events/filters/builtin/firebot/index.ts new file mode 100644 index 000000000..78cf83899 --- /dev/null +++ b/src/backend/events/filters/builtin/firebot/index.ts @@ -0,0 +1,33 @@ +import currency from "./currency"; +import customVariableName from "./custom-variable-name"; +import effectQueue from "./effect-queue"; +import metadataKey from "./metadata-key"; +import metadataValue from "./metadata-value"; +import newCurrencyAmount from "./new-currency-amount"; +import newRank from "./new-rank"; +import newViewTime from "./new-view-time"; +import previousCurrencyAmount from "./previous-currency-amount"; +import previousRank from "./previous-rank"; +import previousViewTime from "./previous-view-time"; +import rankLadder from "./rank-ladder"; +import rankTransitionType from "./rank-transition-type"; +import viewerRanks from "./viewer-ranks"; +import viewerRoles from "./viewer-roles"; + +export default [ + currency, + customVariableName, + effectQueue, + metadataKey, + metadataValue, + newCurrencyAmount, + newRank, + newViewTime, + previousCurrencyAmount, + previousRank, + previousViewTime, + rankLadder, + rankTransitionType, + viewerRanks, + viewerRoles +]; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/metadata-key.ts b/src/backend/events/filters/builtin/firebot/metadata-key.ts similarity index 65% rename from src/backend/events/filters/builtin/metadata-key.ts rename to src/backend/events/filters/builtin/firebot/metadata-key.ts index 604ff3815..e1d4d5e83 100644 --- a/src/backend/events/filters/builtin/metadata-key.ts +++ b/src/backend/events/filters/builtin/firebot/metadata-key.ts @@ -1,6 +1,6 @@ -import { createTextFilter } from "../filter-factory"; +import { createTextFilter } from "../../filter-factory"; -const metadataKeyFilter = createTextFilter({ +const filter = createTextFilter({ id: "firebot:metadata-key", name: "Metadata Key", description: "Filters events based on the metadata key.", @@ -10,4 +10,4 @@ const metadataKeyFilter = createTextFilter({ ] }); -module.exports = metadataKeyFilter; +export default filter; diff --git a/src/backend/events/filters/builtin/metadata-value.ts b/src/backend/events/filters/builtin/firebot/metadata-value.ts similarity index 66% rename from src/backend/events/filters/builtin/metadata-value.ts rename to src/backend/events/filters/builtin/firebot/metadata-value.ts index f06682ed0..87c3c08bc 100644 --- a/src/backend/events/filters/builtin/metadata-value.ts +++ b/src/backend/events/filters/builtin/firebot/metadata-value.ts @@ -1,6 +1,6 @@ -import { createTextOrNumberFilter } from "../filter-factory"; +import { createTextOrNumberFilter } from "../../filter-factory"; -const metadataValueFilter = createTextOrNumberFilter({ +const filter = createTextOrNumberFilter({ id: "firebot:metadata-value", name: "Metadata Value", description: "Filters events based on the metadata value. Only works with text or number value types.", @@ -10,4 +10,4 @@ const metadataValueFilter = createTextOrNumberFilter({ ] }); -module.exports = metadataValueFilter; +export default filter; diff --git a/src/backend/events/filters/builtin/new-currency-amount.js b/src/backend/events/filters/builtin/firebot/new-currency-amount.ts similarity index 56% rename from src/backend/events/filters/builtin/new-currency-amount.js rename to src/backend/events/filters/builtin/firebot/new-currency-amount.ts index 71da991c4..67a463dc0 100644 --- a/src/backend/events/filters/builtin/new-currency-amount.js +++ b/src/backend/events/filters/builtin/firebot/new-currency-amount.ts @@ -1,13 +1,13 @@ -"use strict"; +import { createNumberFilter } from "../../filter-factory"; -const { createNumberFilter } = require("../filter-factory"); - -module.exports = createNumberFilter({ +const filter = createNumberFilter({ id: "firebot:new-currency-amount", name: "New Currency Amount", description: "Filter by the viewers new currency amount", + eventMetaKey: "newCurrencyAmount", events: [ { eventSourceId: "firebot", eventId: "currency-update" } - ], - eventMetaKey: "newCurrencyAmount" -}); \ No newline at end of file + ] +}); + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/firebot/new-rank.ts b/src/backend/events/filters/builtin/firebot/new-rank.ts new file mode 100644 index 000000000..e5029b482 --- /dev/null +++ b/src/backend/events/filters/builtin/firebot/new-rank.ts @@ -0,0 +1,32 @@ +import { createPresetFilter } from "../../filter-factory"; + +const filter = createPresetFilter({ + id: "firebot:new-rank", + name: "New Rank", + description: "Filter to a given new rank", + events: [ + { eventSourceId: "firebot", eventId: "viewer-rank-updated" } + ], + eventMetaKey: "newRankId", + allowIsNot: true, + presetValues: async (viewerRanksService: any) => viewerRanksService + .rankLadders + .flatMap(l => l + .ranks + .map(r => ({ value: r.id, display: `${r.name} (${l.name})`})) + ), + valueIsStillValid: async (filterSettings, viewerRanksService: any) => viewerRanksService + .rankLadders + .find(l => l.ranks?.some(r => r.id === filterSettings.value)) != null, + getSelectedValueDisplay: (filterSettings, viewerRanksService: any) => { + const ladderWithRank = viewerRanksService + .rankLadders + .find(l => l.ranks?.some(r => r.id === filterSettings.value)); + + const rank = ladderWithRank?.ranks?.find(r => r.id === filterSettings.value); + + return rank ? `${rank?.name} (${ladderWithRank?.name})` : "Not set"; + } +}); + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/firebot/new-view-time.ts b/src/backend/events/filters/builtin/firebot/new-view-time.ts new file mode 100644 index 000000000..907ef3180 --- /dev/null +++ b/src/backend/events/filters/builtin/firebot/new-view-time.ts @@ -0,0 +1,13 @@ +import { createNumberFilter } from "../../filter-factory"; + +const filter = createNumberFilter({ + id: "firebot:new-view-time", + name: "New View Time", + description: "Filter a viewers new view time (hours)", + eventMetaKey: "newViewTime", + events: [ + { eventSourceId: "firebot", eventId: "view-time-update" } + ] +}); + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/previous-currency-amount.js b/src/backend/events/filters/builtin/firebot/previous-currency-amount.ts similarity index 69% rename from src/backend/events/filters/builtin/previous-currency-amount.js rename to src/backend/events/filters/builtin/firebot/previous-currency-amount.ts index 32e73961b..565f8237e 100644 --- a/src/backend/events/filters/builtin/previous-currency-amount.js +++ b/src/backend/events/filters/builtin/firebot/previous-currency-amount.ts @@ -1,8 +1,6 @@ -"use strict"; +import { createNumberFilter } from "../../filter-factory"; -const { createNumberFilter } = require("../filter-factory"); - -module.exports = createNumberFilter({ +const filter = createNumberFilter({ id: "firebot:previous-currency-amount", name: "Previous Currency Amount", description: "Filter by the viewers previous currency amount", @@ -10,4 +8,6 @@ module.exports = createNumberFilter({ events: [ { eventSourceId: "firebot", eventId: "currency-update" } ] -}); \ No newline at end of file +}); + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/firebot/previous-rank.ts b/src/backend/events/filters/builtin/firebot/previous-rank.ts new file mode 100644 index 000000000..18c26ec1c --- /dev/null +++ b/src/backend/events/filters/builtin/firebot/previous-rank.ts @@ -0,0 +1,32 @@ +import { createPresetFilter } from "../../filter-factory"; + +const filter = createPresetFilter({ + id: "firebot:previous-rank", + name: "Previous Rank", + description: "Filter to a given previous rank", + events: [ + { eventSourceId: "firebot", eventId: "viewer-rank-updated" } + ], + eventMetaKey: "previousRankId", + allowIsNot: true, + presetValues: async (viewerRanksService: any) => viewerRanksService + .rankLadders + .flatMap(l => l + .ranks + .map(r => ({ value: r.id, display: `${r.name} (${l.name})`})) + ), + valueIsStillValid: async (filterSettings, viewerRanksService: any) => viewerRanksService + .rankLadders + .find(l => l.ranks?.some(r => r.id === filterSettings.value)) != null, + getSelectedValueDisplay: (filterSettings, viewerRanksService: any) => { + const ladderWithRank = viewerRanksService + .rankLadders + .find(l => l.ranks?.some(r => r.id === filterSettings.value)); + + const rank = ladderWithRank?.ranks?.find(r => r.id === filterSettings.value); + + return rank ? `${rank?.name} (${ladderWithRank?.name})` : "Not set"; + } +}); + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/firebot/previous-view-time.ts b/src/backend/events/filters/builtin/firebot/previous-view-time.ts new file mode 100644 index 000000000..7043ea7b3 --- /dev/null +++ b/src/backend/events/filters/builtin/firebot/previous-view-time.ts @@ -0,0 +1,13 @@ +import { createNumberFilter } from "../../filter-factory"; + +const filter = createNumberFilter({ + id: "firebot:previous-view-time", + name: "Previous View Time", + description: "Filter a viewers previous view time (hours)", + eventMetaKey: "previousViewTime", + events: [ + { eventSourceId: "firebot", eventId: "view-time-update" } + ] +}); + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/firebot/rank-ladder.ts b/src/backend/events/filters/builtin/firebot/rank-ladder.ts new file mode 100644 index 000000000..0a11e3ccc --- /dev/null +++ b/src/backend/events/filters/builtin/firebot/rank-ladder.ts @@ -0,0 +1,18 @@ +import { createPresetFilter } from "../../filter-factory"; + +const filter = createPresetFilter({ + id: "firebot:rank-ladder", + name: "Rank Ladder", + description: "Filter to a given rank ladder", + events: [ + { eventSourceId: "firebot", eventId: "viewer-rank-updated" } + ], + eventMetaKey: "rankLadderId", + allowIsNot: true, + presetValues: async (viewerRanksService: any) => viewerRanksService + .rankLadders.map(l => ({value: l.id, display: l.name})), + valueIsStillValid: async (filterSettings, viewerRanksService: any) => viewerRanksService + .getRankLadder(filterSettings.value) != null +}); + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/firebot/rank-transition-type.ts b/src/backend/events/filters/builtin/firebot/rank-transition-type.ts new file mode 100644 index 000000000..9b220c9f8 --- /dev/null +++ b/src/backend/events/filters/builtin/firebot/rank-transition-type.ts @@ -0,0 +1,25 @@ +import { createPresetFilter } from "../../filter-factory"; + +const filter = createPresetFilter({ + id: "firebot:rank-transition-type", + name: "Rank Transition Type", + description: "Filter to a given rank transition type (promotion or demotion)", + events: [ + { eventSourceId: "firebot", eventId: "viewer-rank-updated" } + ], + eventMetaKey: (eventData, filterSettings) => { + if (filterSettings.value === "Promotion") { + return "isPromotion"; + } + if (filterSettings.value === "Demotion") { + return "isDemotion"; + } + return ""; + }, + presetValues: () => [ + { value: "Promotion", display: "Promotion" }, + { value: "Demotion", display: "Demotion" } + ] +}); + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/viewer-ranks.js b/src/backend/events/filters/builtin/firebot/viewer-ranks.ts similarity index 82% rename from src/backend/events/filters/builtin/viewer-ranks.js rename to src/backend/events/filters/builtin/firebot/viewer-ranks.ts index 45ede6aa1..8da5b20fd 100644 --- a/src/backend/events/filters/builtin/viewer-ranks.js +++ b/src/backend/events/filters/builtin/firebot/viewer-ranks.ts @@ -1,9 +1,8 @@ -"use strict"; +import twitchApi from "../../../../twitch-api/api"; +import viewerDatabase from "../../../../viewers/viewer-database"; +import { EventFilter } from "../../../../../types/events"; -const twitchApi = require("../../../twitch-api/api"); -const viewerDatabase = require("../../../viewers/viewer-database"); - -module.exports = { +const filter: EventFilter = { id: "firebot:viewerranks", name: "Viewer's Ranks", description: "Filter to a given viewer rank", @@ -25,12 +24,12 @@ module.exports = { ], comparisonTypes: ["include", "doesn't include"], valueType: "preset", - presetValues: (viewerRanksService) => { + presetValues: (viewerRanksService: any) => { return viewerRanksService .rankLadders - .flatMap(l => l.ranks.map(r => ({value: `${l.id}:${r.id}`, display: `${r.name} (${l.name})`}))); + .flatMap(l => l.ranks.map(r => ({ value: `${l.id}:${r.id}`, display: `${r.name} (${l.name})` }))); }, - valueIsStillValid: (filterSettings, viewerRanksService) => { + valueIsStillValid: (filterSettings, viewerRanksService: any) => { const [ladderId, rankId] = filterSettings.value?.split(":") ?? []; const ladder = viewerRanksService.getRankLadder(ladderId); @@ -39,7 +38,7 @@ module.exports = { return hasRank; }, - getSelectedValueDisplay: (filterSettings, viewerRanksService) => { + getSelectedValueDisplay: (filterSettings, viewerRanksService: any) => { const [ladderId, rankId] = filterSettings.value?.split(":") ?? []; const ladder = viewerRanksService.getRankLadder(ladderId); @@ -57,8 +56,8 @@ module.exports = { const { comparisonType, value } = filterSettings; const { eventMeta } = eventData; - const { username } = eventMeta; - let { userId } = eventMeta; + const username = eventMeta.username as string; + let userId = eventMeta.userId as string; if (!username && !userId) { return false; @@ -93,4 +92,6 @@ module.exports = { return false; } -}; \ No newline at end of file +}; + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/viewer-roles.js b/src/backend/events/filters/builtin/firebot/viewer-roles.ts similarity index 82% rename from src/backend/events/filters/builtin/viewer-roles.js rename to src/backend/events/filters/builtin/firebot/viewer-roles.ts index 1cd668a79..3b84caecd 100644 --- a/src/backend/events/filters/builtin/viewer-roles.js +++ b/src/backend/events/filters/builtin/firebot/viewer-roles.ts @@ -1,12 +1,11 @@ -"use strict"; - -const customRolesManager = require("../../../roles/custom-roles-manager"); -const teamRolesManager = require("../../../roles/team-roles-manager"); -const twitchRolesManager = require("../../../../shared/twitch-roles"); -const chatRolesManager = require("../../../roles/chat-roles-manager"); -const twitchApi = require("../../../twitch-api/api"); - -module.exports = { +import customRolesManager from "../../../../roles/custom-roles-manager"; +import teamRolesManager from "../../../../roles/team-roles-manager"; +import twitchRolesManager from "../../../../../shared/twitch-roles"; +import chatRolesManager from "../../../../roles/chat-roles-manager"; +import twitchApi from "../../../../twitch-api/api"; +import { EventFilter } from "../../../../../types/events"; + +const filter: EventFilter = { id: "firebot:viewerroles", name: "Viewer's Roles", description: "Filter to a given viewer role", @@ -29,15 +28,14 @@ module.exports = { ], comparisonTypes: ["include", "doesn't include"], valueType: "preset", - presetValues: (viewerRolesService) => { + presetValues: (viewerRolesService: any) => { return viewerRolesService .getCustomRoles() .concat(viewerRolesService.getTwitchRoles()) .concat(viewerRolesService.getTeamRoles()) - .map(r => ({value: r.id, display: r.name})); - + .map(r => ({ value: r.id, display: r.name })); }, - valueIsStillValid: (filterSettings, viewerRolesService) => { + valueIsStillValid: (filterSettings, viewerRolesService: any) => { const allRoles = viewerRolesService .getCustomRoles() .concat(viewerRolesService.getTeamRoles()) @@ -47,7 +45,7 @@ module.exports = { return role != null && role.name != null; }, - getSelectedValueDisplay: (filterSettings, viewerRolesService) => { + getSelectedValueDisplay: (filterSettings, viewerRolesService: any) => { const allRoles = viewerRolesService.getCustomRoles() .concat(viewerRolesService.getTeamRoles()) .concat(viewerRolesService.getTwitchRoles()); @@ -60,13 +58,12 @@ module.exports = { return filterSettings.value; }, - predicate: async (filterSettings, eventData) => { const { comparisonType, value } = filterSettings; const { eventMeta } = eventData; - const { username } = eventMeta; - let { userId } = eventMeta; + const username = eventMeta.username as string; + let userId = eventMeta.userId as string; if (!username && !userId) { return false; @@ -83,8 +80,7 @@ module.exports = { userId = user.id; } - /** @type {string[]} */ - let twitchUserRoles = eventMeta.twitchUserRoles; + let twitchUserRoles = eventMeta.twitchUserRoles as string[]; // For sub tier-specific/known bot permission checking, we have to get live data if (twitchUserRoles == null @@ -123,4 +119,6 @@ module.exports = { return false; } -}; \ No newline at end of file +}; + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/gift-count.js b/src/backend/events/filters/builtin/gift-count.js deleted file mode 100644 index aaef3abb6..000000000 --- a/src/backend/events/filters/builtin/gift-count.js +++ /dev/null @@ -1,51 +0,0 @@ -"use strict"; - -const { ComparisonType } = require("../../../../shared/filter-constants"); - -module.exports = { - id: "firebot:gift-count", - name: "Gift Count", - description: "Filter by the number of subs gifted", - events: [ - { eventSourceId: "twitch", eventId: "community-subs-gifted" } - ], - comparisonTypes: [ - ComparisonType.IS, - ComparisonType.IS_NOT, - ComparisonType.LESS_THAN, - ComparisonType.LESS_THAN_OR_EQUAL_TO, - ComparisonType.GREATER_THAN, - ComparisonType.GREATER_THAN_OR_EQUAL_TO - ], - valueType: "number", - predicate: (filterSettings, eventData) => { - - const { comparisonType, value } = filterSettings; - const { eventMeta } = eventData; - - const giftCountCount = eventMeta.subCount || 0; - - switch (comparisonType) { - case ComparisonType.IS: { - return giftCountCount === value; - } - case ComparisonType.IS_NOT: { - return giftCountCount !== value; - } - case ComparisonType.LESS_THAN: { - return giftCountCount < value; - } - case ComparisonType.LESS_THAN_OR_EQUAL_TO: { - return giftCountCount <= value; - } - case ComparisonType.GREATER_THAN: { - return giftCountCount > value; - } - case ComparisonType.GREATER_THAN_OR_EQUAL_TO: { - return giftCountCount >= value; - } - default: - return false; - } - } -}; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/gift-duration.js b/src/backend/events/filters/builtin/gift-duration.js deleted file mode 100644 index 7408181a3..000000000 --- a/src/backend/events/filters/builtin/gift-duration.js +++ /dev/null @@ -1,51 +0,0 @@ -"use strict"; - -const { ComparisonType } = require("../../../../shared/filter-constants"); - -module.exports = { - id: "firebot:gift-duration", - name: "Gift Duration", - description: "Filter by the duration of the gift sub (in months)", - events: [ - { eventSourceId: "twitch", eventId: "subs-gifted" } - ], - comparisonTypes: [ - ComparisonType.IS, - ComparisonType.IS_NOT, - ComparisonType.LESS_THAN, - ComparisonType.LESS_THAN_OR_EQUAL_TO, - ComparisonType.GREATER_THAN, - ComparisonType.GREATER_THAN_OR_EQUAL_TO - ], - valueType: "number", - predicate: (filterSettings, eventData) => { - - const { comparisonType, value } = filterSettings; - const { eventMeta } = eventData; - - const giftDuration = eventMeta.giftDuration || 1; - - switch (comparisonType) { - case ComparisonType.IS: { - return giftDuration === value; - } - case ComparisonType.IS_NOT: { - return giftDuration !== value; - } - case ComparisonType.LESS_THAN: { - return giftDuration < value; - } - case ComparisonType.LESS_THAN_OR_EQUAL_TO: { - return giftDuration <= value; - } - case ComparisonType.GREATER_THAN: { - return giftDuration > value; - } - case ComparisonType.GREATER_THAN_OR_EQUAL_TO: { - return giftDuration >= value; - } - default: - return false; - } - } -}; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/index.ts b/src/backend/events/filters/builtin/index.ts new file mode 100644 index 000000000..f84b2a658 --- /dev/null +++ b/src/backend/events/filters/builtin/index.ts @@ -0,0 +1,9 @@ +import firebotFilters from "./firebot"; +import thirdPartyFilters from "./third-party"; +import twitchFilters from "./twitch"; + +export default [ + ...firebotFilters, + ...thirdPartyFilters, + ...twitchFilters +]; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/is-anonymous.js b/src/backend/events/filters/builtin/is-anonymous.js deleted file mode 100644 index d2069852c..000000000 --- a/src/backend/events/filters/builtin/is-anonymous.js +++ /dev/null @@ -1,45 +0,0 @@ -"use strict"; - -const { ComparisonType } = require("../../../../shared/filter-constants"); - -module.exports = { - id: "firebot:is-anonymous", - name: "Anonymous", - description: "Filter by whether the event was triggered by an anonymous user", - events: [ - { eventSourceId: "twitch", eventId: "cheer" }, - { eventSourceId: "twitch", eventId: "subs-gifted" }, - { eventSourceId: "twitch", eventId: "community-subs-gifted" } - ], - comparisonTypes: [ComparisonType.IS], - valueType: "preset", - presetValues: () => { - return [ - { - value: "true", - display: "True" - }, - { - value: "false", - display: "False" - } - ]; - }, - getSelectedValueDisplay: (filterSettings) => { - - if (filterSettings.value == null) { - return "False"; - } - - return filterSettings.value === "true" ? "True" : "False"; - }, - predicate: (filterSettings, eventData) => { - - const { value } = filterSettings; - const { eventMeta } = eventData; - - const isAnonymous = eventMeta.isAnonymous === true; - - return value === "true" ? isAnonymous : !isAnonymous; - } -}; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/message.js b/src/backend/events/filters/builtin/message.js deleted file mode 100644 index 14d320707..000000000 --- a/src/backend/events/filters/builtin/message.js +++ /dev/null @@ -1,75 +0,0 @@ -"use strict"; - -const { ComparisonType } = require("../../../../shared/filter-constants"); - -module.exports = { - id: "firebot:message-text", - name: "Message Text", - description: "Filter based on chat message text", - events: [ - { eventSourceId: "twitch", eventId: "chat-message" }, - { eventSourceId: "twitch", eventId: "announcement" } - ], - comparisonTypes: [ - ComparisonType.IS, - ComparisonType.IS_NOT, - ComparisonType.CONTAINS, - ComparisonType.DOESNT_CONTAIN, - ComparisonType.STARTS_WITH, - ComparisonType.DOESNT_STARTS_WITH, - ComparisonType.ENDS_WITH, - ComparisonType.DOESNT_END_WITH, - ComparisonType.MATCHES_REGEX_CS, - ComparisonType.DOESNT_MATCH_REGEX_CS, - ComparisonType.MATCHES_REGEX, - ComparisonType.DOESNT_MATCH_REGEX - ], - valueType: "text", - predicate: (filterSettings, eventData) => { - - const { comparisonType, value } = filterSettings; - const { eventMeta } = eventData; - - /** - * @type {string} - */ - const chatMessage = eventMeta.messageText || ""; - - switch (comparisonType) { - case ComparisonType.IS: - return chatMessage === value; - case ComparisonType.IS_NOT: - return chatMessage !== value; - case ComparisonType.CONTAINS: - return chatMessage.includes(value); - case ComparisonType.DOESNT_CONTAIN: - return !chatMessage.includes(value); - case ComparisonType.STARTS_WITH: - return chatMessage.startsWith(value); - case ComparisonType.DOESNT_STARTS_WITH: - return !chatMessage.startsWith(value); - case ComparisonType.ENDS_WITH: - return chatMessage.endsWith(value); - case ComparisonType.DOESNT_END_WITH: - return !chatMessage.endsWith(value); - case ComparisonType.MATCHES_REGEX: { - const regex = new RegExp(value, "gi"); - return regex.test(chatMessage); - } - case ComparisonType.DOESNT_MATCH_REGEX: { - const regex = new RegExp(value, "gi"); - return !regex.test(chatMessage); - } - case ComparisonType.MATCHES_REGEX_CS: { - const regex = new RegExp(value, "g"); - return regex.test(chatMessage); - } - case ComparisonType.DOESNT_MATCH_REGEX_CS: { - const regex = new RegExp(value, "g"); - return !regex.test(chatMessage); - } - default: - return false; - } - } -}; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/new-rank.js b/src/backend/events/filters/builtin/new-rank.js deleted file mode 100644 index 70eb8aed7..000000000 --- a/src/backend/events/filters/builtin/new-rank.js +++ /dev/null @@ -1,54 +0,0 @@ -"use strict"; - -module.exports = { - id: "firebot:new-rank", - name: "New Rank", - description: "Filter to a given new rank", - events: [ - { eventSourceId: "firebot", eventId: "viewer-rank-updated" } - ], - comparisonTypes: ["is", "is not"], - valueType: "preset", - presetValues: (viewerRanksService) => { - return viewerRanksService - .rankLadders - .flatMap(l => l - .ranks - .map(r => ({ value: r.id, display: `${r.name} (${l.name})`})) - ); - }, - valueIsStillValid: (filterSettings, viewerRanksService) => { - const ladderWithRank = viewerRanksService - .rankLadders - .find(l => l.ranks?.some(r => r.id === filterSettings.value)); - - return ladderWithRank != null; - }, - getSelectedValueDisplay: (filterSettings, viewerRanksService) => { - const ladderWithRank = viewerRanksService - .rankLadders - .find(l => l.ranks?.some(r => r.id === filterSettings.value)); - - const rank = ladderWithRank?.ranks?.find(r => r.id === filterSettings.value); - - return rank ? `${rank?.name} (${ladderWithRank?.name})` : "Not set"; - }, - - predicate: async (filterSettings, eventData) => { - const { comparisonType, value } = filterSettings; - const { eventMeta } = eventData; - - const { newRankId } = eventMeta; - - const isRank = newRankId === value; - - switch (comparisonType) { - case "is": - return isRank; - case "is not": - return !isRank; - default: - return false; - } - } -}; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/new-view-time.js b/src/backend/events/filters/builtin/new-view-time.js deleted file mode 100644 index 9d6e70ab4..000000000 --- a/src/backend/events/filters/builtin/new-view-time.js +++ /dev/null @@ -1,51 +0,0 @@ -"use strict"; - -const { ComparisonType } = require("../../../../shared/filter-constants"); - -module.exports = { - id: "firebot:new-view-time", - name: "New View Time", - description: "Filter a viewers new view time (hours)", - events: [ - { eventSourceId: "firebot", eventId: "view-time-update" } - ], - comparisonTypes: [ - ComparisonType.IS, - ComparisonType.IS_NOT, - ComparisonType.LESS_THAN, - ComparisonType.LESS_THAN_OR_EQUAL_TO, - ComparisonType.GREATER_THAN, - ComparisonType.GREATER_THAN_OR_EQUAL_TO - ], - valueType: "number", - predicate: (filterSettings, eventData) => { - - const { comparisonType, value } = filterSettings; - const { eventMeta } = eventData; - - const newViewTime = eventMeta.newViewTime || 0; - - switch (comparisonType) { - case ComparisonType.IS: { - return newViewTime === value; - } - case ComparisonType.IS_NOT: { - return newViewTime !== value; - } - case ComparisonType.LESS_THAN: { - return newViewTime < value; - } - case ComparisonType.LESS_THAN_OR_EQUAL_TO: { - return newViewTime <= value; - } - case ComparisonType.GREATER_THAN: { - return newViewTime > value; - } - case ComparisonType.GREATER_THAN_OR_EQUAL_TO: { - return newViewTime >= value; - } - default: - return false; - } - } -}; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/previous-rank.js b/src/backend/events/filters/builtin/previous-rank.js deleted file mode 100644 index 6318d32c0..000000000 --- a/src/backend/events/filters/builtin/previous-rank.js +++ /dev/null @@ -1,54 +0,0 @@ -"use strict"; - -module.exports = { - id: "firebot:previous-rank", - name: "Previous Rank", - description: "Filter to a given previous rank", - events: [ - { eventSourceId: "firebot", eventId: "viewer-rank-updated" } - ], - comparisonTypes: ["is", "is not"], - valueType: "preset", - presetValues: (viewerRanksService) => { - return viewerRanksService - .rankLadders - .flatMap(l => l - .ranks - .map(r => ({ value: r.id, display: `${r.name} (${l.name})`})) - ); - }, - valueIsStillValid: (filterSettings, viewerRanksService) => { - const ladderWithRank = viewerRanksService - .rankLadders - .find(l => l.ranks?.some(r => r.id === filterSettings.value)); - - return ladderWithRank != null; - }, - getSelectedValueDisplay: (filterSettings, viewerRanksService) => { - const ladderWithRank = viewerRanksService - .rankLadders - .find(l => l.ranks?.some(r => r.id === filterSettings.value)); - - const rank = ladderWithRank?.ranks?.find(r => r.id === filterSettings.value); - - return rank ? `${rank?.name} (${ladderWithRank?.name})` : "Not set"; - }, - - predicate: async (filterSettings, eventData) => { - const { comparisonType, value } = filterSettings; - const { eventMeta } = eventData; - - const { newRankId } = eventMeta; - - const isRank = newRankId === value; - - switch (comparisonType) { - case "is": - return isRank; - case "is not": - return !isRank; - default: - return false; - } - } -}; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/previous-view-time.js b/src/backend/events/filters/builtin/previous-view-time.js deleted file mode 100644 index 085dd5bf5..000000000 --- a/src/backend/events/filters/builtin/previous-view-time.js +++ /dev/null @@ -1,51 +0,0 @@ -"use strict"; - -const { ComparisonType } = require("../../../../shared/filter-constants"); - -module.exports = { - id: "firebot:previous-view-time", - name: "Previous View Time", - description: "Filter a viewers previous view time (hours)", - events: [ - { eventSourceId: "firebot", eventId: "view-time-update" } - ], - comparisonTypes: [ - ComparisonType.IS, - ComparisonType.IS_NOT, - ComparisonType.LESS_THAN, - ComparisonType.LESS_THAN_OR_EQUAL_TO, - ComparisonType.GREATER_THAN, - ComparisonType.GREATER_THAN_OR_EQUAL_TO - ], - valueType: "number", - predicate: (filterSettings, eventData) => { - - const { comparisonType, value } = filterSettings; - const { eventMeta } = eventData; - - const previousViewTime = eventMeta.previousViewTime || 0; - - switch (comparisonType) { - case ComparisonType.IS: { - return previousViewTime === value; - } - case ComparisonType.IS_NOT: { - return previousViewTime !== value; - } - case ComparisonType.LESS_THAN: { - return previousViewTime < value; - } - case ComparisonType.LESS_THAN_OR_EQUAL_TO: { - return previousViewTime <= value; - } - case ComparisonType.GREATER_THAN: { - return previousViewTime > value; - } - case ComparisonType.GREATER_THAN_OR_EQUAL_TO: { - return previousViewTime >= value; - } - default: - return false; - } - } -}; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/raid-viewer-count.js b/src/backend/events/filters/builtin/raid-viewer-count.js deleted file mode 100644 index 54f76457f..000000000 --- a/src/backend/events/filters/builtin/raid-viewer-count.js +++ /dev/null @@ -1,51 +0,0 @@ -"use strict"; - -const { ComparisonType } = require("../../../../shared/filter-constants"); - -module.exports = { - id: "firebot:raid-viewer-count", - name: "Raid Viewer Count", - description: "Filter by how many viewers have been brought or are being sent over by the raid.", - events: [ - { eventSourceId: "twitch", eventId: "raid" }, - { eventSourceId: "twitch", eventId: "raid-sent-off" } - ], - comparisonTypes: [ - ComparisonType.IS, - ComparisonType.IS_NOT, - ComparisonType.LESS_THAN, - ComparisonType.LESS_THAN_OR_EQUAL_TO, - ComparisonType.GREATER_THAN, - ComparisonType.GREATER_THAN_OR_EQUAL_TO - ], - valueType: "number", - predicate: (filterSettings, eventData) => { - const { comparisonType, value } = filterSettings; - const { eventMeta } = eventData; - - const raidViewerCount = eventMeta.viewerCount || 0; - - switch (comparisonType) { - case ComparisonType.IS: { - return raidViewerCount === value; - } - case ComparisonType.IS_NOT: { - return raidViewerCount !== value; - } - case ComparisonType.LESS_THAN: { - return raidViewerCount < value; - } - case ComparisonType.LESS_THAN_OR_EQUAL_TO: { - return raidViewerCount <= value; - } - case ComparisonType.GREATER_THAN: { - return raidViewerCount > value; - } - case ComparisonType.GREATER_THAN_OR_EQUAL_TO: { - return raidViewerCount >= value; - } - default: - return false; - } - } -}; diff --git a/src/backend/events/filters/builtin/rank-ladder.js b/src/backend/events/filters/builtin/rank-ladder.js deleted file mode 100644 index 46d49ae44..000000000 --- a/src/backend/events/filters/builtin/rank-ladder.js +++ /dev/null @@ -1,43 +0,0 @@ -"use strict"; - -module.exports = { - id: "firebot:rank-ladder", - name: "Rank Ladder", - description: "Filter to a given rank ladder", - events: [ - { eventSourceId: "firebot", eventId: "viewer-rank-updated" } - ], - comparisonTypes: ["is", "is not"], - valueType: "preset", - presetValues: (viewerRanksService) => { - return viewerRanksService - .rankLadders - .map(l => ({value: l.id, display: l.name})); - }, - valueIsStillValid: (filterSettings, viewerRanksService) => { - const ladder = viewerRanksService.getRankLadder(filterSettings.value); - return ladder != null; - }, - getSelectedValueDisplay: (filterSettings, viewerRanksService) => { - const ladder = viewerRanksService.getRankLadder(filterSettings.value); - return ladder?.name ?? "Not set"; - }, - - predicate: async (filterSettings, eventData) => { - const { comparisonType, value } = filterSettings; - const { eventMeta } = eventData; - - const {rankLadderId } = eventMeta; - - const isLadder = rankLadderId === value; - - switch (comparisonType) { - case "is": - return isLadder; - case "is not": - return !isLadder; - default: - return false; - } - } -}; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/rank-transition-type.js b/src/backend/events/filters/builtin/rank-transition-type.js deleted file mode 100644 index d34597253..000000000 --- a/src/backend/events/filters/builtin/rank-transition-type.js +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -module.exports = { - id: "firebot:rank-transition-type", - name: "Rank Transition Type", - description: "Filter to a given rank transition type (promotion or demotion)", - events: [ - { eventSourceId: "firebot", eventId: "viewer-rank-updated" } - ], - comparisonTypes: ["is"], - valueType: "preset", - presetValues: () => { - return [ - { value: "Promotion", display: "Promotion" }, - { value: "Demotion", display: "Demotion" } - ]; - }, - valueIsStillValid: () => { - return true; - }, - getSelectedValueDisplay: (filterSettings) => { - return filterSettings.value; - }, - - predicate: async (filterSettings, eventData) => { - const { value } = filterSettings; - const { eventMeta } = eventData; - - const { isPromotion, isDemotion } = eventMeta; - - return value === "Promotion" ? - isPromotion : - value === "Demotion" ? - isDemotion : - false; - } -}; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/reward-name.js b/src/backend/events/filters/builtin/reward-name.js deleted file mode 100644 index d5ab99891..000000000 --- a/src/backend/events/filters/builtin/reward-name.js +++ /dev/null @@ -1,38 +0,0 @@ -"use strict"; - -const { ComparisonType } = require("../../../../shared/filter-constants"); - -module.exports = { - id: "firebot:reward-name", - name: "Reward Name", - description: "Filter to a Custom Channel Reward by Name", - events: [ - { eventSourceId: "twitch", eventId: "channel-reward-redemption" } - ], - comparisonTypes: [ComparisonType.IS, ComparisonType.IS_NOT, ComparisonType.CONTAINS, ComparisonType.MATCHES_REGEX], - valueType: "text", - predicate: (filterSettings, eventData) => { - - const { comparisonType, value } = filterSettings; - const { eventMeta } = eventData; - - // normalize - const actual = eventMeta.rewardName ? eventMeta.rewardName.toLowerCase() : ""; - const expected = value ? value.toLowerCase() : ""; - - switch (comparisonType) { - case ComparisonType.IS: - return actual === expected; - case ComparisonType.IS_NOT: - return actual !== expected; - case ComparisonType.CONTAINS: - return actual.includes(expected); - case ComparisonType.MATCHES_REGEX: { - const regex = new RegExp(expected, "gi"); - return regex.test(actual); - } - default: - return false; - } - } -}; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/reward.js b/src/backend/events/filters/builtin/reward.js deleted file mode 100644 index d268058c3..000000000 --- a/src/backend/events/filters/builtin/reward.js +++ /dev/null @@ -1,53 +0,0 @@ -"use strict"; - -module.exports = { - id: "firebot:reward", - name: "Reward", - description: "Filter to a Custom Channel Reward", - events: [ - { eventSourceId: "twitch", eventId: "channel-reward-redemption" } - ], - comparisonTypes: ["is", "is not"], - valueType: "preset", - presetValues: (backendCommunicator) => { - return backendCommunicator - .fireEventAsync("get-channel-rewards").then(rewards => - rewards.map(r => ({value: r.id, display: r.twitchData.title}))); - }, - valueIsStillValid: (filterSettings, backendCommunicator) => { - return new Promise((resolve) => { - backendCommunicator - .fireEventAsync("get-channel-rewards").then((rewards) => { - resolve(rewards.some(r => r.id === filterSettings.value)); - }); - }); - }, - getSelectedValueDisplay: (filterSettings, backendCommunicator) => { - return new Promise((resolve) => { - backendCommunicator - .fireEventAsync("get-channel-rewards").then((rewards) => { - const reward = rewards.find(r => r.id === filterSettings.value); - - resolve(reward ? reward.twitchData.title : "Unknown Reward"); - }); - }); - }, - predicate: (filterSettings, eventData) => { - - const { comparisonType, value } = filterSettings; - const { eventMeta } = eventData; - - // normalize - const actual = eventMeta.rewardId; - const expected = value; - - switch (comparisonType) { - case "is": - return actual === expected; - case "is not": - return actual !== expected; - default: - return false; - } - } -}; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/shared-chat.ts b/src/backend/events/filters/builtin/shared-chat.ts deleted file mode 100644 index 1c024746e..000000000 --- a/src/backend/events/filters/builtin/shared-chat.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { ComparisonType } from "../../../../shared/filter-constants"; - -module.exports = { - id: "firebot:is-shared-chat-message", - name: "Shared Chat", - description: "Filter by whether the event was triggered by a shared chat message", - events: [ - { eventSourceId: "twitch", eventId: "chat-message" }, - { eventSourceId: "twitch", eventId: "announcement" }, - { eventSourceId: "twitch", eventId: "first-time-chat" }, - { eventSourceId: "twitch", eventId: "viewer-arrived" } - ], - comparisonTypes: [ComparisonType.IS], - valueType: "preset", - presetValues: () => { - return [ - { - value: "true", - display: "True" - }, - { - value: "false", - display: "False" - } - ]; - }, - getSelectedValueDisplay: (filterSettings) => { - - if (filterSettings.value == null) { - return "False"; - } - - return filterSettings.value === "true" ? "True" : "False"; - }, - predicate: (filterSettings, eventData) => { - - const { value } = filterSettings; - const { eventMeta } = eventData; - - const isShared = eventMeta.chatMessage.isSharedChatMessage; - - return value === "true" ? isShared : !isShared; - } -}; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/stream-category.js b/src/backend/events/filters/builtin/stream-category.js deleted file mode 100644 index 39e893e40..000000000 --- a/src/backend/events/filters/builtin/stream-category.js +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -const { ComparisonType } = require("../../../../shared/filter-constants"); - -module.exports = { - id: "firebot:category-changed", - name: "Category", - description: "The category that is currently selected to stream to.", - events: [ - { eventSourceId: "firebot", eventId: "category-changed" }, - { eventSourceId: "twitch", eventId: "category-changed" } - ], - comparisonTypes: [ComparisonType.IS, ComparisonType.IS_NOT, ComparisonType.CONTAINS, ComparisonType.MATCHES_REGEX], - valueType: "text", - predicate: (filterSettings, eventData) => { - const { comparisonType, value } = filterSettings; - const { eventMeta } = eventData; - - const eventCategory = eventMeta.category ? eventMeta.category.toLowerCase() : ""; - const filterCategory = value ? value.toLowerCase() : ""; - - switch (comparisonType) { - case ComparisonType.IS: - return eventCategory === filterCategory; - case ComparisonType.IS_NOT: - return eventCategory !== filterCategory; - case ComparisonType.CONTAINS: - return eventCategory.includes(filterCategory); - case ComparisonType.MATCHES_REGEX: { - const regex = new RegExp(filterCategory, "gi"); - return regex.test(eventCategory); - } - default: - return false; - } - } -}; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/sub-kind.js b/src/backend/events/filters/builtin/sub-kind.js deleted file mode 100644 index 41830b105..000000000 --- a/src/backend/events/filters/builtin/sub-kind.js +++ /dev/null @@ -1,50 +0,0 @@ -"use strict"; - -const { ComparisonType } = require("../../../../shared/filter-constants"); - -module.exports = { - id: "firebot:sub-kind", - name: "Kind of Sub", - description: "Filter by the kind of sub (resub vs first sub)", - events: [ - { eventSourceId: "twitch", eventId: "sub" } - ], - comparisonTypes: [ComparisonType.IS], - valueType: "preset", - presetValues: () => { - return [ - { - value: "first", - display: "First Sub" - }, - { - value: "resub", - display: "Resub" - } - ]; - }, - getSelectedValueDisplay: (filterSettings) => { - switch (filterSettings.value) { - case "first": - return "First Sub"; - case "resub": - return "Resub"; - default: - return "[Not set]"; - } - }, - predicate: (filterSettings, eventData) => { - - const { value } = filterSettings; - const { eventMeta } = eventData; - - if (value == null) { - return true; - } - - const isResub = eventMeta.isResub; - const expectingResub = value === 'resub'; - - return isResub === expectingResub; - } -}; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/sub-type.js b/src/backend/events/filters/builtin/sub-type.js deleted file mode 100644 index 41e166fcb..000000000 --- a/src/backend/events/filters/builtin/sub-type.js +++ /dev/null @@ -1,71 +0,0 @@ -"use strict"; - -const { ComparisonType } = require("../../../../shared/filter-constants"); - -module.exports = { - id: "firebot:sub-type", - name: "Sub Tier", - description: "Filter by the tier of sub (Prime, Tier 1, 2, 3, etc)", - events: [ - { eventSourceId: "twitch", eventId: "sub" }, - { eventSourceId: "twitch", eventId: "subs-gifted" }, - { eventSourceId: "twitch", eventId: "community-subs-gifted" }, - { eventSourceId: "twitch", eventId: "prime-sub-upgraded" }, - { eventSourceId: "twitch", eventId: "gift-sub-upgraded" } - ], - comparisonTypes: [ComparisonType.IS, ComparisonType.IS_NOT], - valueType: "preset", - presetValues: () => { - return [ - { - value: "Prime", - display: "Prime" - }, - { - value: "1000", - display: "Tier 1" - }, - { - value: "2000", - display: "Tier 2" - }, - { - value: "3000", - display: "Tier 3" - } - ]; - }, - getSelectedValueDisplay: (filterSettings) => { - switch (filterSettings.value) { - case "Prime": - return "Prime"; - case "1000": - return "Tier 1"; - case "2000": - return "Tier 2"; - case "3000": - return "Tier 3"; - default: - return "[Not set]"; - } - }, - predicate: (filterSettings, eventData) => { - - const { comparisonType, value } = filterSettings; - const { eventMeta } = eventData; - - if (value == null) { - return true; - } - - const subPlan = eventMeta.subPlan; - - if (comparisonType === ComparisonType.IS) { - return subPlan === value; - } else if (comparisonType === ComparisonType.IS_NOT) { - return subPlan !== value; - } - - return true; - } -}; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/third-party/donation-amount.ts b/src/backend/events/filters/builtin/third-party/donation-amount.ts new file mode 100644 index 000000000..7b75224e6 --- /dev/null +++ b/src/backend/events/filters/builtin/third-party/donation-amount.ts @@ -0,0 +1,17 @@ +import { createNumberFilter } from "../../filter-factory"; + +const filter = createNumberFilter({ + id: "firebot:donation-amount", + name: "Donation Amount", + description: "Filter by the amount of donation from StreamLabs/Tipeee/ExtraLife", + eventMetaKey: "donationAmount", + events: [ + { eventSourceId: "streamlabs", eventId: "donation" }, + { eventSourceId: "streamlabs", eventId: "eldonation" }, + { eventSourceId: "extralife", eventId: "donation" }, + { eventSourceId: "tipeeestream", eventId: "donation" }, + { eventSourceId: "streamelements", eventId: "donation" } + ] +}); + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/third-party/donation-from.ts b/src/backend/events/filters/builtin/third-party/donation-from.ts new file mode 100644 index 000000000..48afb391a --- /dev/null +++ b/src/backend/events/filters/builtin/third-party/donation-from.ts @@ -0,0 +1,18 @@ +import { createTextFilter } from "../../filter-factory"; + +const filter = createTextFilter({ + id: "firebot:donationfrom", + name: "Donation From", + caseInsensitive: true, + description: "Filter to a specific donation sender", + eventMetaKey: "from", + events: [ + { eventSourceId: "streamlabs", eventId: "donation" }, + { eventSourceId: "streamlabs", eventId: "eldonation" }, + { eventSourceId: "extralife", eventId: "donation" }, + { eventSourceId: "tipeeestream", eventId: "donation" }, + { eventSourceId: "streamelements", eventId: "donation" } + ] +}); + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/third-party/index.ts b/src/backend/events/filters/builtin/third-party/index.ts new file mode 100644 index 000000000..dc3adca25 --- /dev/null +++ b/src/backend/events/filters/builtin/third-party/index.ts @@ -0,0 +1,7 @@ +import donationAmount from "./donation-amount"; +import donationFrom from "./donation-from"; + +export default [ + donationAmount, + donationFrom +]; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/twitch/bits-badge-tier.ts b/src/backend/events/filters/builtin/twitch/bits-badge-tier.ts new file mode 100644 index 000000000..043daef5b --- /dev/null +++ b/src/backend/events/filters/builtin/twitch/bits-badge-tier.ts @@ -0,0 +1,13 @@ +import { createNumberFilter } from "../../filter-factory"; + +const filter = createNumberFilter({ + id: "firebot:bits-badge-tier", + name: "Bits Badge Tier", + description: "Filter by the tier of the bits badge that was unlocked (100, 1000, 5000, etc.)", + events: [ + { eventSourceId: "twitch", eventId: "bits-badge-unlocked" } + ], + eventMetaKey: "badgeTier" +}); + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/twitch/chat-mode-duration.ts b/src/backend/events/filters/builtin/twitch/chat-mode-duration.ts new file mode 100644 index 000000000..f0b035453 --- /dev/null +++ b/src/backend/events/filters/builtin/twitch/chat-mode-duration.ts @@ -0,0 +1,13 @@ +import { createNumberFilter } from "../../filter-factory"; + +const filter = createNumberFilter({ + id: "firebot:chatmodeduration", + name: "Duration", + description: "Filter by a chat mode's duration (only for Slow (seconds) and Follower (minutes))", + eventMetaKey: "duration", + events: [ + { eventSourceId: "twitch", eventId: "chat-mode-changed" } + ] +}); + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/twitch/chat-mode-setting.ts b/src/backend/events/filters/builtin/twitch/chat-mode-setting.ts new file mode 100644 index 000000000..bf4fb4e06 --- /dev/null +++ b/src/backend/events/filters/builtin/twitch/chat-mode-setting.ts @@ -0,0 +1,23 @@ +import { createPresetFilter } from "../../filter-factory"; + +const filter = createPresetFilter({ + id: "firebot:chatmodesetting", + name: "Setting", + description: "Filter by a chat mode's setting", + events: [ + { eventSourceId: "twitch", eventId: "chat-mode-changed" } + ], + eventMetaKey: "chatModeState", + presetValues: async () => [ + { + value: "enabled", + display: "Enabled" + }, + { + value: "disabled", + display: "Disabled" + } + ] +}); + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/chat-mode.js b/src/backend/events/filters/builtin/twitch/chat-mode.ts similarity index 57% rename from src/backend/events/filters/builtin/chat-mode.js rename to src/backend/events/filters/builtin/twitch/chat-mode.ts index 2d1fef8d8..b68235302 100644 --- a/src/backend/events/filters/builtin/chat-mode.js +++ b/src/backend/events/filters/builtin/twitch/chat-mode.ts @@ -1,8 +1,7 @@ -"use strict"; +import { EventFilter } from "../../../../../types/events"; +import { ComparisonType } from "../../../../../shared/filter-constants"; -const { ComparisonType } = require("../../../../shared/filter-constants"); - -module.exports = { +const filter: EventFilter = { id: "firebot:chatmode", name: "Chat Mode", description: "Filter by a chat mode", @@ -11,7 +10,7 @@ module.exports = { ], comparisonTypes: [ComparisonType.IS, ComparisonType.IS_NOT], valueType: "preset", - presetValues: () => { + presetValues: async () => { return [ { value: "emoteonly", @@ -35,34 +34,26 @@ module.exports = { } ]; }, - getSelectedValueDisplay: (filterSettings) => { - switch (filterSettings.value) { - case "emoteonly": - return "Emote Only"; - case "followers": - return "Followers"; - case "subscribers": - return "Subscribers Only"; - case "slow": - return "Slow"; - case "r9kbeta": - return "Unique Chat"; - default: - return "[Not set]"; - } + getSelectedValueDisplay: async (filterSettings) => { + return (await filter.presetValues()) + .find(pv => pv.value === filterSettings.value)?.display ?? "[Not Set]"; }, predicate: async (filterSettings, eventData) => { const { comparisonType, value } = filterSettings; const { eventMeta } = eventData; + const chatModes = eventMeta.chatMode as string; + switch (comparisonType) { - case "is": - return eventMeta.chatMode.includes(value); - case "is not": - return !eventMeta.chatMode.includes(value); + case ComparisonType.IS: + return chatModes.includes(value); + case ComparisonType.IS_NOT: + return !chatModes.includes(value); default: return false; } } -}; \ No newline at end of file +}; + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/twitch/cheer-bits-amount.ts b/src/backend/events/filters/builtin/twitch/cheer-bits-amount.ts new file mode 100644 index 000000000..561aa92f0 --- /dev/null +++ b/src/backend/events/filters/builtin/twitch/cheer-bits-amount.ts @@ -0,0 +1,13 @@ +import { createNumberFilter } from "../../filter-factory"; + +const filter = createNumberFilter({ + id: "firebot:cheerbitsamount", + name: "Cheer Bits Amount", + description: "Filter by the amount of bits in a Cheer", + eventMetaKey: "bits", + events: [ + { eventSourceId: "twitch", eventId: "cheer" } + ] +}); + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/twitch/gift-count.ts b/src/backend/events/filters/builtin/twitch/gift-count.ts new file mode 100644 index 000000000..991777a85 --- /dev/null +++ b/src/backend/events/filters/builtin/twitch/gift-count.ts @@ -0,0 +1,13 @@ +import { createNumberFilter } from "../../filter-factory"; + +const filter = createNumberFilter({ + id: "firebot:gift-count", + name: "Gift Count", + description: "Filter by the number of subs gifted", + eventMetaKey: "subCount", + events: [ + { eventSourceId: "twitch", eventId: "subs-gifted" } + ] +}); + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/twitch/gift-duration.ts b/src/backend/events/filters/builtin/twitch/gift-duration.ts new file mode 100644 index 000000000..3f6f35928 --- /dev/null +++ b/src/backend/events/filters/builtin/twitch/gift-duration.ts @@ -0,0 +1,13 @@ +import { createNumberFilter } from "../../filter-factory"; + +const filter = createNumberFilter({ + id: "firebot:gift-duration", + name: "Gift Duration", + description: "Filter by the duration of the gift sub (in months)", + eventMetaKey: "giftDuration", + events: [ + { eventSourceId: "twitch", eventId: "subs-gifted" } + ] +}); + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/twitch/index.ts b/src/backend/events/filters/builtin/twitch/index.ts new file mode 100644 index 000000000..543a436ba --- /dev/null +++ b/src/backend/events/filters/builtin/twitch/index.ts @@ -0,0 +1,37 @@ +import bitsBadgeTier from "./bits-badge-tier"; +import chatModeDuration from "./chat-mode-duration"; +import chatModeSetting from "./chat-mode-setting"; +import chatMode from "./chat-mode"; +import cheerBitsAmount from "./cheer-bits-amount"; +import giftCount from "./gift-count"; +import giftDuration from "./gift-duration"; +import isAnonymous from "./is-anonymous"; +import message from "./message"; +import raidViewerCount from "./raid-viewer-count"; +import rewardName from "./reward-name"; +import reward from "./reward"; +import sharedChat from "./shared-chat"; +import streamCategory from "./stream-category"; +import subKind from "./sub-kind"; +import subType from "./sub-type"; +import username from "./username"; + +export default [ + bitsBadgeTier, + chatModeDuration, + chatModeSetting, + chatMode, + cheerBitsAmount, + giftCount, + giftDuration, + isAnonymous, + message, + raidViewerCount, + rewardName, + reward, + sharedChat, + streamCategory, + subKind, + subType, + username +]; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/twitch/is-anonymous.ts b/src/backend/events/filters/builtin/twitch/is-anonymous.ts new file mode 100644 index 000000000..0f18ce4a4 --- /dev/null +++ b/src/backend/events/filters/builtin/twitch/is-anonymous.ts @@ -0,0 +1,25 @@ +import { createPresetFilter } from "../../filter-factory"; + +const filter = createPresetFilter({ + id: "firebot:is-anonymous", + name: "Anonymous", + description: "Filter by whether the event was triggered by an anonymous user", + events: [ + { eventSourceId: "twitch", eventId: "cheer" }, + { eventSourceId: "twitch", eventId: "subs-gifted" }, + { eventSourceId: "twitch", eventId: "community-subs-gifted" } + ], + eventMetaKey: "isAnonymous", + presetValues: async () => [ + { + value: "true", + display: "True" + }, + { + value: "false", + display: "False" + } + ] +}); + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/twitch/message.ts b/src/backend/events/filters/builtin/twitch/message.ts new file mode 100644 index 000000000..a28860932 --- /dev/null +++ b/src/backend/events/filters/builtin/twitch/message.ts @@ -0,0 +1,14 @@ +import { createTextFilter } from "../../filter-factory"; + +const filter = createTextFilter({ + id: "firebot:message-text", + name: "Message Text", + description: "Filter based on chat message text", + eventMetaKey: "messageText", + events: [ + { eventSourceId: "twitch", eventId: "chat-message" }, + { eventSourceId: "twitch", eventId: "announcement" } + ] +}); + +export default filter; diff --git a/src/backend/events/filters/builtin/twitch/raid-viewer-count.ts b/src/backend/events/filters/builtin/twitch/raid-viewer-count.ts new file mode 100644 index 000000000..1131b4afb --- /dev/null +++ b/src/backend/events/filters/builtin/twitch/raid-viewer-count.ts @@ -0,0 +1,14 @@ +import { createNumberFilter } from "../../filter-factory"; + +const filter = createNumberFilter({ + id: "firebot:raid-viewer-count", + name: "Raid Viewer Count", + description: "Filter by how many viewers have been brought or are being sent over by the raid", + eventMetaKey: "viewerCount", + events: [ + { eventSourceId: "twitch", eventId: "raid" }, + { eventSourceId: "twitch", eventId: "raid-sent-off" } + ] +}); + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/twitch/reward-name.ts b/src/backend/events/filters/builtin/twitch/reward-name.ts new file mode 100644 index 000000000..8b72a4b93 --- /dev/null +++ b/src/backend/events/filters/builtin/twitch/reward-name.ts @@ -0,0 +1,14 @@ +import { createTextFilter } from "../../filter-factory"; + +const filter = createTextFilter({ + id: "firebot:reward-name", + name: "Reward Name", + caseInsensitive: true, + description: "Filter to a Custom Channel Reward by Name", + eventMetaKey: "rewardName", + events: [ + { eventSourceId: "twitch", eventId: "channel-reward-redemption" } + ] +}); + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/twitch/reward.ts b/src/backend/events/filters/builtin/twitch/reward.ts new file mode 100644 index 000000000..f34ebff6e --- /dev/null +++ b/src/backend/events/filters/builtin/twitch/reward.ts @@ -0,0 +1,22 @@ +import { createPresetFilter } from "../../filter-factory"; + +const filter = createPresetFilter({ + id: "firebot:reward", + name: "Reward", + description: "Filter to a Custom Channel Reward", + events: [ + { eventSourceId: "twitch", eventId: "channel-reward-redemption" } + ], + eventMetaKey: "rewardId", + allowIsNot: true, + presetValues: async (backendCommunicator: any) => { + const rewards = await backendCommunicator.fireEventAsync("get-channel-rewards"); + return rewards.map(r => ({value: r.id, display: r.twitchData.title})); + }, + valueIsStillValid: async (filterSettings, backendCommunicator: any) => { + const rewards = await backendCommunicator.fireEventAsync("get-channel-rewards"); + return rewards.some(r => r.id === filterSettings.value); + } +}); + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/twitch/shared-chat.ts b/src/backend/events/filters/builtin/twitch/shared-chat.ts new file mode 100644 index 000000000..a96c4b6a7 --- /dev/null +++ b/src/backend/events/filters/builtin/twitch/shared-chat.ts @@ -0,0 +1,26 @@ +import { createPresetFilter } from "../../filter-factory"; + +const filter = createPresetFilter({ + id: "firebot:is-shared-chat-message", + name: "Shared Chat", + description: "Filter by whether the event was triggered by a shared chat message", + events: [ + { eventSourceId: "twitch", eventId: "chat-message" }, + { eventSourceId: "twitch", eventId: "announcement" }, + { eventSourceId: "twitch", eventId: "first-time-chat" }, + { eventSourceId: "twitch", eventId: "viewer-arrived" } + ], + eventMetaKey: "chatMessage.isSharedChatMessage", + presetValues: async () => [ + { + value: "true", + display: "True" + }, + { + value: "false", + display: "False" + } + ] +}); + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/twitch/stream-category.ts b/src/backend/events/filters/builtin/twitch/stream-category.ts new file mode 100644 index 000000000..fe420565b --- /dev/null +++ b/src/backend/events/filters/builtin/twitch/stream-category.ts @@ -0,0 +1,15 @@ +import { createTextFilter } from "../../filter-factory"; + +const filter = createTextFilter({ + id: "firebot:category-changed", + name: "Category", + caseInsensitive: true, + description: "The category that is currently selected to stream to.", + eventMetaKey: "category", + events: [ + { eventSourceId: "firebot", eventId: "category-changed" }, + { eventSourceId: "twitch", eventId: "category-changed" } + ] +}); + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/twitch/sub-kind.ts b/src/backend/events/filters/builtin/twitch/sub-kind.ts new file mode 100644 index 000000000..265750193 --- /dev/null +++ b/src/backend/events/filters/builtin/twitch/sub-kind.ts @@ -0,0 +1,23 @@ +import { createPresetFilter } from "../../filter-factory"; + +const filter = createPresetFilter({ + id: "firebot:sub-kind", + name: "Kind of Sub", + description: "Filter by the kind of sub (resub vs first sub)", + events: [ + { eventSourceId: "twitch", eventId: "sub" } + ], + eventMetaKey: "isResub", + presetValues: () => [ + { + value: "first", + display: "First Sub" + }, + { + value: "resub", + display: "Resub" + } + ] +}); + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/twitch/sub-type.ts b/src/backend/events/filters/builtin/twitch/sub-type.ts new file mode 100644 index 000000000..8985a1642 --- /dev/null +++ b/src/backend/events/filters/builtin/twitch/sub-type.ts @@ -0,0 +1,35 @@ +import { createPresetFilter } from "../../filter-factory"; + +const filter = createPresetFilter({ + id: "firebot:sub-type", + name: "Sub Tier", + description: "Filter by the tier of sub (Prime, Tier 1, 2, 3, etc)", + events: [ + { eventSourceId: "twitch", eventId: "sub" }, + { eventSourceId: "twitch", eventId: "subs-gifted" }, + { eventSourceId: "twitch", eventId: "community-subs-gifted" }, + { eventSourceId: "twitch", eventId: "prime-sub-upgraded" }, + { eventSourceId: "twitch", eventId: "gift-sub-upgraded" } + ], + eventMetaKey: "subPlan", + presetValues: () => [ + { + value: "Prime", + display: "Prime" + }, + { + value: "1000", + display: "Tier 1" + }, + { + value: "2000", + display: "Tier 2" + }, + { + value: "3000", + display: "Tier 3" + } + ] +}); + +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/builtin/username.js b/src/backend/events/filters/builtin/twitch/username.ts similarity index 56% rename from src/backend/events/filters/builtin/username.js rename to src/backend/events/filters/builtin/twitch/username.ts index e1792582b..2019d2a8f 100644 --- a/src/backend/events/filters/builtin/username.js +++ b/src/backend/events/filters/builtin/twitch/username.ts @@ -1,11 +1,11 @@ -"use strict"; +import { createTextFilter } from "../../filter-factory"; -const { ComparisonType } = require("../../../../shared/filter-constants"); - -module.exports = { +const filter = createTextFilter({ id: "firebot:username", name: "Username", + caseInsensitive: true, description: "Filter to a specific username", + eventMetaKey: "username", events: [ { eventSourceId: "twitch", eventId: "cheer" }, { eventSourceId: "twitch", eventId: "bits-badge-unlocked" }, @@ -29,31 +29,7 @@ module.exports = { { eventSourceId: "streamloots", eventId: "purchase" }, { eventSourceId: "streamloots", eventId: "redemption" }, { eventSourceId: "streamlabs", eventId: "follow" } - ], - comparisonTypes: [ComparisonType.IS, ComparisonType.IS_NOT, ComparisonType.CONTAINS, ComparisonType.MATCHES_REGEX], - valueType: "text", - predicate: (filterSettings, eventData) => { - - const { comparisonType, value } = filterSettings; - const { eventMeta } = eventData; - - // normalize usernames - const eventUsername = eventMeta.username ? eventMeta.username.toLowerCase() : ""; - const filterUsername = value ? value.toLowerCase() : ""; + ] +}); - switch (comparisonType) { - case ComparisonType.IS: - return eventUsername === filterUsername; - case ComparisonType.IS_NOT: - return eventUsername !== filterUsername; - case ComparisonType.CONTAINS: - return eventUsername.includes(filterUsername); - case ComparisonType.MATCHES_REGEX: { - const regex = new RegExp(filterUsername, "gi"); - return regex.test(eventUsername); - } - default: - return false; - } - } -}; \ No newline at end of file +export default filter; \ No newline at end of file diff --git a/src/backend/events/filters/filter-factory.ts b/src/backend/events/filters/filter-factory.ts index b883d1b99..25143e4d1 100644 --- a/src/backend/events/filters/filter-factory.ts +++ b/src/backend/events/filters/filter-factory.ts @@ -1,5 +1,7 @@ -import { EventFilter } from "../../../types/events"; +import { EventFilter, FilterSettings, PresetValue } from "../../../types/events"; import { ComparisonType } from "../../../shared/filter-constants"; +import { extractPropertyWithPath } from "../../utility"; +import { auto } from "angular"; type EventData = { eventSourceId: string; @@ -14,10 +16,17 @@ type FilterConfig = { name: string; description: string; events: Array; - eventMetaKey: string | ((eventData: EventData) => string); + eventMetaKey: string | ((eventData: EventData, filterSettings: FilterSettings) => string); caseInsensitive?: boolean; }; +type PresetFilterConfig = FilterConfig & { + presetValues: (...args: unknown[]) => Promise | PresetValue[]; + valueIsStillValid?(filterSettings: FilterSettings, ...args: unknown[]): Promise | boolean; + getSelectedValueDisplay?(filterSettings: FilterSettings, ...args: unknown[]): Promise | string; + allowIsNot?: boolean; +} + const TEXT_COMPARISON_TYPES = [ ComparisonType.IS, ComparisonType.IS_NOT, @@ -103,9 +112,9 @@ function compareValue( } } -function getMetaKey(eventMetaKey: FilterConfig["eventMetaKey"], event: EventData): string { +function getMetaKey(eventMetaKey: FilterConfig["eventMetaKey"], event: EventData, filter: FilterSettings): string { if (typeof eventMetaKey === "function") { - return eventMetaKey(event); + return eventMetaKey(event, filter); } return eventMetaKey; } @@ -114,7 +123,7 @@ export function createTextFilter({ eventMetaKey, caseInsensitive, ...config -}: FilterConfig): Omit { +}: Omit): Omit { return { ...config, comparisonTypes: TEXT_COMPARISON_TYPES, @@ -123,7 +132,7 @@ export function createTextFilter({ const { comparisonType, value } = filterSettings; const { eventMeta } = eventData; - let eventValue = eventMeta[getMetaKey(eventMetaKey, eventData)] ?? ""; + let eventValue = extractPropertyWithPath(eventMeta, getMetaKey(eventMetaKey, eventData, filterSettings)) ?? ""; if (caseInsensitive) { eventValue = eventValue.toString().toLowerCase(); } @@ -138,7 +147,7 @@ export function createTextFilter({ export function createNumberFilter({ eventMetaKey, ...config -}: Omit): Omit & { +}: Omit): Omit & { valueType: "number"; } { return { @@ -149,7 +158,7 @@ export function createNumberFilter({ const { comparisonType, value } = filterSettings; const { eventMeta } = eventData; - const eventValue = eventMeta[getMetaKey(eventMetaKey, eventData)] ?? 0; + const eventValue = extractPropertyWithPath(eventMeta, getMetaKey(eventMetaKey, eventData, filterSettings)) ?? 0; return compareValue(comparisonType, value, eventValue); } @@ -158,19 +167,64 @@ export function createNumberFilter({ export function createTextOrNumberFilter({ eventMetaKey, + caseInsensitive, ...config -}: Omit): Omit { +}: Omit): Omit { return { ...config, comparisonTypes: NUMBER_TEXT_COMPARISON_TYPES, valueType: "text", async predicate(filterSettings, eventData) { - const { comparisonType, value: filterValue } = filterSettings; + const { comparisonType, value } = filterSettings; const { eventMeta } = eventData; - const eventValue = eventMeta[getMetaKey(eventMetaKey, eventData)] ?? ""; - + let eventValue = extractPropertyWithPath(eventMeta, getMetaKey(eventMetaKey, eventData, filterSettings)) ?? ""; + if (caseInsensitive) { + eventValue = eventValue.toString().toLowerCase(); + } + const filterValue = + (caseInsensitive ? value?.toString()?.toLowerCase() : value) ?? ""; return compareValue(comparisonType, filterValue, eventValue); } }; } + +export function createPresetFilter({ + eventMetaKey, + presetValues, + getSelectedValueDisplay, + valueIsStillValid, + allowIsNot = false, + ...config +}: Omit): EventFilter { + const comparisonTypes: ComparisonType[] = [ComparisonType.IS]; + if (allowIsNot) { + comparisonTypes.push(ComparisonType.IS_NOT); + } + + const valueDisplay = getSelectedValueDisplay ?? (async (filterSettings, $injector: auto.IInjectorService) => { + return (await $injector.invoke(presetValues, {}, {})) + .find(pv => pv.value === filterSettings.value)?.display ?? "[Not Set]"; + }); + + return { + ...config, + comparisonTypes, + valueType: "preset", + presetValues, + getSelectedValueDisplay: valueDisplay, + valueIsStillValid, + async predicate(filterSettings, eventData) { + const { value, comparisonType } = filterSettings; + const { eventMeta } = eventData; + + const data = extractPropertyWithPath(eventMeta, getMetaKey(eventMetaKey, eventData, filterSettings)); + + const output = data === value || + (data === true && value === "true") || + (data === false && value === "false"); + + return comparisonType === ComparisonType.IS ? output : !output; + } + }; +} diff --git a/src/backend/integrations/builtin/obs/filters/group-name-filter.ts b/src/backend/integrations/builtin/obs/filters/group-name-filter.ts index 4d080111a..6b280a7a2 100644 --- a/src/backend/integrations/builtin/obs/filters/group-name-filter.ts +++ b/src/backend/integrations/builtin/obs/filters/group-name-filter.ts @@ -13,7 +13,7 @@ export const GroupNameEventFilter: EventFilter = { description: "Filter on the name of the group owning the item that triggered the event", valueType: "preset", comparisonTypes: ["is", "is not"], - presetValues: (backendCommunicator, $q) => { + presetValues: (backendCommunicator: any, $q: any) => { return $q .when(backendCommunicator.fireEvents("obs-get-group-list")) .then((groups: string[]) => diff --git a/src/backend/integrations/builtin/obs/filters/scene-name-filter.ts b/src/backend/integrations/builtin/obs/filters/scene-name-filter.ts index aff418905..7a43ddce8 100644 --- a/src/backend/integrations/builtin/obs/filters/scene-name-filter.ts +++ b/src/backend/integrations/builtin/obs/filters/scene-name-filter.ts @@ -15,7 +15,7 @@ export const SceneNameEventFilter: EventFilter = { description: "Filter on the name of the now active OBS scene", valueType: "preset", comparisonTypes: ["is", "is not"], - presetValues: (backendCommunicator: any, $q) => { + presetValues: (backendCommunicator: any, $q: any) => { return $q .when(backendCommunicator.fireEventAsync("obs-get-scene-list")) .then((scenes: string[]) => diff --git a/src/backend/utility.js b/src/backend/utility.js index fb4879286..ebc72b54d 100644 --- a/src/backend/utility.js +++ b/src/backend/utility.js @@ -63,18 +63,16 @@ const secondsForHumans = (seconds) => { continue; } returntext += - ` ${ - levels[i][0] - } ${ - levels[i][0] === 1 - ? levels[i][1].substr(0, levels[i][1].length - 1) - : levels[i][1]}`; + ` ${levels[i][0] + } ${levels[i][0] === 1 + ? levels[i][1].substr(0, levels[i][1].length - 1) + : levels[i][1]}`; } return returntext.trim(); }; const formattedSeconds = (secs, simpleOutput = false) => { - const duration = Duration.fromDurationLike({ seconds: Math.round(secs)}).rescale(); + const duration = Duration.fromDurationLike({ seconds: Math.round(secs) }).rescale(); if (simpleOutput === true) { if (simpleOutput) { @@ -295,6 +293,29 @@ const findIndexIgnoreCase = (array, element) => { return -1; }; +/** + * extract a property from an object using a dot-notation property path + * @param {Object} obj input object + * @param {string} path dot-notation based property path + * @param {*} defaultValue default value if no value exists at the specified path + * @returns {*|undefined} value at path, defaultValue or undefined + */ +const extractPropertyWithPath = (obj, path, defaultValue = undefined) => { + const propertyPath = path.split(""); + let data = structuredClone(obj); + try { + for (const item of propertyPath) { + if (data === undefined) { + return defaultValue; + } + data = data[item]; + } + return data ?? defaultValue; + } catch (_) { + return defaultValue; + } +}; + exports.getRandomInt = getRandomInt; exports.escapeRegExp = escapeRegExp; exports.getUrlRegex = getUrlRegex; @@ -316,3 +337,4 @@ exports.deepClone = deepClone; exports.deepFreeze = deepFreeze; exports.emptyFolder = emptyFolder; exports.findIndexIgnoreCase = findIndexIgnoreCase; +exports.extractPropertyWithPath = extractPropertyWithPath; diff --git a/src/types/events.d.ts b/src/types/events.d.ts index 37fe5c417..42e147877 100644 --- a/src/types/events.d.ts +++ b/src/types/events.d.ts @@ -1,3 +1,5 @@ +import { ComparisonType } from "src/shared/filter-constants"; + export type EventSource = { id: string; name: string; @@ -10,6 +12,16 @@ export type EventSource = { }>; }; +export type PresetValue = { + value: any; + display: string; +} + +export type FilterSettings = { + comparisonType: ComparisonType; + value: any; +}; + export type EventFilter = { id: string; name: string; @@ -20,13 +32,15 @@ export type EventFilter = { }>; comparisonTypes: string[]; valueType: "text" | "preset"; - presetValues(...args: any[]): Promise; + presetValues?(...args: unknown[]): Promise | PresetValue[]; + valueIsStillValid?(filterSettings: FilterSettings, ...args: unknown[]): Promise | boolean; + getSelectedValueDisplay?(filterSettings: FilterSettings, ...args: unknown[]): Promise | string; predicate( - filterSettings: { comparisonType: string; value: any }, + filterSettings: FilterSettings, eventData: { eventSourceId: string; eventId: string; - eventMeta: Record; + eventMeta: Record; } - ): Promise; + ): Promise | boolean; }; \ No newline at end of file From 98a770b9da78ad1ca22d1f9158357d77b3993887 Mon Sep 17 00:00:00 2001 From: dennisrijsdijk Date: Fri, 8 Nov 2024 15:34:49 +0100 Subject: [PATCH 4/5] refactor: OBS filters --- .../builtin/obs/filters/group-name-filter.ts | 45 +++++++------------ .../builtin/obs/filters/scene-name-filter.ts | 45 +++++++------------ .../builtin/obs/obs-integration.ts | 4 +- 3 files changed, 34 insertions(+), 60 deletions(-) diff --git a/src/backend/integrations/builtin/obs/filters/group-name-filter.ts b/src/backend/integrations/builtin/obs/filters/group-name-filter.ts index 6b280a7a2..ffde89d81 100644 --- a/src/backend/integrations/builtin/obs/filters/group-name-filter.ts +++ b/src/backend/integrations/builtin/obs/filters/group-name-filter.ts @@ -1,41 +1,28 @@ +import { createPresetFilter } from "../../../../events/filters/filter-factory"; import { EventFilter } from "../../../../../types/events"; import { OBS_EVENT_SOURCE_ID, OBS_SCENE_ITEM_ENABLE_STATE_CHANGED_EVENT_ID } from "../constants"; -export const GroupNameEventFilter: EventFilter = { +const filter: EventFilter = createPresetFilter({ id: "ebiggz:obs-group-name", name: "Group Name", + description: "Filter on the name of the group owning the item that triggered the event", events: [ { eventSourceId: OBS_EVENT_SOURCE_ID, eventId: OBS_SCENE_ITEM_ENABLE_STATE_CHANGED_EVENT_ID } ], - description: "Filter on the name of the group owning the item that triggered the event", - valueType: "preset", - comparisonTypes: ["is", "is not"], - presetValues: (backendCommunicator: any, $q: any) => { - return $q - .when(backendCommunicator.fireEvents("obs-get-group-list")) - .then((groups: string[]) => - groups.map((g) => { - return { - value: g, - display: g - }; - }) - ); - }, - predicate: async ({ comparisonType, value }, { eventMeta }) => { - const expected = value; - const actual = eventMeta.groupName; - - switch (comparisonType) { - case "is": - return actual === expected; - case "is not": - return actual !== expected; - default: - return false; - } + eventMetaKey: "groupName", + allowIsNot: true, + presetValues: async (backendCommunicator: any) => { + const groups: string[] = backendCommunicator.fireEventSync("obs-get-group-list"); + return groups.map((g) => { + return { + value: g, + display: g + }; + }); } -}; +}); + +export default filter; diff --git a/src/backend/integrations/builtin/obs/filters/scene-name-filter.ts b/src/backend/integrations/builtin/obs/filters/scene-name-filter.ts index 7a43ddce8..7a8ab41ca 100644 --- a/src/backend/integrations/builtin/obs/filters/scene-name-filter.ts +++ b/src/backend/integrations/builtin/obs/filters/scene-name-filter.ts @@ -1,3 +1,4 @@ +import { createPresetFilter } from "../../../../events/filters/filter-factory"; import { EventFilter } from "../../../../../types/events"; import { OBS_EVENT_SOURCE_ID, @@ -5,39 +6,25 @@ import { OBS_SCENE_ITEM_ENABLE_STATE_CHANGED_EVENT_ID } from "../constants"; -export const SceneNameEventFilter: EventFilter = { +const filter: EventFilter = createPresetFilter({ id: "ebiggz:obs-scene-name", name: "Scene Name", + description: "Filter on the name of the now active OBS scene", events: [ { eventSourceId: OBS_EVENT_SOURCE_ID, eventId: OBS_SCENE_CHANGED_EVENT_ID }, { eventSourceId: OBS_EVENT_SOURCE_ID, eventId: OBS_SCENE_ITEM_ENABLE_STATE_CHANGED_EVENT_ID } ], - description: "Filter on the name of the now active OBS scene", - valueType: "preset", - comparisonTypes: ["is", "is not"], - presetValues: (backendCommunicator: any, $q: any) => { - return $q - .when(backendCommunicator.fireEventAsync("obs-get-scene-list")) - .then((scenes: string[]) => - scenes.map((s) => { - return { - value: s, - display: s - }; - }) - ); - }, - predicate: async ({ comparisonType, value }, { eventMeta }) => { - const expected = value; - const actual = eventMeta.sceneName; - - switch (comparisonType) { - case "is": - return actual === expected; - case "is not": - return actual !== expected; - default: - return false; - } + eventMetaKey: "sceneName", + allowIsNot: true, + presetValues: async (backendCommunicator: any) => { + const scenes: string[] = await backendCommunicator.fireEventAsync("obs-get-scene-list"); + return scenes.map((s) => { + return { + value: s, + display: s + }; + }); } -}; +}); + +export default filter; diff --git a/src/backend/integrations/builtin/obs/obs-integration.ts b/src/backend/integrations/builtin/obs/obs-integration.ts index 671c43834..ffe8bc14e 100644 --- a/src/backend/integrations/builtin/obs/obs-integration.ts +++ b/src/backend/integrations/builtin/obs/obs-integration.ts @@ -39,8 +39,8 @@ import { TakeOBSSourceScreenshotEffectType } from "./effects/take-obs-source-scr import { OBSEventSource } from "./events/obs-event-source"; -import { GroupNameEventFilter } from "./filters/group-name-filter"; -import { SceneNameEventFilter } from "./filters/scene-name-filter"; +import GroupNameEventFilter from "./filters/group-name-filter"; +import SceneNameEventFilter from "./filters/scene-name-filter"; import { SceneNameVariable } from "./variables/scene-name-variable"; import { SceneCollectionNameVariable } from "./variables/scene-collection-name"; From 5cb878afe77c354c5266c967b82ada9fa71d6555 Mon Sep 17 00:00:00 2001 From: dennisrijsdijk Date: Fri, 8 Nov 2024 19:22:12 +0100 Subject: [PATCH 5/5] refactor: streamloots filters --- .../builtin/streamloots/filters/card-name.js | 44 -------------- .../builtin/streamloots/filters/card-name.ts | 14 +++++ .../streamloots/filters/card-rarity.js | 58 ------------------- .../streamloots/filters/card-rarity.ts | 34 +++++++++++ .../filters/{chest-gift.js => chest-gift.ts} | 8 ++- .../streamloots/filters/chest-quantity.js | 40 ------------- .../streamloots/filters/chest-quantity.ts | 13 +++++ 7 files changed, 66 insertions(+), 145 deletions(-) delete mode 100644 src/backend/integrations/builtin/streamloots/filters/card-name.js create mode 100644 src/backend/integrations/builtin/streamloots/filters/card-name.ts delete mode 100644 src/backend/integrations/builtin/streamloots/filters/card-rarity.js create mode 100644 src/backend/integrations/builtin/streamloots/filters/card-rarity.ts rename src/backend/integrations/builtin/streamloots/filters/{chest-gift.js => chest-gift.ts} (90%) delete mode 100644 src/backend/integrations/builtin/streamloots/filters/chest-quantity.js create mode 100644 src/backend/integrations/builtin/streamloots/filters/chest-quantity.ts diff --git a/src/backend/integrations/builtin/streamloots/filters/card-name.js b/src/backend/integrations/builtin/streamloots/filters/card-name.js deleted file mode 100644 index 95dfba2ec..000000000 --- a/src/backend/integrations/builtin/streamloots/filters/card-name.js +++ /dev/null @@ -1,44 +0,0 @@ -"use strict"; - -const { ComparisonType } = require("../../../../../shared/filter-constants"); - -module.exports = { - id: "streamloots:card-name", - name: "Card Name", - description: "Filter by StreamLoots Card name", - events: [ - { eventSourceId: "streamloots", eventId: "redemption" } - ], - comparisonTypes: [ComparisonType.IS, ComparisonType.IS_NOT, ComparisonType.CONTAINS, ComparisonType.MATCHES_REGEX], - valueType: "text", - predicate: (filterSettings, eventData) => { - - const { comparisonType, value } = filterSettings; - const { eventMeta } = eventData; - - let cardName = eventMeta.cardName; - - if (!cardName) { - return false; - } - - cardName = cardName.toLowerCase(); - - const filterCardName = value && value.toLowerCase(); - - switch (comparisonType) { - case ComparisonType.IS: - return cardName === filterCardName; - case ComparisonType.IS_NOT: - return cardName !== filterCardName; - case ComparisonType.CONTAINS: - return cardName.includes(filterCardName); - case ComparisonType.MATCHES_REGEX: { - const regex = new RegExp(filterCardName, "gi"); - return regex.test(cardName); - } - default: - return false; - } - } -}; \ No newline at end of file diff --git a/src/backend/integrations/builtin/streamloots/filters/card-name.ts b/src/backend/integrations/builtin/streamloots/filters/card-name.ts new file mode 100644 index 000000000..8e072b3f1 --- /dev/null +++ b/src/backend/integrations/builtin/streamloots/filters/card-name.ts @@ -0,0 +1,14 @@ +import { createTextFilter } from "../../../../events/filters/filter-factory"; + +const filter = createTextFilter({ + id: "streamloots:card-name", + name: "Card Name", + description: "Filter by StreamLoots Card name", + events: [ + { eventSourceId: "streamloots", eventId: "redemption" } + ], + eventMetaKey: "cardName", + caseInsensitive: true +}); + +module.exports = filter; \ No newline at end of file diff --git a/src/backend/integrations/builtin/streamloots/filters/card-rarity.js b/src/backend/integrations/builtin/streamloots/filters/card-rarity.js deleted file mode 100644 index de2c69d74..000000000 --- a/src/backend/integrations/builtin/streamloots/filters/card-rarity.js +++ /dev/null @@ -1,58 +0,0 @@ -"use strict"; - -const { ComparisonType } = require("../../../../../shared/filter-constants"); - -module.exports = { - id: "streamloots:card-rarity", - name: "Card Rarity", - description: "Filter by the rarity of redeemed Streamloots Cards", - events: [ - { eventSourceId: "streamloots", eventId: "redemption" } - ], - comparisonTypes: [ComparisonType.IS, ComparisonType.IS_NOT], - valueType: "preset", - presetValues: async () => { - return [ - { - value: "common", - display: "Common" - }, - { - value: "rare", - display: "Rare" - }, - { - value: "epic", - display: "Epic" - }, - { - value: "legendary", - display: "Legendary" - } - ]; - }, - getSelectedValueDisplay: (filterSettings) => { - - const capitalize = ([first, ...rest]) => - first.toUpperCase() + rest.join("").toLowerCase(); - - if (filterSettings.value == null) { - return "[Not set]"; - } - - return capitalize(filterSettings.value); - }, - predicate: (filterSettings, eventData) => { - - const { comparisonType, value } = filterSettings; - const { eventMeta } = eventData; - - const cardRarity = eventMeta.cardRarity; - - if (!cardRarity) { - return false; - } - - return comparisonType === ComparisonType.IS ? value === cardRarity : value !== cardRarity; - } -}; \ No newline at end of file diff --git a/src/backend/integrations/builtin/streamloots/filters/card-rarity.ts b/src/backend/integrations/builtin/streamloots/filters/card-rarity.ts new file mode 100644 index 000000000..1ecba36c0 --- /dev/null +++ b/src/backend/integrations/builtin/streamloots/filters/card-rarity.ts @@ -0,0 +1,34 @@ +import { createPresetFilter } from "../../../../events/filters/filter-factory"; + +const filter = createPresetFilter({ + id: "streamloots:card-rarity", + name: "Card Rarity", + description: "Filter by the rarity of redeemed Streamloots Cards", + events: [ + { eventSourceId: "streamloots", eventId: "redemption" } + ], + eventMetaKey: "cardRarity", + allowIsNot: true, + presetValues: async () => { + return [ + { + value: "common", + display: "Common" + }, + { + value: "rare", + display: "Rare" + }, + { + value: "epic", + display: "Epic" + }, + { + value: "legendary", + display: "Legendary" + } + ]; + } +}); + +module.exports = filter; \ No newline at end of file diff --git a/src/backend/integrations/builtin/streamloots/filters/chest-gift.js b/src/backend/integrations/builtin/streamloots/filters/chest-gift.ts similarity index 90% rename from src/backend/integrations/builtin/streamloots/filters/chest-gift.js rename to src/backend/integrations/builtin/streamloots/filters/chest-gift.ts index f0f47bb7a..1657b9f71 100644 --- a/src/backend/integrations/builtin/streamloots/filters/chest-gift.js +++ b/src/backend/integrations/builtin/streamloots/filters/chest-gift.ts @@ -1,8 +1,8 @@ -"use strict"; +import { EventFilter } from "../../../../../types/events"; const { ComparisonType } = require("../../../../../shared/filter-constants"); -module.exports = { +const filter: EventFilter = { id: "streamloots:gift-purchase", name: "Chest Purchase", description: "Filter by whether or not the StreamLoots chest purchase was a gift.", @@ -42,4 +42,6 @@ module.exports = { return filterGiftValue === isGift; } -}; \ No newline at end of file +}; + +module.exports = filter; \ No newline at end of file diff --git a/src/backend/integrations/builtin/streamloots/filters/chest-quantity.js b/src/backend/integrations/builtin/streamloots/filters/chest-quantity.js deleted file mode 100644 index ffffb518e..000000000 --- a/src/backend/integrations/builtin/streamloots/filters/chest-quantity.js +++ /dev/null @@ -1,40 +0,0 @@ -"use strict"; - -module.exports = { - id: "streamloots:chest-quantity", - name: "Chest Quantity", - description: "Filter by the number of StreamLoots chests purchased/gifted.", - events: [ - { eventSourceId: "streamloots", eventId: "purchase" } - ], - comparisonTypes: ["is", "is not", "less than", "greater than"], - valueType: "number", - predicate: (filterSettings, eventData) => { - - const { comparisonType, value } = filterSettings; - const { eventMeta } = eventData; - - const quantity = eventMeta.quantity; - - if (quantity === undefined || quantity === null) { - return false; - } - - switch (comparisonType) { - case "is": { - return quantity === value; - } - case "is not": { - return quantity !== value; - } - case "less than": { - return quantity < value; - } - case "greater than": { - return quantity > value; - } - default: - return false; - } - } -}; \ No newline at end of file diff --git a/src/backend/integrations/builtin/streamloots/filters/chest-quantity.ts b/src/backend/integrations/builtin/streamloots/filters/chest-quantity.ts new file mode 100644 index 000000000..72769eb27 --- /dev/null +++ b/src/backend/integrations/builtin/streamloots/filters/chest-quantity.ts @@ -0,0 +1,13 @@ +import { createNumberFilter } from "../../../../events/filters/filter-factory"; + +const filter = createNumberFilter({ + id: "streamloots:chest-quantity", + name: "Chest Quantity", + description: "Filter by the number of StreamLoots chests purchased/gifted.", + events: [ + { eventSourceId: "streamloots", eventId: "purchase" } + ], + eventMetaKey: "quantity" +}); + +module.exports = filter; \ No newline at end of file