multichat-ts 0.0.82 → 0.0.84
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/worker/index.d.ts +144 -0
- package/dist/worker/index.js +2 -0
- package/dist/worker/kick.d.ts +192 -0
- package/dist/worker/kick.js +182 -0
- package/dist/worker/twitch.d.ts +73 -0
- package/dist/worker/twitch.js +425 -0
- package/package.json +3 -2
- package/src/worker/index.ts +168 -0
- package/src/worker/kick.ts +417 -0
- package/src/worker/twitch.ts +540 -0
- /package/dist/{index.d.ts → default/index.d.ts} +0 -0
- /package/dist/{index.js → default/index.js} +0 -0
- /package/dist/{kick.d.ts → default/kick.d.ts} +0 -0
- /package/dist/{kick.js → default/kick.js} +0 -0
- /package/dist/{twitch.d.ts → default/twitch.d.ts} +0 -0
- /package/dist/{twitch.js → default/twitch.js} +0 -0
- /package/src/{index.ts → default/index.ts} +0 -0
- /package/src/{kick.ts → default/kick.ts} +0 -0
- /package/src/{twitch.ts → default/twitch.ts} +0 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
export * from './kick.js';
|
|
2
|
+
export * from './twitch.js';
|
|
3
|
+
export type Message = {
|
|
4
|
+
body: BodyComponent[];
|
|
5
|
+
channel: {
|
|
6
|
+
room_id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
};
|
|
9
|
+
id: string;
|
|
10
|
+
raw_text: string;
|
|
11
|
+
timestamp_sent: number;
|
|
12
|
+
user: {
|
|
13
|
+
badges: Badge[];
|
|
14
|
+
color: string;
|
|
15
|
+
id: string;
|
|
16
|
+
username: string;
|
|
17
|
+
display_name: string;
|
|
18
|
+
roles: {
|
|
19
|
+
[role in 'vip' | 'moderator' | 'turbo' | 'admin' | 'global_moderator' | 'staff']?: boolean;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
export type ClearMessages = {
|
|
24
|
+
channel: {
|
|
25
|
+
room_id: string;
|
|
26
|
+
name: string;
|
|
27
|
+
};
|
|
28
|
+
user?: {
|
|
29
|
+
id: string;
|
|
30
|
+
username: string;
|
|
31
|
+
};
|
|
32
|
+
timeout_duration_seconds?: number | undefined;
|
|
33
|
+
timestamp_sent: number;
|
|
34
|
+
};
|
|
35
|
+
export type DeleteMessage = {
|
|
36
|
+
channel: {
|
|
37
|
+
room_id?: string;
|
|
38
|
+
name: string;
|
|
39
|
+
};
|
|
40
|
+
user?: {
|
|
41
|
+
username: string;
|
|
42
|
+
};
|
|
43
|
+
id: string;
|
|
44
|
+
raw_text: string;
|
|
45
|
+
timestamp_sent: number;
|
|
46
|
+
};
|
|
47
|
+
type EventData = {
|
|
48
|
+
subscription: {
|
|
49
|
+
months: number;
|
|
50
|
+
streak?: number;
|
|
51
|
+
subscription_plan: {
|
|
52
|
+
type: 'prime' | 1000 | 2000 | 3000;
|
|
53
|
+
name: string;
|
|
54
|
+
};
|
|
55
|
+
gift_upgrade?: {
|
|
56
|
+
gift_total: number;
|
|
57
|
+
promo_name: string;
|
|
58
|
+
sender: {
|
|
59
|
+
username: string;
|
|
60
|
+
display_name: string;
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
gift: {
|
|
65
|
+
months: number;
|
|
66
|
+
recipient: {
|
|
67
|
+
id: string;
|
|
68
|
+
username: string;
|
|
69
|
+
display_name: string;
|
|
70
|
+
};
|
|
71
|
+
subscription_plan: {
|
|
72
|
+
type: 'prime' | 1000 | 2000 | 3000;
|
|
73
|
+
name: string;
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
raid: {
|
|
77
|
+
sender: {
|
|
78
|
+
username: string;
|
|
79
|
+
display_name: string;
|
|
80
|
+
viewer_count: number;
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
export type Event = {
|
|
85
|
+
[E in keyof EventData]: {
|
|
86
|
+
type: E;
|
|
87
|
+
body: BodyComponent[];
|
|
88
|
+
channel: {
|
|
89
|
+
room_id: string;
|
|
90
|
+
name: string;
|
|
91
|
+
};
|
|
92
|
+
id: string;
|
|
93
|
+
raw_text: string;
|
|
94
|
+
system_message: string;
|
|
95
|
+
timestamp_sent: number;
|
|
96
|
+
user: {
|
|
97
|
+
badges: Badge[];
|
|
98
|
+
color: string;
|
|
99
|
+
id: string;
|
|
100
|
+
username: string;
|
|
101
|
+
display_name: string;
|
|
102
|
+
roles: {
|
|
103
|
+
[role in 'moderator' | 'subscriber' | 'turbo' | 'admin' | 'global_moderator' | 'staff']?: boolean;
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
data: EventData[E];
|
|
107
|
+
};
|
|
108
|
+
}[keyof EventData];
|
|
109
|
+
export type BodyComponentEmote = {
|
|
110
|
+
end_exclusive: number;
|
|
111
|
+
start_inclusive: number;
|
|
112
|
+
type: 'emote';
|
|
113
|
+
url: string;
|
|
114
|
+
};
|
|
115
|
+
export type BodyComponent = {
|
|
116
|
+
end_exclusive: number;
|
|
117
|
+
label: string;
|
|
118
|
+
start_inclusive: number;
|
|
119
|
+
type: 'link';
|
|
120
|
+
url: string;
|
|
121
|
+
} | {
|
|
122
|
+
end_exclusive: number;
|
|
123
|
+
start_inclusive: number;
|
|
124
|
+
text: string;
|
|
125
|
+
type: 'text';
|
|
126
|
+
} | BodyComponentEmote;
|
|
127
|
+
type Badge = {
|
|
128
|
+
info?: string | undefined;
|
|
129
|
+
set_id: string;
|
|
130
|
+
url: string;
|
|
131
|
+
};
|
|
132
|
+
export type BadgeURLsByNameOrCount = {
|
|
133
|
+
[badge_name: string]: string | {
|
|
134
|
+
[badge_count: number]: string;
|
|
135
|
+
};
|
|
136
|
+
};
|
|
137
|
+
export type BadgeURLsBySetIDOrSetIDAndVersion = {
|
|
138
|
+
[set_id: string]: {
|
|
139
|
+
[version: string]: string;
|
|
140
|
+
} | string;
|
|
141
|
+
};
|
|
142
|
+
export type EmoteURLsByName = {
|
|
143
|
+
[emote_name: string]: string;
|
|
144
|
+
};
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import Pusher from 'pusher-js/worker';
|
|
2
|
+
import { type BadgeURLsByNameOrCount, type EmoteURLsByName, type Message } from './index.js';
|
|
3
|
+
type EventCallbackFunctions = {
|
|
4
|
+
message: (message: Message) => unknown;
|
|
5
|
+
subscription: (data: ChatSubscriptionEvent) => unknown;
|
|
6
|
+
gifted: (data: ChatGiftedEvent) => unknown;
|
|
7
|
+
raw_message: (message: ChatMessageEvent) => unknown;
|
|
8
|
+
};
|
|
9
|
+
type EventNames = keyof EventCallbackFunctions;
|
|
10
|
+
export declare class KickPusher {
|
|
11
|
+
kick_pusher_key: string;
|
|
12
|
+
channel_name?: string;
|
|
13
|
+
private assets;
|
|
14
|
+
private public_listeners;
|
|
15
|
+
socket?: Pusher;
|
|
16
|
+
isConnected: boolean;
|
|
17
|
+
setBadges(badges: BadgeURLsByNameOrCount): void;
|
|
18
|
+
setExternalEmotes(external_emotes: EmoteURLsByName): void;
|
|
19
|
+
getStoredBadges(): BadgeURLsByNameOrCount;
|
|
20
|
+
getStoredExternalEmotes(): EmoteURLsByName;
|
|
21
|
+
connect(channel?: {
|
|
22
|
+
channelName?: string;
|
|
23
|
+
}): Promise<void>;
|
|
24
|
+
disconnect(): void;
|
|
25
|
+
on<EventName extends EventNames>(event_name: EventName, callback_fn: EventCallbackFunctions[EventName]): void;
|
|
26
|
+
private onSubscriptionSuccess;
|
|
27
|
+
private onChatSubscription;
|
|
28
|
+
private onChatGifted;
|
|
29
|
+
private onChatMessage;
|
|
30
|
+
}
|
|
31
|
+
export interface GetChannelResponse {
|
|
32
|
+
id: number;
|
|
33
|
+
user_id: number;
|
|
34
|
+
slug: string;
|
|
35
|
+
is_banned: boolean;
|
|
36
|
+
playback_url?: string;
|
|
37
|
+
vod_enabled: boolean;
|
|
38
|
+
subscription_enabled: boolean;
|
|
39
|
+
followers_count: number;
|
|
40
|
+
following?: boolean;
|
|
41
|
+
subscription?: unknown;
|
|
42
|
+
subscriber_badges: Array<{
|
|
43
|
+
id: number;
|
|
44
|
+
channel_id: number;
|
|
45
|
+
months: number;
|
|
46
|
+
badge_image: {
|
|
47
|
+
srcset: string;
|
|
48
|
+
src: string;
|
|
49
|
+
};
|
|
50
|
+
}>;
|
|
51
|
+
banner_image?: {
|
|
52
|
+
url: string;
|
|
53
|
+
};
|
|
54
|
+
livestream?: ChannelLivestream;
|
|
55
|
+
role?: unknown;
|
|
56
|
+
muted: boolean;
|
|
57
|
+
follower_badges: unknown[];
|
|
58
|
+
offline_banner_image: unknown;
|
|
59
|
+
verified: boolean;
|
|
60
|
+
recent_categories: Array<{
|
|
61
|
+
id: number;
|
|
62
|
+
category_id: number;
|
|
63
|
+
name: string;
|
|
64
|
+
slug: string;
|
|
65
|
+
tags: string[];
|
|
66
|
+
description?: string;
|
|
67
|
+
deleted_at: unknown;
|
|
68
|
+
viewers: number;
|
|
69
|
+
banner: {
|
|
70
|
+
responsive: string;
|
|
71
|
+
url: string;
|
|
72
|
+
};
|
|
73
|
+
category: {
|
|
74
|
+
id: number;
|
|
75
|
+
name: string;
|
|
76
|
+
slug: string;
|
|
77
|
+
icon: string;
|
|
78
|
+
};
|
|
79
|
+
}>;
|
|
80
|
+
can_host: boolean;
|
|
81
|
+
user: {
|
|
82
|
+
id: number;
|
|
83
|
+
username: string;
|
|
84
|
+
agreed_to_terms: true;
|
|
85
|
+
email_verified_at: Date;
|
|
86
|
+
bio?: string;
|
|
87
|
+
country?: string;
|
|
88
|
+
state?: string;
|
|
89
|
+
city?: string;
|
|
90
|
+
instagram?: string;
|
|
91
|
+
twitter?: string;
|
|
92
|
+
youtube?: string;
|
|
93
|
+
discord?: string;
|
|
94
|
+
tiktok?: string;
|
|
95
|
+
facebook?: string;
|
|
96
|
+
profile_pic?: string;
|
|
97
|
+
};
|
|
98
|
+
chatroom: ChannelChatroom;
|
|
99
|
+
ascending_links?: Array<{
|
|
100
|
+
id: number;
|
|
101
|
+
channel_id: number;
|
|
102
|
+
description: string;
|
|
103
|
+
link: string;
|
|
104
|
+
created_at: Date;
|
|
105
|
+
updated_at: Date;
|
|
106
|
+
order: number;
|
|
107
|
+
title: string;
|
|
108
|
+
}>;
|
|
109
|
+
}
|
|
110
|
+
export interface ChannelLivestream {
|
|
111
|
+
id: number;
|
|
112
|
+
slug: string;
|
|
113
|
+
channel_id: number;
|
|
114
|
+
created_at: Date;
|
|
115
|
+
session_title: string;
|
|
116
|
+
is_live: boolean;
|
|
117
|
+
risk_level_id: unknown;
|
|
118
|
+
start_time: Date;
|
|
119
|
+
source: unknown;
|
|
120
|
+
twitch_channel: unknown;
|
|
121
|
+
duration: number;
|
|
122
|
+
language: string;
|
|
123
|
+
is_mature: boolean;
|
|
124
|
+
viewer_count: number;
|
|
125
|
+
thumbnail: {
|
|
126
|
+
url: string;
|
|
127
|
+
};
|
|
128
|
+
categories: Array<{
|
|
129
|
+
id: number;
|
|
130
|
+
category_id: number;
|
|
131
|
+
name: string;
|
|
132
|
+
slug: string;
|
|
133
|
+
tags: string[];
|
|
134
|
+
description?: string;
|
|
135
|
+
deleted_at: unknown;
|
|
136
|
+
viewers: number;
|
|
137
|
+
category: {
|
|
138
|
+
id: number;
|
|
139
|
+
name: string;
|
|
140
|
+
slug: string;
|
|
141
|
+
icon: string;
|
|
142
|
+
};
|
|
143
|
+
}>;
|
|
144
|
+
tags: unknown[];
|
|
145
|
+
}
|
|
146
|
+
export interface ChannelChatroom {
|
|
147
|
+
id: number;
|
|
148
|
+
chatable_type: string;
|
|
149
|
+
channel_id: string;
|
|
150
|
+
created_at: Date;
|
|
151
|
+
updated_at: Date;
|
|
152
|
+
chat_mode_old: string;
|
|
153
|
+
chat_mode: string;
|
|
154
|
+
slow_mode: boolean;
|
|
155
|
+
chatable_id: number;
|
|
156
|
+
followers_mode: boolean;
|
|
157
|
+
subscribers_mode: boolean;
|
|
158
|
+
emotes_mode: boolean;
|
|
159
|
+
message_interval: number;
|
|
160
|
+
following_min_duration: number;
|
|
161
|
+
}
|
|
162
|
+
export interface ChatMessageEvent {
|
|
163
|
+
id: string;
|
|
164
|
+
chatroom_id: number;
|
|
165
|
+
content: string;
|
|
166
|
+
type: string;
|
|
167
|
+
created_at: string;
|
|
168
|
+
sender: {
|
|
169
|
+
id: number;
|
|
170
|
+
username: string;
|
|
171
|
+
slug?: string;
|
|
172
|
+
identity: {
|
|
173
|
+
color: string;
|
|
174
|
+
badges: Array<{
|
|
175
|
+
type: string;
|
|
176
|
+
text: string;
|
|
177
|
+
count?: number;
|
|
178
|
+
}>;
|
|
179
|
+
};
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
export interface ChatSubscriptionEvent {
|
|
183
|
+
chatroom_id: string;
|
|
184
|
+
username: string;
|
|
185
|
+
months: number;
|
|
186
|
+
}
|
|
187
|
+
export interface ChatGiftedEvent {
|
|
188
|
+
chatroom_id: string;
|
|
189
|
+
gifted_usernames: string[];
|
|
190
|
+
gifter_username: string;
|
|
191
|
+
}
|
|
192
|
+
export {};
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import Pusher from 'pusher-js/worker';
|
|
2
|
+
const DEFAULT_KICK_PUSHER_KEY = '32cbd69e4b950bf97679';
|
|
3
|
+
export class KickPusher {
|
|
4
|
+
kick_pusher_key = DEFAULT_KICK_PUSHER_KEY;
|
|
5
|
+
channel_name;
|
|
6
|
+
assets = {
|
|
7
|
+
external_emotes: {},
|
|
8
|
+
badges: {
|
|
9
|
+
founder: '/svgs/badges/default-kick/founder.svg',
|
|
10
|
+
moderator: '/svgs/badges/default-kick/moderator.svg',
|
|
11
|
+
og: '/svgs/badges/default-kick/og.svg',
|
|
12
|
+
sub_gifter: {
|
|
13
|
+
1: '/svgs/badges/default-kick/sub-gifter-blue.svg',
|
|
14
|
+
25: '/svgs/badges/default-kick/sub-gifter-purple.svg',
|
|
15
|
+
50: '/svgs/badges/default-kick/sub-gifter-red.svg',
|
|
16
|
+
100: '/svgs/badges/default-kick/sub-gifter-yellow.svg',
|
|
17
|
+
200: '/svgs/badges/default-kick/sub-gifter-green.svg',
|
|
18
|
+
},
|
|
19
|
+
verified: '/svgs/badges/default-kick/verified.svg',
|
|
20
|
+
vip: '/svgs/badges/default-kick/vip.svg',
|
|
21
|
+
broadcaster: '/svgs/badges/default-kick/broadcaster.svg',
|
|
22
|
+
staff: '/svgs/badges/default-kick/staff.svg',
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
public_listeners = {};
|
|
26
|
+
socket;
|
|
27
|
+
isConnected = false;
|
|
28
|
+
setBadges(badges) {
|
|
29
|
+
this.assets.badges = { ...this.assets.badges, ...badges };
|
|
30
|
+
}
|
|
31
|
+
setExternalEmotes(external_emotes) {
|
|
32
|
+
this.assets.external_emotes = { ...this.assets.external_emotes, ...external_emotes };
|
|
33
|
+
}
|
|
34
|
+
getStoredBadges() {
|
|
35
|
+
return this.assets.badges;
|
|
36
|
+
}
|
|
37
|
+
getStoredExternalEmotes() {
|
|
38
|
+
return this.assets.external_emotes;
|
|
39
|
+
}
|
|
40
|
+
async connect(channel) {
|
|
41
|
+
if (channel?.channelName)
|
|
42
|
+
this.channel_name = channel.channelName;
|
|
43
|
+
if (!this.channel_name)
|
|
44
|
+
return console.error('channel_name not specified');
|
|
45
|
+
console.log(`connecting to ${this.channel_name}...`);
|
|
46
|
+
const channel_response = await fetch(`https://kick.com/api/v2/channels/${this.channel_name}`, {
|
|
47
|
+
headers: {
|
|
48
|
+
accept: 'aplication/json',
|
|
49
|
+
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
|
|
50
|
+
},
|
|
51
|
+
})
|
|
52
|
+
.then((res) => res.json())
|
|
53
|
+
.then((json) => json);
|
|
54
|
+
if (!channel_response)
|
|
55
|
+
return console.error('Failed to connect to Kick.com chat');
|
|
56
|
+
channel_response.subscriber_badges.forEach((subscriber_badge) => {
|
|
57
|
+
this.assets.badges['subscriber'] = {
|
|
58
|
+
...(this.assets.badges['subscriber'] ?? {}),
|
|
59
|
+
[subscriber_badge.months]: subscriber_badge.badge_image.src,
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
this.disconnect();
|
|
63
|
+
this.socket = new Pusher(this.kick_pusher_key, {
|
|
64
|
+
cluster: 'us2',
|
|
65
|
+
});
|
|
66
|
+
this.socket
|
|
67
|
+
.subscribe(`chatrooms.${channel_response.chatroom.id}.v2`)
|
|
68
|
+
.bind('pusher:subscription_succeeded', () => this.onSubscriptionSuccess())
|
|
69
|
+
.bind('App\\Events\\ChatMessageEvent', (data) => this.onChatMessage(data))
|
|
70
|
+
.bind('App\\Events\\SubscriptionEvent', (data) => this.onChatSubscription(data))
|
|
71
|
+
.bind('App\\Events\\GiftedSubscriptionsEvent', (data) => this.onChatGifted(data));
|
|
72
|
+
}
|
|
73
|
+
disconnect() {
|
|
74
|
+
this.socket?.disconnect();
|
|
75
|
+
this.socket?.unbind_all();
|
|
76
|
+
}
|
|
77
|
+
on(event_name, callback_fn) {
|
|
78
|
+
this.public_listeners[event_name] = callback_fn;
|
|
79
|
+
}
|
|
80
|
+
onSubscriptionSuccess() {
|
|
81
|
+
console.log(`Connected to Kick Pusher (${this.channel_name})`);
|
|
82
|
+
}
|
|
83
|
+
onChatSubscription(data) {
|
|
84
|
+
this.public_listeners.subscription?.(data);
|
|
85
|
+
}
|
|
86
|
+
onChatGifted(data) {
|
|
87
|
+
this.public_listeners.gifted?.(data);
|
|
88
|
+
}
|
|
89
|
+
onChatMessage(data) {
|
|
90
|
+
this.public_listeners.raw_message?.(data);
|
|
91
|
+
const text = data.content;
|
|
92
|
+
const emote_matches = [...data.content.matchAll(/\[emote:\d+:[a-zA-Z0-9]*\]/g)];
|
|
93
|
+
console.log(emote_matches);
|
|
94
|
+
const body = [];
|
|
95
|
+
emote_matches.forEach((match) => {
|
|
96
|
+
const emote_string = match[0];
|
|
97
|
+
const emote_parts = emote_string.slice(1, emote_string.length - 1).split(':');
|
|
98
|
+
const emote_id = emote_parts[1];
|
|
99
|
+
if (!emote_id)
|
|
100
|
+
return;
|
|
101
|
+
console.log(emote_id);
|
|
102
|
+
body.push({
|
|
103
|
+
type: 'emote',
|
|
104
|
+
start_inclusive: match.index,
|
|
105
|
+
end_exclusive: match.index + emote_string.length,
|
|
106
|
+
url: `https://files.kick.com/emotes/${emote_id}/fullsize`,
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
body.sort((a, b) => a.start_inclusive - b.start_inclusive);
|
|
110
|
+
const old_body_length = body.length;
|
|
111
|
+
if (old_body_length > 0) {
|
|
112
|
+
body.forEach((segment, index) => {
|
|
113
|
+
const previous_segment = body[index - 1];
|
|
114
|
+
const text_start_inclusive = previous_segment?.end_exclusive !== undefined ? previous_segment.end_exclusive + 1 : 0;
|
|
115
|
+
const text_end_exclusive = Math.max(0, segment.start_inclusive);
|
|
116
|
+
if (text_end_exclusive - text_start_inclusive > 0) {
|
|
117
|
+
body.push({
|
|
118
|
+
type: 'text',
|
|
119
|
+
text: text.slice(text_start_inclusive, text_end_exclusive),
|
|
120
|
+
start_inclusive: text_start_inclusive,
|
|
121
|
+
end_exclusive: text_end_exclusive,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
if (index === old_body_length - 1 && segment.end_exclusive < text.length - 1) {
|
|
125
|
+
body.push({
|
|
126
|
+
type: 'text',
|
|
127
|
+
text: text.slice(segment.end_exclusive),
|
|
128
|
+
start_inclusive: segment.end_exclusive,
|
|
129
|
+
end_exclusive: text.length,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
body.push({
|
|
136
|
+
type: 'text',
|
|
137
|
+
text,
|
|
138
|
+
start_inclusive: 0,
|
|
139
|
+
end_exclusive: text.length,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
body.sort((a, b) => a.start_inclusive - b.start_inclusive);
|
|
143
|
+
this.public_listeners.message?.({
|
|
144
|
+
id: data.id,
|
|
145
|
+
user: {
|
|
146
|
+
id: `${data.sender.id}`,
|
|
147
|
+
username: data.sender.slug ?? data.sender.username.toLowerCase(),
|
|
148
|
+
display_name: data.sender.username,
|
|
149
|
+
roles: {},
|
|
150
|
+
color: data.sender.identity.color,
|
|
151
|
+
badges: data.sender.identity.badges.flatMap((badge) => {
|
|
152
|
+
let badge_url = undefined;
|
|
153
|
+
const badge_url_or_counts = this.assets.badges[badge.type];
|
|
154
|
+
const badge_count = badge.count;
|
|
155
|
+
if (typeof badge_url_or_counts === 'string')
|
|
156
|
+
badge_url = badge_url_or_counts;
|
|
157
|
+
else if (typeof badge_url_or_counts === 'object' && badge_count !== undefined) {
|
|
158
|
+
const badge_entry_by_count = Object.entries(badge_url_or_counts)
|
|
159
|
+
.sort(([a_min_count], [b_min_count]) => Number(a_min_count) - Number(b_min_count))
|
|
160
|
+
.find(([min_count]) => badge_count >= Number(min_count));
|
|
161
|
+
if (badge_entry_by_count)
|
|
162
|
+
badge_url = badge_entry_by_count[1];
|
|
163
|
+
}
|
|
164
|
+
if (!badge_url)
|
|
165
|
+
return [];
|
|
166
|
+
return {
|
|
167
|
+
set_id: badge.type,
|
|
168
|
+
url: badge_url,
|
|
169
|
+
info: String(badge.count),
|
|
170
|
+
};
|
|
171
|
+
}),
|
|
172
|
+
},
|
|
173
|
+
body,
|
|
174
|
+
channel: {
|
|
175
|
+
room_id: String(data.chatroom_id),
|
|
176
|
+
name: this.channel_name ?? 'unknown',
|
|
177
|
+
},
|
|
178
|
+
raw_text: data.content,
|
|
179
|
+
timestamp_sent: Date.parse(data.created_at),
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { WebSocket } from 'partysocket';
|
|
2
|
+
import { type ClearMessages, type DeleteMessage, type Message, type Event, type EmoteURLsByName, type BadgeURLsBySetIDOrSetIDAndVersion } from './index.js';
|
|
3
|
+
type EventCallbackFunctions = {
|
|
4
|
+
message: (message: Message) => unknown;
|
|
5
|
+
clear_messages: (data: ClearMessages) => unknown;
|
|
6
|
+
delete_message: (data: DeleteMessage) => unknown;
|
|
7
|
+
event: (event: Event) => unknown;
|
|
8
|
+
raw_message: (message: IRC_Message) => unknown;
|
|
9
|
+
};
|
|
10
|
+
type EventNames = keyof EventCallbackFunctions;
|
|
11
|
+
export declare class TwitchIRC {
|
|
12
|
+
channel_name?: string;
|
|
13
|
+
private assets;
|
|
14
|
+
latency: number;
|
|
15
|
+
private ping;
|
|
16
|
+
private public_listeners;
|
|
17
|
+
socket?: WebSocket;
|
|
18
|
+
ws?: WebSocket | undefined;
|
|
19
|
+
constructor(ws?: WebSocket);
|
|
20
|
+
setBadges(badges: BadgeURLsBySetIDOrSetIDAndVersion): void;
|
|
21
|
+
setExternalEmotes(external_emotes: EmoteURLsByName): void;
|
|
22
|
+
getStoredBadges(): BadgeURLsBySetIDOrSetIDAndVersion;
|
|
23
|
+
getStoredExternalEmotes(): EmoteURLsByName;
|
|
24
|
+
connect(channel?: {
|
|
25
|
+
channelName?: string;
|
|
26
|
+
}): void;
|
|
27
|
+
disconnect(): void;
|
|
28
|
+
on<EventName extends EventNames>(event_name: EventName, callback_fn: EventCallbackFunctions[EventName]): void;
|
|
29
|
+
isConnected(): this is {
|
|
30
|
+
socket: {
|
|
31
|
+
readyState: typeof WebSocket.OPEN;
|
|
32
|
+
} & WebSocket;
|
|
33
|
+
};
|
|
34
|
+
private onOpen;
|
|
35
|
+
private onClose;
|
|
36
|
+
private sendPing;
|
|
37
|
+
private send;
|
|
38
|
+
private onMessage;
|
|
39
|
+
}
|
|
40
|
+
type IRC_Message = {
|
|
41
|
+
[C in CommandType]: {
|
|
42
|
+
channel: string;
|
|
43
|
+
command: C;
|
|
44
|
+
params: string[];
|
|
45
|
+
source: RawSource | undefined;
|
|
46
|
+
tags: SpecificRawTags<C> | undefined;
|
|
47
|
+
};
|
|
48
|
+
}[CommandType];
|
|
49
|
+
type RAW_TAGS = typeof RAW_TAGS;
|
|
50
|
+
type CommandType = keyof RAW_TAGS;
|
|
51
|
+
type SpecificRawTags<Command extends CommandType> = Record<RAW_TAGS[Command][number], string | undefined>;
|
|
52
|
+
type RawSource = {
|
|
53
|
+
host: string;
|
|
54
|
+
nick?: string | undefined;
|
|
55
|
+
user?: string | undefined;
|
|
56
|
+
};
|
|
57
|
+
declare const RAW_TAGS: {
|
|
58
|
+
readonly CLEARCHAT: readonly ["ban-duration", "room-id", "target-user-id", "tmi-sent-ts"];
|
|
59
|
+
readonly CLEARMSG: readonly ["login", "room-id", "target-msg-id", "tmi-sent-ts"];
|
|
60
|
+
readonly GLOBALUSERSTATE: readonly ["badge-info", "badges", "color", "display-name", "emote-sets", "turbo", "user-id", "user-type"];
|
|
61
|
+
readonly HOSTTARGET: readonly [];
|
|
62
|
+
readonly NOTICE: readonly ["msg-id", "target-user-id"];
|
|
63
|
+
readonly PART: readonly [];
|
|
64
|
+
readonly PING: readonly [];
|
|
65
|
+
readonly PONG: readonly [];
|
|
66
|
+
readonly PRIVMSG: readonly ["badge-info", "badges", "bits", "color", "display-name", "emotes", "emote-only", "id", "mod", "custom-reward-id", "reply-thread-parent-display-name", "reply-thread-parent-user-id", "pinned-chat-paid-amount", "pinned-chat-paid-currency", "pinned-chat-paid-exponent", "pinned-chat-paid-level", "pinned-chat-paid-is-system-message", "reply-parent-msg-id", "reply-parent-user-id", "reply-parent-user-login", "reply-parent-display-name", "reply-parent-msg-body", "reply-thread-parent-msg-id", "reply-thread-parent-user-login", "room-id", "subscriber", "tmi-sent-ts", "turbo", "user-id", "user-type", "vip", "client-nonce", "first-msg", "flags", "returning-chatter"];
|
|
67
|
+
readonly RECONNECT: readonly [];
|
|
68
|
+
readonly ROOMSTATE: readonly ["emote-only", "followers-only", "r9k", "room-id", "slow", "subs-only"];
|
|
69
|
+
readonly USERNOTICE: readonly ["badge-info", "badges", "color", "display-name", "emotes", "id", "login", "mod", "msg-id", "room-id", "subscriber", "system-msg", "tmi-sent-ts", "turbo", "user-id", "user-type", "vip", "flags", "msg-param-cumulative-months", "msg-param-displayName", "msg-param-login", "msg-param-multimonth-duration", "msg-param-multimonth-tenure", "msg-param-was-gifted=false", "msg-param-months", "msg-param-promo-gift-total", "msg-param-promo-name", "msg-param-recipient-display-name", "msg-param-recipient-id", "msg-param-recipient-user-name", "msg-param-sender-login", "msg-param-sender-name", "msg-param-should-share-streak", "msg-param-streak-months", "msg-param-sub-plan", "msg-param-sub-plan-name", "msg-param-viewerCount", "msg-param-ritual-name", "msg-param-threshold", "msg-param-gift-months", "msg-param-was-gifted", "msg-param-community-gift-id", "msg-param-mass-gift-count", "msg-param-origin-id"];
|
|
70
|
+
readonly USERSTATE: readonly ["badge-info", "badges", "color", "display-name", "emote-sets", "id", "mod", "subscriber", "turbo", "user-type"];
|
|
71
|
+
readonly WHISPER: readonly ["badges", "color", "display-name", "emotes", "message-id", "thread-id", "turbo", "user-id", "user-type"];
|
|
72
|
+
};
|
|
73
|
+
export {};
|