mirror of
https://git.sr.ht/~ashkeel/strimertul
synced 2024-09-18 01:50:50 +00:00
feat: Add sending chat command responses as whispers/replies/announcements
This commit is contained in:
parent
f83a6c6180
commit
29880bdc23
9 changed files with 97 additions and 3 deletions
|
@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## [current]
|
||||
|
||||
### Added
|
||||
|
||||
- Custom chat commands can now be sent as replies, whispers and announcements. Due to some API shenanigans yet to be solved, the latter two will always be sent from your main account, not the bot account (if they are different)
|
||||
|
||||
## [3.2.0] - 2023-05-03
|
||||
|
||||
### Added
|
||||
|
|
|
@ -116,6 +116,12 @@
|
|||
"command-response-placeholder": "Hello {0}!",
|
||||
"command-acl": "Access level",
|
||||
"command-acl-help": "This specifies the minimum level, eg. if you choose VIPs, moderators and streamer can still use the command",
|
||||
"response-types": {
|
||||
"chat": "Message",
|
||||
"reply": "Reply",
|
||||
"whisper": "Whisper",
|
||||
"announce": "Announcement"
|
||||
},
|
||||
"acl": {
|
||||
"everyone": "Everyone",
|
||||
"subscribers": "Subscribers",
|
||||
|
|
|
@ -112,7 +112,13 @@
|
|||
"subscribers": "Abbonati",
|
||||
"vip": "VIP"
|
||||
},
|
||||
"command-already-in-use": "Nome comando già in uso"
|
||||
"command-already-in-use": "Nome comando già in uso",
|
||||
"response-types": {
|
||||
"announce": "Annuncio",
|
||||
"chat": "Canale",
|
||||
"reply": "Risposta",
|
||||
"whisper": "Chat privata"
|
||||
}
|
||||
},
|
||||
"bottimers": {
|
||||
"add-button": "Nuovo timer",
|
||||
|
|
|
@ -34,10 +34,12 @@ export const accessLevels = [
|
|||
|
||||
export type AccessLevelType = (typeof accessLevels)[number];
|
||||
|
||||
export type ReplyType = 'chat' | 'reply' | 'whisper' | 'announce';
|
||||
export interface TwitchBotCustomCommand {
|
||||
description: string;
|
||||
access_level: AccessLevelType;
|
||||
response: string;
|
||||
response_type: ReplyType;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import { modules } from '~/store/api/reducer';
|
|||
import {
|
||||
accessLevels,
|
||||
AccessLevelType,
|
||||
ReplyType,
|
||||
TwitchBotCustomCommand,
|
||||
} from '~/store/api/types';
|
||||
import AlertContent from '../components/AlertContent';
|
||||
|
@ -23,6 +24,8 @@ import {
|
|||
InputBox,
|
||||
Label,
|
||||
MultiButton,
|
||||
MultiToggle,
|
||||
MultiToggleItem,
|
||||
NoneText,
|
||||
PageContainer,
|
||||
PageHeader,
|
||||
|
@ -185,11 +188,15 @@ function CommandDialog({
|
|||
const [commands] = useModule(modules.twitchBotCommands);
|
||||
const [commandName, setCommandName] = useState(name ?? '');
|
||||
const [description, setDescription] = useState(item?.description ?? '');
|
||||
const [responseType, setResponseType] = useState(
|
||||
item?.response_type ?? 'chat',
|
||||
);
|
||||
const [response, setResponse] = useState(item?.response ?? '');
|
||||
const [accessLevel, setAccessLevel] = useState(
|
||||
item?.access_level ?? 'everyone',
|
||||
);
|
||||
const { t } = useTranslation();
|
||||
const replyTypes: ReplyType[] = ['chat', 'reply', 'whisper', 'announce'];
|
||||
|
||||
return (
|
||||
<DialogContent
|
||||
|
@ -207,6 +214,7 @@ function CommandDialog({
|
|||
...item,
|
||||
description,
|
||||
response,
|
||||
response_type: responseType,
|
||||
access_level: accessLevel,
|
||||
});
|
||||
}
|
||||
|
@ -248,6 +256,20 @@ function CommandDialog({
|
|||
<Field spacing="narrow" size="fullWidth">
|
||||
<Label htmlFor="command-response">
|
||||
{t('pages.botcommands.command-response')}
|
||||
<MultiToggle
|
||||
css={{ marginLeft: '0.5rem' }}
|
||||
value={responseType}
|
||||
type="single"
|
||||
onValueChange={(newType) => {
|
||||
setResponseType(newType as ReplyType);
|
||||
}}
|
||||
>
|
||||
{replyTypes.map((replyType) => (
|
||||
<MultiToggleItem size="small" key={replyType} value={replyType}>
|
||||
{t(`pages.botcommands.response-types.${replyType}`)}
|
||||
</MultiToggleItem>
|
||||
))}
|
||||
</MultiToggle>
|
||||
</Label>
|
||||
<Textarea
|
||||
value={response}
|
||||
|
|
|
@ -22,7 +22,7 @@ func (c *Client) GetAuthorizationURL() string {
|
|||
}
|
||||
return c.API.GetAuthorizationURL(&helix.AuthorizationURLParams{
|
||||
ResponseType: "code",
|
||||
Scopes: []string{"bits:read channel:read:subscriptions channel:read:redemptions channel:read:polls channel:read:predictions channel:read:hype_train user_read chat:read chat:edit channel:moderate whispers:read whispers:edit moderator:read:chatters moderator:read:followers"},
|
||||
Scopes: []string{"bits:read channel:read:subscriptions channel:read:redemptions channel:read:polls channel:read:predictions channel:read:hype_train user_read chat:read chat:edit channel:moderate whispers:read whispers:edit moderator:read:chatters moderator:read:followers user:manage:whispers moderator:manage:announcements"},
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,40 @@ func cmdCustom(bot *Bot, cmd string, data BotCustomCommand, message irc.PrivateM
|
|||
bot.logger.Error("Failed to execute custom command template", zap.Error(err))
|
||||
return
|
||||
}
|
||||
bot.Client.Say(message.Channel, buf.String())
|
||||
|
||||
switch data.ResponseType {
|
||||
case ResponseTypeDefault, ResponseTypeChat:
|
||||
bot.Client.Say(message.Channel, buf.String())
|
||||
case ResponseTypeReply:
|
||||
bot.Client.Reply(message.Channel, message.ID, buf.String())
|
||||
case ResponseTypeWhisper:
|
||||
client, err := bot.api.GetUserClient(false)
|
||||
reply, err := client.SendUserWhisper(&helix.SendUserWhisperParams{
|
||||
FromUserID: bot.api.User.ID,
|
||||
ToUserID: message.User.ID,
|
||||
Message: buf.String(),
|
||||
})
|
||||
if reply.Error != "" {
|
||||
bot.logger.Error("Failed to send whisper", zap.String("code", reply.Error), zap.String("message", reply.ErrorMessage))
|
||||
}
|
||||
if err != nil {
|
||||
bot.logger.Error("Failed to send whisper", zap.Error(err))
|
||||
}
|
||||
|
||||
case ResponseTypeAnnounce:
|
||||
client, err := bot.api.GetUserClient(false)
|
||||
reply, err := client.SendChatAnnouncement(&helix.SendChatAnnouncementParams{
|
||||
BroadcasterID: bot.api.User.ID,
|
||||
ModeratorID: bot.api.User.ID,
|
||||
Message: buf.String(),
|
||||
})
|
||||
if reply.Error != "" {
|
||||
bot.logger.Error("Failed to send announcement", zap.String("code", reply.Error), zap.String("message", reply.ErrorMessage))
|
||||
}
|
||||
if err != nil {
|
||||
bot.logger.Error("Failed to send announcement", zap.Error(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bot) setupFunctions() {
|
||||
|
|
|
@ -44,6 +44,16 @@ const (
|
|||
ChatActivityKey = "twitch/chat-activity"
|
||||
)
|
||||
|
||||
type ResponseType string
|
||||
|
||||
const (
|
||||
ResponseTypeDefault ResponseType = ""
|
||||
ResponseTypeChat ResponseType = "chat"
|
||||
ResponseTypeWhisper ResponseType = "whisper"
|
||||
ResponseTypeReply ResponseType = "reply"
|
||||
ResponseTypeAnnounce ResponseType = "announce"
|
||||
)
|
||||
|
||||
// BotCustomCommand is a definition of a custom command of the chatbot
|
||||
type BotCustomCommand struct {
|
||||
// Command description
|
||||
|
@ -57,6 +67,9 @@ type BotCustomCommand struct {
|
|||
|
||||
// Is the command enabled?
|
||||
Enabled bool `json:"enabled" desc:"Is the command enabled?"`
|
||||
|
||||
// How to respond to the user
|
||||
ResponseType ResponseType `json:"response_type" desc:"How to respond to the user"`
|
||||
}
|
||||
|
||||
const CustomCommandsKey = "twitch/bot-custom-commands"
|
||||
|
|
|
@ -80,4 +80,12 @@ var Enums = interfaces.EnumMap{
|
|||
ALTStreamer,
|
||||
},
|
||||
},
|
||||
"ResponseType": interfaces.Enum{
|
||||
Values: []any{
|
||||
ResponseTypeChat,
|
||||
ResponseTypeReply,
|
||||
ResponseTypeWhisper,
|
||||
ResponseTypeAnnounce,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue