Skip to content

Commit

Permalink
Merge branch 'v5' of https://github.com/crowbartools/Firebot into JP_…
Browse files Browse the repository at this point in the history
…TRANSLATION_5.62.0

# Conflicts:
#	package.json
#	src/gui/app/controllers/commands.controller.js
  • Loading branch information
nmori committed Mar 23, 2024
2 parents a0bfc12 + 08dc0e2 commit 8df4797
Show file tree
Hide file tree
Showing 52 changed files with 1,639 additions and 229 deletions.
246 changes: 130 additions & 116 deletions package-lock.json

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "firebotv5",
"version": "5.62.0-beta3",
"version": "5.62.0",
"description": "Twitch 配信者のための高機能な統合BOTツール.",
"main": "build/main.js",
"scripts": {
Expand Down Expand Up @@ -46,11 +46,11 @@
"@crowbartools/firebot-custom-scripts-types": "^5.53.2-6",
"@nut-tree/nut-js": "^3.1.1",
"@seald-io/nedb": "^4.0.4",
"@twurple/api": "^7.0.6",
"@twurple/auth": "^7.0.6",
"@twurple/chat": "^7.0.6",
"@twurple/eventsub-ws": "^7.0.6",
"@twurple/pubsub": "^7.0.6",
"@twurple/api": "^7.1.0",
"@twurple/auth": "^7.1.0",
"@twurple/chat": "^7.1.0",
"@twurple/eventsub-ws": "^7.1.0",
"@twurple/pubsub": "^7.1.0",
"@zunderscore/elgato-light-control": "^1.1.2",
"angular": "^1.8.0",
"angular-animate": "^1.7.8",
Expand Down Expand Up @@ -112,7 +112,7 @@
"node-hue-api": "^4.0.11",
"node-json-db": "^1.4.1",
"node-xlsx": "^0.20.0",
"obs-websocket-js": "^5.0.3",
"obs-websocket-js": "^5.0.5",
"request": "^2.85.0",
"roll": "^1.2.0",
"sanitize-filename": "^1.6.3",
Expand Down
4 changes: 2 additions & 2 deletions src/backend/app-management/electron/window-management.js
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ async function createMainWindow() {
);

// wait for the main window's content to load, then show it
mainWindow.webContents.on("did-finish-load", () => {
mainWindow.webContents.on("did-finish-load", async () => {


createTray(mainWindow);
Expand All @@ -457,7 +457,7 @@ async function createMainWindow() {
}

const startupScriptsManager = require("../../common/handlers/custom-scripts/startup-scripts-manager");
startupScriptsManager.runStartupScripts();
await startupScriptsManager.runStartupScripts();

const eventManager = require("../../events/EventManager");
eventManager.triggerEvent("firebot", "firebot-started", {
Expand Down
3 changes: 3 additions & 0 deletions src/backend/auth/twitch-auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,11 @@ class TwitchAuthProviders {
'moderator:read:chat_settings',
'moderator:read:chatters',
'moderator:read:followers',
'moderator:read:moderators',
'moderator:read:shield_mode',
'moderator:read:shoutouts',
'moderator:read:unban_requests',
'moderator:read:vips',
'user:edit:broadcast',
'user:manage:blocked_users',
'user:manage:whispers',
Expand Down Expand Up @@ -109,6 +111,7 @@ class TwitchAuthProviders {
'moderator:manage:announcements',
'user:manage:whispers',
'user:read:chat',
'user:read:emotes',
'user:write:chat',
'whispers:edit',
'whispers:read'
Expand Down
5 changes: 4 additions & 1 deletion src/backend/chat/chat-listeners/twitch-chat-listeners.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,10 @@ exports.setupChatListeners = (streamerChatClient, botChatClient) => {
if (firebotChatMessage.isFirstChat) {
twitchEventsHandler.chatMessage.triggerFirstTimeChat(firebotChatMessage);
}
await raidMessageChecker.sendMessageToCache(firebotChatMessage);
await raidMessageChecker.sendMessageToCache({
rawText: firebotChatMessage.rawText,
userId: firebotChatMessage.userId
});
});

const whisperHandler = async (_user, messageText, msg, accountType) => {
Expand Down
22 changes: 13 additions & 9 deletions src/backend/chat/moderation/raid-message-checker.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import { FirebotChatMessage } from "../../../types/chat";
import logger from "../../logwrapper";
import twitchApi from "../../twitch-api/api";

interface RaidMessage {
rawText: string;
userId: string;
}

class RaidMessageChecker {
private readonly _chatCacheLimit = 50;
private _messageCache: FirebotChatMessage[] = [];
private _messageCache: RaidMessage[] = [];
private _raidMessage = "";
private _checkerEnabled = false;
private _settings = {
shouldBan: false,
shouldBlock: false
};

private async handleRaider(message: FirebotChatMessage): Promise<void> {
private async handleRaider(message: RaidMessage): Promise<void> {
if (this._settings.shouldBan) {
await twitchApi.moderation.banUser(message.userId);
}
Expand Down Expand Up @@ -48,19 +52,19 @@ class RaidMessageChecker {
}
}

async sendMessageToCache(firebotChatMessage: FirebotChatMessage): Promise<void> {
async sendMessageToCache(raidMessage: RaidMessage): Promise<void> {
if (this._messageCache.length >= this._chatCacheLimit) {
this._messageCache.shift();
}

if (firebotChatMessage.rawText.length > 10) {
firebotChatMessage.rawText = firebotChatMessage.rawText.substr(10);
if (raidMessage.rawText.length > 10) {
raidMessage.rawText = raidMessage.rawText.substr(10);
}

this._messageCache.push(firebotChatMessage);
this._messageCache.push(raidMessage);

if (firebotChatMessage && this._checkerEnabled && firebotChatMessage.rawText === this._raidMessage) {
await this.handleRaider(firebotChatMessage);
if (raidMessage && this._checkerEnabled && raidMessage.rawText === this._raidMessage) {
await this.handleRaider(raidMessage);
}
}

Expand Down
9 changes: 9 additions & 0 deletions src/backend/common/settings-access.js
Original file line number Diff line number Diff line change
Expand Up @@ -322,4 +322,13 @@ settings.setWebOnlineCheckin = (value) => {
pushDataToFile("/settings/webOnlineCheckin", value);
};

settings.getTriggerUpcomingAdBreakMinutes = function() {
const value = getDataFromFile("/settings/triggerUpcomingAdBreakMinutes", false, 0);
return value ?? 0;
};

settings.setTriggerUpcomingAdBreakMinutes = function(value) {
pushDataToFile("/settings/triggerUpcomingAdBreakMinutes", value);
};

exports.settings = settings;
3 changes: 2 additions & 1 deletion src/backend/effects/builtin-effect-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ exports.loadEffects = () => {
'twitch/raid',
'twitch/set-chat-mode',
'twitch/shoutout',
'twitch/snooze-ad-break',
'twitch/stream-title',
'twitch/stream-game',

Expand All @@ -96,7 +97,7 @@ exports.loadEffects = () => {
'twitch/create-prediction',
'twitch/lock-prediction',
'twitch/resolve-prediction'
].forEach(filename => {
].forEach((filename) => {
const definition = require(`./builtin/${filename}`);
effectManager.registerEffect(definition);
});
Expand Down
10 changes: 5 additions & 5 deletions src/backend/effects/builtin/toggle-connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,12 @@ const toggleConnection = {
$scope.effect.services = [];
}

$scope.serviceIsSelected = (serviceId) => $scope.effect.services.some(s => s.id === serviceId);
$scope.serviceIsSelected = serviceId => $scope.effect.services.some(s => s.id === serviceId);

$scope.toggleServiceSelected = (serviceId) => {
if ($scope.serviceIsSelected(serviceId)) {
$scope.effect.services = $scope.effect.services.filter(
(s) => s.id !== serviceId
s => s.id !== serviceId
);
} else {
$scope.effect.services.push({
Expand All @@ -92,7 +92,7 @@ const toggleConnection = {
action
) => {
const service = $scope.effect.services.find(
(s) => s.id === serviceId
s => s.id === serviceId
);
if (service != null) {
service.action = action;
Expand All @@ -101,7 +101,7 @@ const toggleConnection = {

$scope.getConnectionActionDisplay = (serviceId) => {
const service = $scope.effect.services.find(
(s) => s.id === serviceId
s => s.id === serviceId
);
if (service == null) {
return "";
Expand Down Expand Up @@ -153,7 +153,7 @@ const toggleConnection = {
.getAllIntegrationDefinitions()
.filter(i => integrationManager.integrationIsConnectable(i.id))
.map(i => ({
id: i.id,
id: `integration.${i.id}`,
action: effect.allAction
}))
];
Expand Down
29 changes: 29 additions & 0 deletions src/backend/effects/builtin/twitch/set-chat-mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ const model: EffectType<{
setSlowMode: boolean;
enableSlowMode?: boolean;
slowModeDelay?: number;

setUniqueChat: boolean;
enableUniqueChat?: boolean;
}> = {
definition: {
id: "firebot:set-chat-mode",
Expand Down Expand Up @@ -124,6 +127,26 @@ const model: EffectType<{
input-title="遅延 (秒)"
placeholder-text="任意"
/>
<firebot-checkbox
model="effect.setUniqueChat"
label="Set Unique Chat"
tooltip="Whether or not you want to change the unique mode of your Twitch channel chat."
/>
<div class="btn-group mb-4" ng-if="effect.setUniqueChat === true">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="list-effect-type">{{effect.enableUniqueChat == null ? 'Pick one' : (effect.enableUniqueChat === true ? 'Enable' : 'Disable')}}</span> <span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li ng-click="effect.enableUniqueChat = true">
<a href>Enable</a>
</li>
<li ng-click="effect.enableUniqueChat = false">
<a href>Disable</a>
</li>
</ul>
</div>
</eos-container>
`,
optionsValidator: (effect) => {
Expand All @@ -137,6 +160,8 @@ const model: EffectType<{
errors.push("エモーションのみのアクションを指定する必要があります。");
} else if (effect.setSlowMode === true && effect.enableSlowMode == null) {
errors.push("You must specify a slow mode action");
} else if (effect.setUniqueChat === true && effect.enableUniqueChat == null) {
errors.push("You must specify a unique mode action");
}

return errors;
Expand Down Expand Up @@ -166,6 +191,10 @@ const model: EffectType<{
if (effect.setSlowMode === true) {
await twitchApi.chat.setSlowMode(effect.enableSlowMode ?? false, effect.slowModeDelay);
}

if (effect.setUniqueChat === true) {
await twitchApi.chat.setUniqueMode(effect.enableUniqueChat ?? false);
}
}
};

Expand Down
45 changes: 45 additions & 0 deletions src/backend/effects/builtin/twitch/snooze-ad-break.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { EffectType } from "../../../../types/effects";
import { EffectCategory } from "../../../../shared/effect-constants";
import twitchApi from "../../../twitch-api/api";
import adManager from "../../../twitch-api/ad-manager";

const model: EffectType = {
definition: {
id: "twitch:snooze-ad-break",
name: "Snooze Next Ad Break",
description: "Pushes back the next scheduled mid-roll ad break by 5 minutes",
icon: "fad fa-snooze",
categories: [
EffectCategory.COMMON,
EffectCategory.MODERATION,
EffectCategory.TWITCH
],
dependencies: {
twitch: true
}
},
optionsTemplate: `
<eos-container>
<div class="effect-info alert alert-warning">
Note: You must be an affiliate or partner to use this effect.
Also, Twitch limits the number of times you may snooze mid-roll ads.
If you have snoozed ads too many times in a short period, Twitch will deny this.
</div>
</eos-container>
`,
optionsController: () => {},
optionsValidator: () => {
return [];
},
onTriggerEvent: async () => {
const result = await twitchApi.channels.snoozeAdBreak();

if (result === true) {
await adManager.runAdCheck();
}

return result;
}
};

module.exports = model;
71 changes: 71 additions & 0 deletions src/backend/events/builtin/twitch-event-source.js
Original file line number Diff line number Diff line change
Expand Up @@ -931,6 +931,77 @@ module.exports = {
return `配信タイトルを **${eventData.title}** に変更しました`;
}
}
},
{
id: "ad-break-upcoming",
name: "Scheduled Ad Break Starting Soon",
description: "When a scheduled ad break will be starting soon on your channel.",
cached: false,
manualMetadata: {
adBreakDuration: 60,
secondsUntilNextAdBreak: 300
},
activityFeed: {
icon: "fad fa-ad",
getMessage: (eventData) => {
const mins = Math.floor(eventData.adBreakDuration / 60);
const remainingSecs = eventData.adBreakDuration % 60;

const friendlyDuration = mins > 0
? `${mins}m${remainingSecs > 0 ? ` ${remainingSecs}s` : ""}`
: `${eventData.adBreakDuration}s`;

const minutesUntilNextAdBreak = Math.round(eventData.secondsUntilNextAdBreak / 60);

return `**${friendlyDuration}** scheduled ad break starting in about **${minutesUntilNextAdBreak}** minute${minutesUntilNextAdBreak !== 1 ? "s" : ""}`;
}
}
},
{
id: "ad-break-start",
name: "Ad Break Started",
description: "When an ad break starts on your channel.",
cached: false,
manualMetadata: {
adBreakDuration: 60,
isAdBreakScheduled: true
},
activityFeed: {
icon: "fad fa-ad",
getMessage: (eventData) => {
const mins = Math.floor(eventData.adBreakDuration / 60);
const remainingSecs = eventData.adBreakDuration % 60;

const friendlyDuration = mins > 0
? `${mins}m${remainingSecs > 0 ? ` ${remainingSecs}s` : ""}`
: `${eventData.adBreakDuration}s`;

return `**${friendlyDuration}** **${eventData.isAdBreakScheduled ? "scheduled" : "manual"}** ad break started`;
}
}
},
{
id: "ad-break-end",
name: "Ad Break Ended",
description: "When an ad break ends on your channel.",
cached: false,
manualMetadata: {
adBreakDuration: 60,
isAdBreakScheduled: true
},
activityFeed: {
icon: "fad fa-ad",
getMessage: (eventData) => {
const mins = Math.floor(eventData.adBreakDuration / 60);
const remainingSecs = eventData.adBreakDuration % 60;

const friendlyDuration = mins > 0
? `${mins}m${remainingSecs > 0 ? ` ${remainingSecs}s` : ""}`
: `${eventData.adBreakDuration}s`;

return `**${friendlyDuration}** **${eventData.isAdBreakScheduled ? "scheduled" : "manual"}** ad break ended`;
}
}
}
]
};
Loading

0 comments on commit 8df4797

Please sign in to comment.