@overlaysymphony/twitch 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +6 -2
- package/src/authentication/authentication.ts +1 -1
- package/src/authentication/index.ts +1 -1
- package/src/chat/chat.ts +69 -134
- package/src/chat/helpers.ts +33 -24
- package/src/chat/index.ts +4 -6
- package/src/chat/pronouns.ts +141 -0
- package/src/eventsub/events/automod.message.hold-2.ts +81 -0
- package/src/eventsub/events/automod.message.update-2.ts +94 -0
- package/src/eventsub/events/automod.settings.update-1.ts +65 -0
- package/src/eventsub/events/automod.terms.update-1.ts +59 -0
- package/src/eventsub/events/channel.ad_break.begin-1.ts +50 -0
- package/src/eventsub/events/channel.ban-1.ts +58 -0
- package/src/eventsub/events/channel.bits.use-1.ts +112 -0
- package/src/eventsub/events/channel.channel_points_automatic_reward_redemption.add-2.ts +88 -0
- package/src/eventsub/events/channel.channel_points_custom_reward.add-1.ts +101 -0
- package/src/eventsub/events/channel.channel_points_custom_reward.remove-1.ts +103 -0
- package/src/eventsub/events/channel.channel_points_custom_reward.update-1.ts +103 -0
- package/src/eventsub/events/channel.channel_points_custom_reward_redemption.add-1.ts +65 -0
- package/src/eventsub/events/channel.channel_points_custom_reward_redemption.update-1.ts +65 -0
- package/src/eventsub/events/channel.charity_campaign.donate-1.ts +69 -0
- package/src/eventsub/events/channel.charity_campaign.progress-1.ts +74 -0
- package/src/eventsub/events/channel.charity_campaign.start-1.ts +76 -0
- package/src/eventsub/events/channel.charity_campaign.stop-1.ts +76 -0
- package/src/eventsub/events/channel.chat.clear-1.ts +41 -0
- package/src/eventsub/events/channel.chat.clear_user_messages-1.ts +47 -0
- package/src/eventsub/events/channel.chat.message-1.ts +160 -0
- package/src/eventsub/events/channel.chat.message_delete-1.ts +49 -0
- package/src/eventsub/events/channel.chat.notification-1.ts +317 -0
- package/src/eventsub/events/channel.chat.user_message_hold-1.ts +75 -0
- package/src/eventsub/events/channel.chat.user_message_update-1.ts +82 -0
- package/src/eventsub/events/channel.chat_settings.update-1.ts +83 -0
- package/src/eventsub/events/channel.cheer-1.ts +50 -0
- package/src/eventsub/events/channel.follow-2.ts +49 -0
- package/src/eventsub/events/channel.goal.begin-1.ts +80 -0
- package/src/eventsub/events/channel.goal.end-1.ts +80 -0
- package/src/eventsub/events/channel.goal.progress-1.ts +80 -0
- package/src/eventsub/events/channel.guest_star_guest.update-beta.ts +85 -0
- package/src/eventsub/events/channel.guest_star_session.begin-beta.ts +50 -0
- package/src/eventsub/events/channel.guest_star_session.end-beta.ts +58 -0
- package/src/eventsub/events/channel.guest_star_settings.update-beta.ts +62 -0
- package/src/eventsub/events/channel.hype_train.begin-2.ts +90 -0
- package/src/eventsub/events/channel.hype_train.end-2.ts +70 -0
- package/src/eventsub/events/channel.hype_train.progress-2.ts +90 -0
- package/src/eventsub/events/channel.moderate-2.ts +258 -0
- package/src/eventsub/events/channel.moderator.add-1.ts +44 -0
- package/src/eventsub/events/channel.moderator.remove-1.ts +44 -0
- package/src/eventsub/events/channel.poll.begin-1.ts +73 -0
- package/src/eventsub/events/channel.poll.end-1.ts +75 -0
- package/src/eventsub/events/channel.poll.progress-1.ts +73 -0
- package/src/eventsub/events/channel.prediction.begin-1.ts +72 -0
- package/src/eventsub/events/channel.prediction.end-1.ts +76 -0
- package/src/eventsub/events/channel.prediction.lock-1.ts +72 -0
- package/src/eventsub/events/channel.prediction.progress-1.ts +72 -0
- package/src/eventsub/events/channel.raid-1.ts +48 -0
- package/src/eventsub/events/channel.shared_chat.begin-1.ts +55 -0
- package/src/eventsub/events/channel.shared_chat.end-1.ts +46 -0
- package/src/eventsub/events/channel.shared_chat.update-1.ts +55 -0
- package/src/eventsub/events/channel.shield_mode.begin-1.ts +51 -0
- package/src/eventsub/events/channel.shield_mode.end-1.ts +51 -0
- package/src/eventsub/events/channel.shoutout.create-1.ts +61 -0
- package/src/eventsub/events/channel.shoutout.receive-1.ts +51 -0
- package/src/eventsub/events/channel.subscribe-1.ts +48 -0
- package/src/eventsub/events/channel.subscription.end-1.ts +48 -0
- package/src/eventsub/events/channel.subscription.gift-1.ts +52 -0
- package/src/eventsub/events/channel.subscription.message-1.ts +66 -0
- package/src/eventsub/events/channel.suspicious_user.message-1.ts +85 -0
- package/src/eventsub/events/channel.suspicious_user.update-1.ts +55 -0
- package/src/eventsub/events/channel.unban-1.ts +50 -0
- package/src/eventsub/events/channel.unban_request.create-1.ts +53 -0
- package/src/eventsub/events/channel.unban_request.resolve-1.ts +64 -0
- package/src/eventsub/events/channel.update-2.ts +48 -0
- package/src/eventsub/events/channel.vip.add-1.ts +44 -0
- package/src/eventsub/events/channel.vip.remove-1.ts +44 -0
- package/src/eventsub/events/channel.warning.acknowledge-1.ts +47 -0
- package/src/eventsub/events/channel.warning.send-1.ts +57 -0
- package/src/eventsub/events/index.ts +73 -284
- package/src/eventsub/events/stream.offline-1.ts +38 -0
- package/src/eventsub/events/stream.online-1.ts +44 -0
- package/src/eventsub/events/user.update-1.ts +48 -0
- package/src/eventsub/events/user.whisper.message-1.ts +51 -0
- package/src/eventsub/events-helpers.ts +52 -24
- package/src/eventsub/eventsub.ts +37 -74
- package/src/eventsub/index.ts +8 -6
- package/src/eventsub/messages.ts +16 -4
- package/src/helix/channel-points/custom-rewards.ts +120 -33
- package/src/helix/channel-points/index.ts +1 -1
- package/src/helix/channels/channels.ts +39 -0
- package/src/helix/channels/index.ts +1 -0
- package/src/helix/chat/emotes.ts +49 -0
- package/src/helix/chat/index.ts +3 -0
- package/src/helix/chat/send.ts +109 -0
- package/src/helix/chat/shared.ts +49 -0
- package/src/helix/helix.ts +6 -21
- package/src/helix/subscriptions/index.ts +1 -1
- package/src/helix/subscriptions/subscriptions.ts +46 -48
- package/src/helix/users/index.ts +1 -1
- package/src/helix/users/users.ts +22 -19
- package/src/helpers/alerts/alerts.ts +5 -5
- package/src/helpers/alerts/index.ts +2 -2
- package/src/helpers/charity/charity.ts +2 -2
- package/src/helpers/charity/index.ts +1 -1
- package/src/helpers/goal/goal.ts +2 -2
- package/src/helpers/goal/index.ts +1 -1
- package/src/helpers/hype-train/hype-train.ts +2 -2
- package/src/helpers/hype-train/index.ts +1 -1
- package/src/helpers/poll/index.ts +1 -1
- package/src/helpers/poll/poll.ts +3 -3
- package/src/helpers/prediction/index.ts +1 -1
- package/src/helpers/prediction/prediction.ts +3 -3
- package/src/helpers/redemption/index.ts +1 -1
- package/src/helpers/redemption/redemption.ts +2 -2
- package/src/helpers/status/index.ts +1 -1
- package/src/helpers/status/status.ts +2 -2
- package/src/ui/authentication.ts +1 -1
- package/src/ui/popup.ts +26 -3
- package/src/chat/interfaces/events.ts +0 -269
- package/src/chat/interfaces/index.ts +0 -9
- package/src/chat/parser.ts +0 -254
- package/src/eventsub/events/channel.ad_break.begin.ts +0 -51
- package/src/eventsub/events/channel.ban.ts +0 -59
- package/src/eventsub/events/channel.channel_points_custom_reward._.ts +0 -29
- package/src/eventsub/events/channel.channel_points_custom_reward.add.ts +0 -75
- package/src/eventsub/events/channel.channel_points_custom_reward.remove.ts +0 -77
- package/src/eventsub/events/channel.channel_points_custom_reward.update.ts +0 -77
- package/src/eventsub/events/channel.channel_points_custom_reward_redemption._.ts +0 -10
- package/src/eventsub/events/channel.channel_points_custom_reward_redemption.add.ts +0 -59
- package/src/eventsub/events/channel.channel_points_custom_reward_redemption.update.ts +0 -59
- package/src/eventsub/events/channel.charity_campaign.donate.ts +0 -66
- package/src/eventsub/events/channel.charity_campaign.progress.ts +0 -67
- package/src/eventsub/events/channel.charity_campaign.start.ts +0 -69
- package/src/eventsub/events/channel.charity_campaign.stop.ts +0 -69
- package/src/eventsub/events/channel.chat.clear.ts +0 -42
- package/src/eventsub/events/channel.chat.clear_user_messages.ts +0 -48
- package/src/eventsub/events/channel.chat.message_delete.ts +0 -50
- package/src/eventsub/events/channel.chat.notification.ts +0 -50
- package/src/eventsub/events/channel.cheer.ts +0 -51
- package/src/eventsub/events/channel.follow.ts +0 -50
- package/src/eventsub/events/channel.goal.begin.ts +0 -51
- package/src/eventsub/events/channel.goal.end.ts +0 -55
- package/src/eventsub/events/channel.goal.progress.ts +0 -51
- package/src/eventsub/events/channel.guest_star_guest.update.ts +0 -66
- package/src/eventsub/events/channel.guest_star_session.begin.ts +0 -46
- package/src/eventsub/events/channel.guest_star_session.end.ts +0 -48
- package/src/eventsub/events/channel.guest_star_settings.update.ts +0 -50
- package/src/eventsub/events/channel.hype_train._.ts +0 -12
- package/src/eventsub/events/channel.hype_train.begin.ts +0 -57
- package/src/eventsub/events/channel.hype_train.end.ts +0 -55
- package/src/eventsub/events/channel.hype_train.progress.ts +0 -70
- package/src/eventsub/events/channel.moderator.add.ts +0 -45
- package/src/eventsub/events/channel.moderator.remove.ts +0 -45
- package/src/eventsub/events/channel.poll._.ts +0 -26
- package/src/eventsub/events/channel.poll.begin.ts +0 -55
- package/src/eventsub/events/channel.poll.end.ts +0 -57
- package/src/eventsub/events/channel.poll.progress.ts +0 -55
- package/src/eventsub/events/channel.prediction._.ts +0 -25
- package/src/eventsub/events/channel.prediction.begin.ts +0 -51
- package/src/eventsub/events/channel.prediction.end.ts +0 -55
- package/src/eventsub/events/channel.prediction.lock.ts +0 -51
- package/src/eventsub/events/channel.prediction.progress.ts +0 -51
- package/src/eventsub/events/channel.raid.ts +0 -49
- package/src/eventsub/events/channel.shield_mode.begin.ts +0 -50
- package/src/eventsub/events/channel.shield_mode.end.ts +0 -50
- package/src/eventsub/events/channel.shoutout.create.ts +0 -62
- package/src/eventsub/events/channel.shoutout.receive.ts +0 -52
- package/src/eventsub/events/channel.subscribe.ts +0 -49
- package/src/eventsub/events/channel.subscription.end.ts +0 -49
- package/src/eventsub/events/channel.subscription.gift.ts +0 -53
- package/src/eventsub/events/channel.subscription.message.ts +0 -67
- package/src/eventsub/events/channel.unban.ts +0 -51
- package/src/eventsub/events/channel.update.ts +0 -49
- package/src/eventsub/events/stream.offline.ts +0 -39
- package/src/eventsub/events/stream.online.ts +0 -45
- package/src/eventsub/events/user.update.ts +0 -45
package/package.json
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@overlaysymphony/twitch",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Twitch module for the OverlaySymphony interactive streaming framework.",
|
|
5
5
|
"homepage": "https://github.com/OverlaySymphony/overlaysymphony",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/OverlaySymphony/overlaysymphony"
|
|
9
|
+
},
|
|
6
10
|
"type": "module",
|
|
7
11
|
"exports": {
|
|
8
12
|
"./authentication": "./src/authentication/index.ts",
|
|
@@ -14,7 +18,7 @@
|
|
|
14
18
|
"./package.json": "./package.json"
|
|
15
19
|
},
|
|
16
20
|
"dependencies": {
|
|
17
|
-
"@overlaysymphony/core": "0.2.
|
|
21
|
+
"@overlaysymphony/core": "0.2.1"
|
|
18
22
|
},
|
|
19
23
|
"devDependencies": {
|
|
20
24
|
"@vitest/coverage-v8": "^2.1.2",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from "./authentication.
|
|
1
|
+
export * from "./authentication.ts"
|
package/src/chat/chat.ts
CHANGED
|
@@ -1,161 +1,96 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
type ChatSubscriber = <
|
|
15
|
-
EventType extends TwitchChatEventType,
|
|
16
|
-
Event extends TwitchChatEvent<EventType>,
|
|
17
|
-
>(
|
|
18
|
-
types: EventType[],
|
|
19
|
-
callback: (event: Event) => void,
|
|
20
|
-
) => () => void
|
|
1
|
+
import { type Authentication } from "../authentication/index.ts"
|
|
2
|
+
import { type EventPayload } from "../eventsub/events-helpers.ts"
|
|
3
|
+
import createEventSub, { type TwitchEventSub } from "../eventsub/index.ts"
|
|
4
|
+
import { sendChatAnnouncement, sendChatMessage } from "../helix/chat/index.ts"
|
|
5
|
+
|
|
6
|
+
type ChatMessage = EventPayload<"channel.chat.message">["event"]
|
|
7
|
+
type ChatCommand = ChatMessage & {
|
|
8
|
+
message: {
|
|
9
|
+
command: string
|
|
10
|
+
parameters?: string[]
|
|
11
|
+
} & ChatMessage["message"]
|
|
12
|
+
}
|
|
21
13
|
|
|
22
|
-
type ChatSender = (message: string) => void
|
|
14
|
+
type ChatSender = (message: string) => Promise<void>
|
|
15
|
+
type ChatAnnouncer = (message: string, color?: string) => Promise<void>
|
|
23
16
|
|
|
24
17
|
type ChatMessageSubscriber = (
|
|
25
|
-
callback: (event:
|
|
18
|
+
callback: (event: ChatMessage) => void,
|
|
26
19
|
) => () => void
|
|
27
20
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
21
|
+
type ChatCommandSubscriber = (
|
|
22
|
+
name: string,
|
|
23
|
+
callback: (event: ChatCommand) => void,
|
|
24
|
+
___?: never,
|
|
25
|
+
) => () => void
|
|
26
|
+
// type ChatCommandSubscriber = (
|
|
27
|
+
// name: string,
|
|
28
|
+
// pattern: string,
|
|
29
|
+
// callback: (event: ChatCommand) => void,
|
|
30
|
+
// ) => () => void
|
|
38
31
|
|
|
39
32
|
export interface TwitchChat {
|
|
40
|
-
listen: ChatListener
|
|
41
|
-
subscribe: ChatSubscriber
|
|
42
33
|
send: ChatSender
|
|
34
|
+
announce: ChatAnnouncer
|
|
43
35
|
onMessage: ChatMessageSubscriber
|
|
44
36
|
onCommand: ChatCommandSubscriber
|
|
45
37
|
}
|
|
46
38
|
|
|
47
|
-
export async function createChat(
|
|
39
|
+
export default async function createChat(
|
|
48
40
|
authentication: Authentication,
|
|
49
|
-
|
|
41
|
+
eventsub?: TwitchEventSub,
|
|
50
42
|
): Promise<TwitchChat> {
|
|
51
|
-
|
|
43
|
+
eventsub ??= await createEventSub(authentication)
|
|
52
44
|
|
|
53
|
-
const
|
|
54
|
-
|
|
45
|
+
const send: ChatSender = async (message) => {
|
|
46
|
+
await sendChatMessage(authentication, message)
|
|
47
|
+
}
|
|
55
48
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
49
|
+
const announce: ChatAnnouncer = async (message, color) => {
|
|
50
|
+
await sendChatAnnouncement(authentication, message, color)
|
|
51
|
+
}
|
|
59
52
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
continue
|
|
66
|
-
}
|
|
53
|
+
const onMessage: ChatMessageSubscriber = (callback) => {
|
|
54
|
+
return eventsub.on(["channel.chat.message"], (payload) => {
|
|
55
|
+
callback(payload.event)
|
|
56
|
+
})
|
|
57
|
+
}
|
|
67
58
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
command.type === "JOIN" ||
|
|
71
|
-
command.type === "USERSTATE" ||
|
|
72
|
-
command.type === "HOSTTARGET" ||
|
|
73
|
-
command.type === "NOTICE"
|
|
74
|
-
) {
|
|
75
|
-
continue
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (command.type === "PING") {
|
|
79
|
-
socket.send(`PONG :${command.message}`)
|
|
80
|
-
continue
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (command.type === "CAP") {
|
|
84
|
-
socket.send(`PASS oauth:${authentication.accessToken}`)
|
|
85
|
-
socket.send(`NICK ${authentication.user.login}`)
|
|
86
|
-
continue
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (command.type === "RECONNECT") {
|
|
90
|
-
console.warn("The server is about to terminate for maintenance.")
|
|
91
|
-
continue
|
|
92
|
-
}
|
|
59
|
+
const onCommand: ChatCommandSubscriber = (name, ...args) => {
|
|
60
|
+
const pattern = typeof args[0] === "string" ? args[0] : undefined
|
|
93
61
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (command.type === "ROOMSTATE") {
|
|
100
|
-
resolve()
|
|
101
|
-
continue
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
pubsub.dispatch(command)
|
|
105
|
-
}
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
return promise.then(() => {
|
|
109
|
-
const listen: ChatListener = (callback) => {
|
|
110
|
-
return pubsub.subscribe((event) => {
|
|
111
|
-
callback(event)
|
|
112
|
-
})
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const subscribe: ChatSubscriber = (types, callback) => {
|
|
116
|
-
return pubsub.subscribe((event) => {
|
|
117
|
-
// @ts-expect-error: generic events are complicated
|
|
118
|
-
if (types.includes(event.type)) {
|
|
119
|
-
// @ts-expect-error: generic events are complicated
|
|
120
|
-
callback(event)
|
|
121
|
-
}
|
|
122
|
-
})
|
|
62
|
+
const callback = typeof args[0] === "function" ? args[0] : args[1]
|
|
63
|
+
if (!callback) {
|
|
64
|
+
throw new Error("onCommand: Missing callback.")
|
|
123
65
|
}
|
|
124
66
|
|
|
125
|
-
const
|
|
126
|
-
socket.send(`PRIVMSG #${authentication.user.login} :${message}`)
|
|
127
|
-
}
|
|
67
|
+
const regex = new RegExp(`^\\s*!([a-z0-9])(?:\\s+(.+))$`, "i")
|
|
128
68
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
callback(event)
|
|
133
|
-
}
|
|
134
|
-
})
|
|
135
|
-
}
|
|
69
|
+
return onMessage((payload) => {
|
|
70
|
+
const [command, text] =
|
|
71
|
+
payload.message.text.match(regex) ?? ([] as Array<string | undefined>)
|
|
136
72
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const callback = typeof args[0] === "function" ? args[0] : args[1]
|
|
140
|
-
if (!callback) {
|
|
141
|
-
throw new Error("onCommand: Missing callback.")
|
|
73
|
+
if (command !== name) {
|
|
74
|
+
return
|
|
142
75
|
}
|
|
143
76
|
|
|
144
|
-
|
|
145
|
-
if (event.type === "PRIVMSG-COMMAND") {
|
|
146
|
-
if (typeof name === "undefined" || event.command === name) {
|
|
147
|
-
callback(event)
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
})
|
|
151
|
-
}
|
|
77
|
+
const parameters = pattern ? undefined : text?.split(" ")
|
|
152
78
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
79
|
+
callback({
|
|
80
|
+
...payload,
|
|
81
|
+
message: {
|
|
82
|
+
command: "",
|
|
83
|
+
parameters,
|
|
84
|
+
...payload.message,
|
|
85
|
+
},
|
|
86
|
+
})
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
send,
|
|
92
|
+
announce,
|
|
93
|
+
onMessage,
|
|
94
|
+
onCommand,
|
|
95
|
+
}
|
|
161
96
|
}
|
package/src/chat/helpers.ts
CHANGED
|
@@ -1,36 +1,45 @@
|
|
|
1
1
|
interface ApplicableChatEvent {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
2
|
+
badges: Array<{
|
|
3
|
+
set_id: string
|
|
4
|
+
id: string
|
|
5
|
+
info: string
|
|
6
|
+
}>
|
|
8
7
|
}
|
|
9
8
|
|
|
10
|
-
export function isBroadcaster(event: ApplicableChatEvent): boolean
|
|
11
|
-
const broadcaster = event.
|
|
9
|
+
export function isBroadcaster(event: ApplicableChatEvent): boolean {
|
|
10
|
+
const broadcaster = !!event.badges.find((badge) => {
|
|
11
|
+
return badge.set_id === "broadcaster"
|
|
12
|
+
})
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
return !!broadcaster
|
|
14
|
+
return broadcaster
|
|
16
15
|
}
|
|
17
16
|
|
|
18
|
-
export function
|
|
19
|
-
const broadcaster = event.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return
|
|
17
|
+
export function isModerator(event: ApplicableChatEvent): boolean {
|
|
18
|
+
const broadcaster = !!event.badges.find((badge) => {
|
|
19
|
+
return badge.set_id === "broadcaster"
|
|
20
|
+
})
|
|
21
|
+
const moderator = !!event.badges.find((badge) => {
|
|
22
|
+
return badge.set_id === "moderator"
|
|
23
|
+
})
|
|
24
24
|
|
|
25
|
-
return broadcaster ||
|
|
25
|
+
return broadcaster || moderator
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
export function
|
|
29
|
-
const broadcaster = event.
|
|
30
|
-
|
|
28
|
+
export function isModeratorOnly(event: ApplicableChatEvent): boolean {
|
|
29
|
+
const broadcaster = !!event.badges.find((badge) => {
|
|
30
|
+
return badge.set_id === "broadcaster"
|
|
31
|
+
})
|
|
32
|
+
const moderator = !!event.badges.find((badge) => {
|
|
33
|
+
return badge.set_id === "moderator"
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
return !broadcaster && moderator
|
|
37
|
+
}
|
|
31
38
|
|
|
32
|
-
|
|
33
|
-
|
|
39
|
+
export function isSubscriber(event: ApplicableChatEvent): false | number {
|
|
40
|
+
const subscriber = event.badges.find((badge) => {
|
|
41
|
+
return badge.set_id === "subscriber"
|
|
42
|
+
})
|
|
34
43
|
|
|
35
|
-
return
|
|
44
|
+
return +(subscriber?.info ?? "0") || false
|
|
36
45
|
}
|
package/src/chat/index.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
TwitchChatEvent,
|
|
4
|
-
} from "./interfaces/index.js"
|
|
1
|
+
export { default } from "./chat.ts"
|
|
2
|
+
export * from "./chat.ts"
|
|
5
3
|
|
|
6
|
-
export * from "./
|
|
7
|
-
export * from "./helpers.
|
|
4
|
+
export * from "./pronouns.ts"
|
|
5
|
+
export * from "./helpers.ts"
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
type AllPronounsResponse = Array<{
|
|
2
|
+
name: string
|
|
3
|
+
display: string
|
|
4
|
+
}>
|
|
5
|
+
|
|
6
|
+
type UserPronounsResponse = Array<{
|
|
7
|
+
id: string
|
|
8
|
+
login: string
|
|
9
|
+
pronoun_id: string
|
|
10
|
+
}>
|
|
11
|
+
|
|
12
|
+
type Pronouns = {
|
|
13
|
+
subject: string
|
|
14
|
+
object: string
|
|
15
|
+
posessive: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const pronouns: Record<string, Pronouns> = {
|
|
19
|
+
hehim: {
|
|
20
|
+
subject: "he",
|
|
21
|
+
object: "him",
|
|
22
|
+
posessive: "his",
|
|
23
|
+
},
|
|
24
|
+
sheher: {
|
|
25
|
+
subject: "she",
|
|
26
|
+
object: "her",
|
|
27
|
+
posessive: "her",
|
|
28
|
+
},
|
|
29
|
+
theythem: {
|
|
30
|
+
subject: "they",
|
|
31
|
+
object: "them",
|
|
32
|
+
posessive: "their",
|
|
33
|
+
},
|
|
34
|
+
shethem: {
|
|
35
|
+
subject: "she",
|
|
36
|
+
object: "they",
|
|
37
|
+
posessive: "their",
|
|
38
|
+
},
|
|
39
|
+
hethem: {
|
|
40
|
+
subject: "he",
|
|
41
|
+
object: "they",
|
|
42
|
+
posessive: "their",
|
|
43
|
+
},
|
|
44
|
+
heshe: {
|
|
45
|
+
subject: "he",
|
|
46
|
+
object: "she",
|
|
47
|
+
posessive: "their",
|
|
48
|
+
},
|
|
49
|
+
xexem: {
|
|
50
|
+
subject: "xe",
|
|
51
|
+
object: "xem",
|
|
52
|
+
posessive: "xeir",
|
|
53
|
+
},
|
|
54
|
+
faefaer: {
|
|
55
|
+
subject: "fae",
|
|
56
|
+
object: "faer",
|
|
57
|
+
posessive: "faer",
|
|
58
|
+
},
|
|
59
|
+
vever: {
|
|
60
|
+
subject: "ve",
|
|
61
|
+
object: "ver",
|
|
62
|
+
posessive: "ver",
|
|
63
|
+
},
|
|
64
|
+
aeaer: {
|
|
65
|
+
subject: "ae",
|
|
66
|
+
object: "aer",
|
|
67
|
+
posessive: "aer",
|
|
68
|
+
},
|
|
69
|
+
ziehir: {
|
|
70
|
+
subject: "zie",
|
|
71
|
+
object: "hir",
|
|
72
|
+
posessive: "hir",
|
|
73
|
+
},
|
|
74
|
+
perper: {
|
|
75
|
+
subject: "per",
|
|
76
|
+
object: "per",
|
|
77
|
+
posessive: "per",
|
|
78
|
+
},
|
|
79
|
+
eem: {
|
|
80
|
+
subject: "e",
|
|
81
|
+
object: "em",
|
|
82
|
+
posessive: "eir",
|
|
83
|
+
},
|
|
84
|
+
itits: {
|
|
85
|
+
subject: "it",
|
|
86
|
+
object: "its",
|
|
87
|
+
posessive: "its",
|
|
88
|
+
},
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const cache: Partial<Record<string, keyof typeof pronouns>> = {}
|
|
92
|
+
|
|
93
|
+
export async function getAllPronouns(): Promise<AllPronounsResponse> {
|
|
94
|
+
const response = await fetch("https://pronouns.alejo.io/api/pronouns")
|
|
95
|
+
|
|
96
|
+
if (!response.ok) {
|
|
97
|
+
throw new Error(await response.text())
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const data = (await response.json()) as AllPronounsResponse
|
|
101
|
+
|
|
102
|
+
return data
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export async function getUserPronouns(
|
|
106
|
+
login: string,
|
|
107
|
+
): Promise<string | undefined> {
|
|
108
|
+
const response = await fetch(`https://pronouns.alejo.io/api/users/${login}`)
|
|
109
|
+
|
|
110
|
+
if (!response.ok) {
|
|
111
|
+
return undefined
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
const data = (await response.json()) as UserPronounsResponse
|
|
116
|
+
|
|
117
|
+
return data[0].pronoun_id
|
|
118
|
+
} catch {
|
|
119
|
+
return undefined
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export async function getPronouns(
|
|
124
|
+
login: string,
|
|
125
|
+
fallback: keyof typeof pronouns = "theythem",
|
|
126
|
+
): Promise<{
|
|
127
|
+
subject: string
|
|
128
|
+
object: string
|
|
129
|
+
}> {
|
|
130
|
+
if (!(login in cache)) {
|
|
131
|
+
try {
|
|
132
|
+
const id = await getUserPronouns(login)
|
|
133
|
+
cache[login] = id
|
|
134
|
+
} catch {
|
|
135
|
+
cache[login] = undefined
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const id = cache[login] ?? fallback
|
|
140
|
+
return pronouns[id]
|
|
141
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { type EventConfig, registerEvent } from "../events-helpers.ts"
|
|
2
|
+
|
|
3
|
+
declare module "../events-helpers.ts" {
|
|
4
|
+
interface EventConfigs {
|
|
5
|
+
"automod.message.hold": AutomodMessageHold
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** Automod Message Hold v2: When the user's message is caught by automod for review. Only public blocked terms trigger notifications, not private ones. */
|
|
10
|
+
type AutomodMessageHold = EventConfig<{
|
|
11
|
+
Type: "automod.message.hold"
|
|
12
|
+
Version: "2"
|
|
13
|
+
/** The conditions to listen for when the user's message is caught by automod for review. Only public blocked terms trigger notifications, not private ones. */
|
|
14
|
+
Condition: {
|
|
15
|
+
/** User ID of the broadcaster (channel). */
|
|
16
|
+
broadcaster_user_id: string
|
|
17
|
+
/** User ID of the moderator. */
|
|
18
|
+
moderator_user_id: string
|
|
19
|
+
}
|
|
20
|
+
/** The event fired when the user's message is caught by automod for review. Only public blocked terms trigger notifications, not private ones. */
|
|
21
|
+
Event: {
|
|
22
|
+
/** The ID of the broadcaster specified in the request. */
|
|
23
|
+
broadcaster_user_id: string
|
|
24
|
+
/** The login of the broadcaster specified in the request. */
|
|
25
|
+
broadcaster_user_login: string
|
|
26
|
+
/** The user name of the broadcaster specified in the request. */
|
|
27
|
+
broadcaster_user_name: string
|
|
28
|
+
/** The message sender's user ID. */
|
|
29
|
+
user_id: string
|
|
30
|
+
/** The message sender's login name. */
|
|
31
|
+
user_login: string
|
|
32
|
+
/** The message sender's display name. */
|
|
33
|
+
user_name: string
|
|
34
|
+
/** The ID of the message that was flagged by automod. */
|
|
35
|
+
message_id: string
|
|
36
|
+
/** The body of the message. */
|
|
37
|
+
message: {
|
|
38
|
+
/** The contents of the message caught by automod. */
|
|
39
|
+
text: string
|
|
40
|
+
/** Metadata surrounding the potential inappropriate fragments of the message. */
|
|
41
|
+
fragments: Array<{
|
|
42
|
+
/** Message text in a fragment. */
|
|
43
|
+
text: string
|
|
44
|
+
/** Metadata pertaining to the emote. */
|
|
45
|
+
emote?: {
|
|
46
|
+
/** An ID that uniquely identifies this emote. */
|
|
47
|
+
id: string
|
|
48
|
+
/** An ID that identifies the emote set that the emote belongs to. */
|
|
49
|
+
emote_set_id: string
|
|
50
|
+
}
|
|
51
|
+
/** Metadata pertaining to the cheermote. */
|
|
52
|
+
cheermote?: {
|
|
53
|
+
/** The name portion of the Cheermote string that you use in chat to cheer Bits. The full Cheermote string is the concatenation of {prefix} + {number of Bits}. */
|
|
54
|
+
prefix: string
|
|
55
|
+
/** The amount of Bits cheered. */
|
|
56
|
+
bits: number
|
|
57
|
+
/** The tier level of the cheermote. */
|
|
58
|
+
tier: number
|
|
59
|
+
}
|
|
60
|
+
}>
|
|
61
|
+
}
|
|
62
|
+
/** The category of the message. */
|
|
63
|
+
category: string
|
|
64
|
+
/** The level of severity. Measured between 1 to 4. */
|
|
65
|
+
level: number
|
|
66
|
+
/** The timestamp of when automod saved the message. */
|
|
67
|
+
held_at: string
|
|
68
|
+
}
|
|
69
|
+
}>
|
|
70
|
+
|
|
71
|
+
registerEvent("automod.message.hold", {
|
|
72
|
+
scopes: ["moderator:manage:automod"],
|
|
73
|
+
subscriber: (userId) => ({
|
|
74
|
+
type: "automod.message.hold",
|
|
75
|
+
version: "2",
|
|
76
|
+
condition: {
|
|
77
|
+
broadcaster_user_id: userId,
|
|
78
|
+
moderator_user_id: userId,
|
|
79
|
+
},
|
|
80
|
+
}),
|
|
81
|
+
})
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { type EventConfig, registerEvent } from "../events-helpers.ts"
|
|
2
|
+
|
|
3
|
+
declare module "../events-helpers.ts" {
|
|
4
|
+
interface EventConfigs {
|
|
5
|
+
"automod.message.update": AutomodMessageUpdate
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** Automod Message Update v2: When a message in the automod queue had its status changed. Only public blocked terms trigger notifications, not private ones. */
|
|
10
|
+
type AutomodMessageUpdate = EventConfig<{
|
|
11
|
+
Type: "automod.message.update"
|
|
12
|
+
Version: "2"
|
|
13
|
+
/** The conditions to listen for when a message in the automod queue had its status changed. Only public blocked terms trigger notifications, not private ones. */
|
|
14
|
+
Condition: {
|
|
15
|
+
/** User ID of the broadcaster (channel). Maximum:1. */
|
|
16
|
+
broadcaster_user_id: string
|
|
17
|
+
/** User ID of the moderator. */
|
|
18
|
+
moderator_user_id: string
|
|
19
|
+
}
|
|
20
|
+
/** The event fired when a message in the automod queue had its status changed. Only public blocked terms trigger notifications, not private ones. */
|
|
21
|
+
Event: {
|
|
22
|
+
/** The ID of the broadcaster specified in the request. */
|
|
23
|
+
broadcaster_user_id: string
|
|
24
|
+
/** The login of the broadcaster specified in the request. */
|
|
25
|
+
broadcaster_user_login: string
|
|
26
|
+
/** The user name of the broadcaster specified in the request. */
|
|
27
|
+
broadcaster_user_name: string
|
|
28
|
+
/** The message sender's user ID. */
|
|
29
|
+
user_id: string
|
|
30
|
+
/** The message sender's login name. */
|
|
31
|
+
user_login: string
|
|
32
|
+
/** The message sender's display name. */
|
|
33
|
+
user_name: string
|
|
34
|
+
/** The ID of the moderator. */
|
|
35
|
+
moderator_user_id: string
|
|
36
|
+
/** TThe moderator's user name. */
|
|
37
|
+
moderator_user_name: string
|
|
38
|
+
/** The login of the moderator. */
|
|
39
|
+
moderator_user_login: string
|
|
40
|
+
/** The ID of the message that was flagged by automod. */
|
|
41
|
+
message_id: string
|
|
42
|
+
/** The body of the message. */
|
|
43
|
+
message: {
|
|
44
|
+
/** The contents of the message caught by automod. */
|
|
45
|
+
text: string
|
|
46
|
+
/** Metadata surrounding the potential inappropriate fragments of the message. */
|
|
47
|
+
fragments: Array<{
|
|
48
|
+
/** Message text in a fragment. */
|
|
49
|
+
text: string
|
|
50
|
+
/** Metadata pertaining to the emote. */
|
|
51
|
+
emote?: {
|
|
52
|
+
/** An ID that uniquely identifies this emote. */
|
|
53
|
+
id: string
|
|
54
|
+
/** An ID that identifies the emote set that the emote belongs to. */
|
|
55
|
+
emote_set_id: string
|
|
56
|
+
}
|
|
57
|
+
/** Metadata pertaining to the cheermote. */
|
|
58
|
+
cheermote?: {
|
|
59
|
+
/** The name portion of the Cheermote string that you use in chat to cheer Bits. The full Cheermote string is the concatenation of {prefix} + {number of Bits}. */
|
|
60
|
+
prefix: string
|
|
61
|
+
/** The amount of Bits cheered. */
|
|
62
|
+
bits: number
|
|
63
|
+
/** The tier level of the cheermote. */
|
|
64
|
+
tier: number
|
|
65
|
+
}
|
|
66
|
+
}>
|
|
67
|
+
}
|
|
68
|
+
/** The category of the message. */
|
|
69
|
+
category: string
|
|
70
|
+
/** The level of severity. Measured between 1 to 4. */
|
|
71
|
+
level: number
|
|
72
|
+
/**
|
|
73
|
+
* The message's status. Possible values are:
|
|
74
|
+
* - Approved
|
|
75
|
+
* - Denied
|
|
76
|
+
* - Expired
|
|
77
|
+
*/
|
|
78
|
+
status: string
|
|
79
|
+
/** The timestamp of when automod saved the message. */
|
|
80
|
+
held_at: string
|
|
81
|
+
}
|
|
82
|
+
}>
|
|
83
|
+
|
|
84
|
+
registerEvent("automod.message.update", {
|
|
85
|
+
scopes: ["moderator:manage:automod"],
|
|
86
|
+
subscriber: (userId) => ({
|
|
87
|
+
type: "automod.message.update",
|
|
88
|
+
version: "2",
|
|
89
|
+
condition: {
|
|
90
|
+
broadcaster_user_id: userId,
|
|
91
|
+
moderator_user_id: userId,
|
|
92
|
+
},
|
|
93
|
+
}),
|
|
94
|
+
})
|