@mkody/twitch-emoticons 2.9.6 → 3.0.0-beta.2
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/README.md +530 -169
- package/dist/TwitchEmoticons.cjs +950 -0
- package/dist/TwitchEmoticons.esm.min.js +7 -0
- package/dist/TwitchEmoticons.esm.min.js.map +7 -0
- package/dist/TwitchEmoticons.min.js +2 -20
- package/dist/TwitchEmoticons.min.js.map +4 -4
- package/package.json +99 -72
- package/src/index.js +38 -12
- package/src/struct/BTTVEmote.js +72 -74
- package/src/struct/Channel.js +48 -48
- package/src/struct/Emote.js +71 -71
- package/src/struct/EmoteFetcher.js +358 -322
- package/src/struct/EmoteParser.js +95 -84
- package/src/struct/EmoteTypeMapper.js +9 -9
- package/src/struct/FFZEmote.js +91 -93
- package/src/struct/SevenTVEmote.js +88 -90
- package/src/struct/TwitchEmote.js +72 -71
- package/src/util/Collection.js +69 -55
- package/src/util/Constants.js +30 -30
- package/typings/index.d.cts +254 -0
- package/typings/index.d.ts +216 -99
- package/.jsdoc.json +0 -46
- package/.nvmrc +0 -1
- package/docs/BTTVEmote.html +0 -1532
- package/docs/Channel.html +0 -824
- package/docs/Collection.html +0 -798
- package/docs/Emote.html +0 -832
- package/docs/EmoteFetcher.html +0 -3741
- package/docs/EmoteParser.html +0 -1187
- package/docs/FFZEmote.html +0 -1686
- package/docs/SevenTVEmote.html +0 -1596
- package/docs/TwitchEmote.html +0 -1528
- package/docs/fonts/Montserrat/Montserrat-Bold.eot +0 -0
- package/docs/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
- package/docs/fonts/Montserrat/Montserrat-Bold.woff +0 -0
- package/docs/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
- package/docs/fonts/Montserrat/Montserrat-Regular.eot +0 -0
- package/docs/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
- package/docs/fonts/Montserrat/Montserrat-Regular.woff +0 -0
- package/docs/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +0 -978
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +0 -1049
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
- package/docs/index.html +0 -233
- package/docs/scripts/collapse.js +0 -39
- package/docs/scripts/commonNav.js +0 -28
- package/docs/scripts/linenumber.js +0 -25
- package/docs/scripts/nav.js +0 -12
- package/docs/scripts/polyfill.js +0 -4
- package/docs/scripts/prettify/Apache-License-2.0.txt +0 -202
- package/docs/scripts/prettify/lang-css.js +0 -2
- package/docs/scripts/prettify/prettify.js +0 -28
- package/docs/scripts/search.js +0 -99
- package/docs/struct_BTTVEmote.js.html +0 -162
- package/docs/struct_Channel.js.html +0 -132
- package/docs/struct_Emote.js.html +0 -159
- package/docs/struct_EmoteFetcher.js.html +0 -429
- package/docs/struct_EmoteParser.js.html +0 -172
- package/docs/struct_FFZEmote.js.html +0 -185
- package/docs/struct_SevenTVEmote.js.html +0 -180
- package/docs/struct_TwitchEmote.js.html +0 -159
- package/docs/styles/jsdoc.css +0 -776
- package/docs/styles/prettify.css +0 -80
- package/docs/util_Collection.js.html +0 -151
- package/eslint.config.mjs +0 -215
- package/jest.config.js +0 -198
- package/test/BTTV.test.js +0 -48
- package/test/FFZ.test.js +0 -71
- package/test/SevenTV.test.js +0 -71
- package/test/ToFromObject.test.js +0 -156
- package/test/Twitch.test.js +0 -64
- package/test/__snapshots__/ToFromObject.test.js.snap +0 -121
- package/test/other.test.js +0 -72
|
@@ -1,357 +1,393 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const axios = require('axios');
|
|
10
|
-
const { ApiClient } = require('@twurple/api');
|
|
11
|
-
const { AppTokenAuthProvider } = require('@twurple/auth');
|
|
1
|
+
import BTTVEmote from './BTTVEmote.js'
|
|
2
|
+
import Channel from './Channel.js'
|
|
3
|
+
import Collection from '../util/Collection.js'
|
|
4
|
+
import Constants from '../util/Constants.js'
|
|
5
|
+
import FFZEmote from './FFZEmote.js'
|
|
6
|
+
import SevenTVEmote from './SevenTVEmote.js'
|
|
7
|
+
import TwitchEmote from './TwitchEmote.js'
|
|
12
8
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
* Fetches and caches emotes.
|
|
16
|
-
* @param {string} clientId The client id for the twitch api.
|
|
17
|
-
* @param {string} clientSecret The client secret for the twitch api.
|
|
18
|
-
* @param {object} options Additional options.
|
|
19
|
-
* @param {ApiClient} options.apiClient - Bring your own Twurple ApiClient.
|
|
20
|
-
*/
|
|
21
|
-
constructor(clientId, clientSecret, options) {
|
|
22
|
-
if (options && options.apiClient) {
|
|
23
|
-
this.apiClient = options.apiClient;
|
|
24
|
-
} else if (clientId !== undefined && clientSecret !== undefined) {
|
|
25
|
-
const authProvider = new AppTokenAuthProvider(clientId, clientSecret);
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Twitch api client.
|
|
29
|
-
*/
|
|
30
|
-
this.apiClient = new ApiClient({ authProvider });
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Cached emotes.
|
|
35
|
-
* Collectionped by emote code to Emote instance.
|
|
36
|
-
* @type {Collection<string, Emote>}
|
|
37
|
-
*/
|
|
38
|
-
this.emotes = new Collection();
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Cached channels.
|
|
42
|
-
* Collectionped by name to Channel instance.
|
|
43
|
-
* @type {Collection<string, Channel>}
|
|
44
|
-
*/
|
|
45
|
-
this.channels = new Collection();
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Save if we fetched FFZ's modifier emotes once.
|
|
49
|
-
* @type {boolean}
|
|
50
|
-
*/
|
|
51
|
-
this.ffzModifiersFetched = false;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* The global channel for Twitch, BTTV and 7TV.
|
|
56
|
-
* @readonly
|
|
57
|
-
* @type {?Channel}
|
|
58
|
-
*/
|
|
59
|
-
get globalChannel() {
|
|
60
|
-
return this.channels.get(null);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Sets up a channel
|
|
65
|
-
* @private
|
|
66
|
-
* @param {int} channel_id - ID of the channel.
|
|
67
|
-
* @param {string} [format=null] - The type file format to use (webp/avif).
|
|
68
|
-
* @throws {Error} When Twitch Client ID or Client Secret were not provided.
|
|
69
|
-
* @returns {Channel}
|
|
70
|
-
*/
|
|
71
|
-
_setupChannel(channel_id, format = null) {
|
|
72
|
-
let channel = this.channels.get(channel_id);
|
|
73
|
-
if (!channel) {
|
|
74
|
-
channel = new Channel(this, channel_id);
|
|
75
|
-
this.channels.set(channel_id, channel);
|
|
76
|
-
}
|
|
77
|
-
if (format) channel.format = format;
|
|
78
|
-
return channel;
|
|
79
|
-
}
|
|
9
|
+
import { ApiClient } from '@twurple/api'
|
|
10
|
+
import { AppTokenAuthProvider } from '@twurple/auth'
|
|
80
11
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
12
|
+
class EmoteFetcher {
|
|
13
|
+
/**
|
|
14
|
+
* Fetches and caches emotes.
|
|
15
|
+
* @param {object} [options={}] Fetcher's options.
|
|
16
|
+
* @param {string} [options.twitchAppID] Your app ID for the Twitch API.
|
|
17
|
+
* @param {string} [options.twitchAppSecret] Your app secret for the Twitch API.
|
|
18
|
+
* @param {ApiClient} [options.apiClient] - Bring your own Twurple ApiClient.
|
|
19
|
+
* @param {boolean} [options.forceStatic=false] - Force emotes to be static (non-animated).
|
|
20
|
+
* @param {'dark' | 'light'} [options.twitchThemeMode='dark'] - Theme mode (background color) preference for Twitch emotes.
|
|
21
|
+
*/
|
|
22
|
+
constructor (options = {}) {
|
|
23
|
+
if (options.apiClient) {
|
|
24
|
+
/**
|
|
25
|
+
* Provided Twitch ApiClient.
|
|
26
|
+
* @type {ApiClient}
|
|
27
|
+
*/
|
|
28
|
+
this.apiClient = options.apiClient
|
|
29
|
+
} else if (options.twitchAppID && options.twitchAppSecret) {
|
|
30
|
+
const authProvider = new AppTokenAuthProvider(options.twitchAppID, options.twitchAppSecret)
|
|
31
|
+
/**
|
|
32
|
+
* Twitch API client.
|
|
33
|
+
* @type {ApiClient}
|
|
34
|
+
*/
|
|
35
|
+
this.apiClient = new ApiClient({ authProvider })
|
|
97
36
|
}
|
|
98
37
|
|
|
99
38
|
/**
|
|
100
|
-
*
|
|
101
|
-
* @
|
|
102
|
-
* @param {int} channel_id - ID of the channel.
|
|
103
|
-
* @param {object} data - Raw data.
|
|
104
|
-
* @param {TwitchEmote} [existing_emote=null] - Existing emote to cache.
|
|
105
|
-
* @returns {TwitchEmote}
|
|
39
|
+
* Force emotes to be static (non-animated).
|
|
40
|
+
* @type {boolean}
|
|
106
41
|
*/
|
|
107
|
-
|
|
108
|
-
const channel = this._setupChannel(channel_id);
|
|
109
|
-
const emote = existing_emote || new TwitchEmote(channel, data.id, data);
|
|
110
|
-
this.emotes.set(emote.code, emote);
|
|
111
|
-
channel.emotes.set(emote.code, emote);
|
|
112
|
-
return emote;
|
|
113
|
-
}
|
|
42
|
+
this.forceStatic = options.forceStatic || false
|
|
114
43
|
|
|
115
44
|
/**
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
* @private
|
|
119
|
-
* @param {int} [id=null] - ID of the channel.
|
|
120
|
-
* @returns {Promise<object[]>}
|
|
45
|
+
* Theme mode (background color) preference for Twitch emotes.
|
|
46
|
+
* @type {'dark' | 'light'}
|
|
121
47
|
*/
|
|
122
|
-
|
|
123
|
-
const endpoint = !id
|
|
124
|
-
? Constants.BTTV.Global
|
|
125
|
-
: Constants.BTTV.Channel(id); // eslint-disable-line new-cap
|
|
126
|
-
|
|
127
|
-
return axios.get(endpoint).then(req => {
|
|
128
|
-
// Global emotes
|
|
129
|
-
if (req.data instanceof Array) return req.data;
|
|
130
|
-
// Channel emotes
|
|
131
|
-
return [...req.data.channelEmotes, ...req.data.sharedEmotes];
|
|
132
|
-
});
|
|
133
|
-
}
|
|
48
|
+
this.twitchThemeMode = options.twitchThemeMode || 'dark'
|
|
134
49
|
|
|
135
50
|
/**
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
* @
|
|
139
|
-
* @param {object} data - Raw data.
|
|
140
|
-
* @param {BTTVEmote} [existing_emote=null] - Existing emote to cache.
|
|
141
|
-
* @returns {BTTVEmote}
|
|
51
|
+
* Cached emotes.
|
|
52
|
+
* Collectionped by emote code to Emote instance.
|
|
53
|
+
* @type {Collection<string, Emote>}
|
|
142
54
|
*/
|
|
143
|
-
|
|
144
|
-
const channel = this._setupChannel(channel_id);
|
|
145
|
-
const emote = existing_emote || new BTTVEmote(channel, data.id, data);
|
|
146
|
-
this.emotes.set(emote.code, emote);
|
|
147
|
-
channel.emotes.set(emote.code, emote);
|
|
148
|
-
return emote;
|
|
149
|
-
}
|
|
55
|
+
this.emotes = new Collection()
|
|
150
56
|
|
|
151
57
|
/**
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
* @
|
|
155
|
-
* @returns {Promise<object[]>}
|
|
58
|
+
* Cached channels.
|
|
59
|
+
* Collectionped by name to Channel instance.
|
|
60
|
+
* @type {Collection<string, Channel>}
|
|
156
61
|
*/
|
|
157
|
-
|
|
158
|
-
const endpoint = Constants.FFZ.Set(id); // eslint-disable-line new-cap
|
|
159
|
-
|
|
160
|
-
return axios.get(endpoint).then(req => {
|
|
161
|
-
return req.data.set.emoticons;
|
|
162
|
-
});
|
|
163
|
-
}
|
|
62
|
+
this.channels = new Collection()
|
|
164
63
|
|
|
165
64
|
/**
|
|
166
|
-
*
|
|
167
|
-
* @
|
|
168
|
-
* @param {int} id - ID of the channel.
|
|
169
|
-
* @returns {Promise<object[]>}
|
|
65
|
+
* Save if we fetched FFZ's modifier emotes once.
|
|
66
|
+
* @type {boolean}
|
|
170
67
|
*/
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
68
|
+
this.ffzModifiersFetched = false
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The global channel for Twitch, BTTV and 7TV.
|
|
73
|
+
* @readonly
|
|
74
|
+
* @type {?Channel}
|
|
75
|
+
*/
|
|
76
|
+
get globalChannel () {
|
|
77
|
+
return this.channels.get(null)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Sets up a channel
|
|
82
|
+
* @private
|
|
83
|
+
* @param {number} channelId - ID of the channel.
|
|
84
|
+
* @param {string} [format] - The type file format to use (webp/avif).
|
|
85
|
+
* @throws {Error} When Twitch Client ID or Client Secret were not provided.
|
|
86
|
+
* @returns {Channel} - A Channel instance.
|
|
87
|
+
*/
|
|
88
|
+
_setupChannel (channelId, format) {
|
|
89
|
+
let channel = this.channels.get(channelId)
|
|
90
|
+
if (!channel) {
|
|
91
|
+
channel = new Channel(this, channelId)
|
|
92
|
+
this.channels.set(channelId, channel)
|
|
183
93
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
channel.emotes.set(emote.code, emote);
|
|
198
|
-
return emote;
|
|
94
|
+
if (format) channel.format = format.toLowerCase()
|
|
95
|
+
return channel
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Gets the raw Twitch emotes data for a channel.
|
|
100
|
+
* @private
|
|
101
|
+
* @param {number} id - ID of the channel.
|
|
102
|
+
* @returns {Promise<object[]>} - A promise that resolves to an array of raw Twitch emote data.
|
|
103
|
+
*/
|
|
104
|
+
_getRawTwitchEmotes (id) {
|
|
105
|
+
if (!this.apiClient) {
|
|
106
|
+
throw new Error('Client id or client secret not provided.')
|
|
199
107
|
}
|
|
200
108
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
* @returns {Promise<object[]>}
|
|
206
|
-
*/
|
|
207
|
-
_getRawSevenTVEmotes(id) {
|
|
208
|
-
const endpoint = !id
|
|
209
|
-
? Constants.SevenTV.Global
|
|
210
|
-
: Constants.SevenTV.Channel(id); // eslint-disable-line new-cap
|
|
211
|
-
|
|
212
|
-
return axios.get(endpoint).then(req => req.data);
|
|
109
|
+
if (id) {
|
|
110
|
+
return this.apiClient.chat.getChannelEmotes(id)
|
|
111
|
+
} else {
|
|
112
|
+
return this.apiClient.chat.getGlobalEmotes()
|
|
213
113
|
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Converts and caches a raw twitch emote.
|
|
118
|
+
* @private
|
|
119
|
+
* @param {number} channelId - ID of the channel.
|
|
120
|
+
* @param {object} data - Raw data.
|
|
121
|
+
* @param {TwitchEmote} [existingEmote] - Existing emote to cache.
|
|
122
|
+
* @returns {TwitchEmote} - A TwitchEmote instance.
|
|
123
|
+
*/
|
|
124
|
+
_cacheTwitchEmote (channelId, data, existingEmote) {
|
|
125
|
+
const channel = this._setupChannel(channelId)
|
|
126
|
+
const emote = existingEmote || new TwitchEmote(channel, data.id, data)
|
|
127
|
+
this.emotes.set(emote.code, emote)
|
|
128
|
+
channel.emotes.set(emote.code, emote)
|
|
129
|
+
return emote
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Gets the raw BTTV emotes data for a channel.
|
|
134
|
+
* Use `null` for the global emotes channel.
|
|
135
|
+
* @private
|
|
136
|
+
* @param {number} [id] - ID of the channel.
|
|
137
|
+
* @returns {Promise<object[]>} - A promise that resolves to an array of raw BTTV emote data.
|
|
138
|
+
*/
|
|
139
|
+
_getRawBTTVEmotes (id) {
|
|
140
|
+
const endpoint = id
|
|
141
|
+
? Constants.BTTV.Channel(id)
|
|
142
|
+
: Constants.BTTV.Global
|
|
143
|
+
|
|
144
|
+
return fetch(endpoint)
|
|
145
|
+
.then((response) => response.json())
|
|
146
|
+
.then((data) => {
|
|
147
|
+
// Global emotes
|
|
148
|
+
if (Array.isArray(data)) return data
|
|
149
|
+
// Channel emotes
|
|
150
|
+
if (data?.channelEmotes && data?.sharedEmotes) {
|
|
151
|
+
return [
|
|
152
|
+
...data.channelEmotes,
|
|
153
|
+
...data.sharedEmotes,
|
|
154
|
+
]
|
|
155
|
+
}
|
|
156
|
+
// Fallback - in case the response format is unexpected
|
|
157
|
+
return data || []
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Converts and caches a raw BTTV emote.
|
|
163
|
+
* @private
|
|
164
|
+
* @param {number} channelId - ID of the channel.
|
|
165
|
+
* @param {object} data - Raw data.
|
|
166
|
+
* @param {BTTVEmote} [existingEmote] - Existing emote to cache.
|
|
167
|
+
* @returns {BTTVEmote} - A BTTVEmote instance.
|
|
168
|
+
*/
|
|
169
|
+
_cacheBTTVEmote (channelId, data, existingEmote) {
|
|
170
|
+
const channel = this._setupChannel(channelId)
|
|
171
|
+
const emote = existingEmote || new BTTVEmote(channel, data.id, data)
|
|
172
|
+
this.emotes.set(emote.code, emote)
|
|
173
|
+
channel.emotes.set(emote.code, emote)
|
|
174
|
+
return emote
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Gets the raw FFZ emote data from a set.
|
|
179
|
+
* @private
|
|
180
|
+
* @param {number} id - ID of the set.
|
|
181
|
+
* @returns {Promise<object[]>} - A promise that resolves to an array of raw FFZ emote data.
|
|
182
|
+
*/
|
|
183
|
+
_getRawFFZEmoteSet (id) {
|
|
184
|
+
const endpoint = Constants.FFZ.Set(id)
|
|
185
|
+
|
|
186
|
+
return fetch(endpoint)
|
|
187
|
+
.then((response) => response.json())
|
|
188
|
+
.then((data) => {
|
|
189
|
+
return data.set.emoticons
|
|
190
|
+
})
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Gets the raw FFZ emotes data for a channel.
|
|
195
|
+
* @private
|
|
196
|
+
* @param {number} id - ID of the channel.
|
|
197
|
+
* @returns {Promise<object[]>} - A promise that resolves to an array of raw FFZ emote data.
|
|
198
|
+
*/
|
|
199
|
+
_getRawFFZEmotes (id) {
|
|
200
|
+
const endpoint = Constants.FFZ.Channel(id)
|
|
201
|
+
|
|
202
|
+
return fetch(endpoint)
|
|
203
|
+
.then((response) => response.json())
|
|
204
|
+
.then((data) => {
|
|
205
|
+
const emotes = []
|
|
206
|
+
for (const key of Object.keys(data.sets)) {
|
|
207
|
+
const set = data.sets[key]
|
|
208
|
+
emotes.push(...set.emoticons)
|
|
209
|
+
}
|
|
214
210
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
211
|
+
return emotes
|
|
212
|
+
})
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Converts and caches a raw FFZ emote.
|
|
217
|
+
* @private
|
|
218
|
+
* @param {number} channelId - ID of the channel.
|
|
219
|
+
* @param {object} data - Raw data.
|
|
220
|
+
* @param {FFZEmote} [existingEmote] - Existing emote to cache.
|
|
221
|
+
* @returns {FFZEmote} - A FFZEmote instance.
|
|
222
|
+
*/
|
|
223
|
+
_cacheFFZEmote (channelId, data, existingEmote) {
|
|
224
|
+
const channel = this._setupChannel(channelId)
|
|
225
|
+
const emote = existingEmote || new FFZEmote(channel, data.id, data)
|
|
226
|
+
this.emotes.set(emote.code, emote)
|
|
227
|
+
channel.emotes.set(emote.code, emote)
|
|
228
|
+
return emote
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Gets the raw 7TV emotes data for a channel.
|
|
233
|
+
* @private
|
|
234
|
+
* @param {number} [id] - ID of the channel.
|
|
235
|
+
* @returns {Promise<object[]>} - A promise that resolves to an array of raw 7TV emote data.
|
|
236
|
+
*/
|
|
237
|
+
_getRawSevenTVEmotes (id) {
|
|
238
|
+
const endpoint = id
|
|
239
|
+
? Constants.SevenTV.Channel(id)
|
|
240
|
+
: Constants.SevenTV.Global
|
|
241
|
+
|
|
242
|
+
return fetch(endpoint).then((response) => response.json())
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Converts and caches a raw 7TV emote.
|
|
247
|
+
* @private
|
|
248
|
+
* @param {number} channelId - ID of the channel.
|
|
249
|
+
* @param {object} data - Raw data.
|
|
250
|
+
* @param {string} format - The type file format to use (webp/avif).
|
|
251
|
+
* @param {SevenTVEmote} [existingEmote] - Existing emote to cache.
|
|
252
|
+
* @returns {SevenTVEmote} - A SevenTVEmote instance.
|
|
253
|
+
*/
|
|
254
|
+
_cacheSevenTVEmote (channelId, data, format, existingEmote) {
|
|
255
|
+
const channel = this._setupChannel(channelId, format)
|
|
256
|
+
const emote = existingEmote || new SevenTVEmote(channel, data.id, data)
|
|
257
|
+
this.emotes.set(emote.code, emote)
|
|
258
|
+
channel.emotes.set(emote.code, emote)
|
|
259
|
+
return emote
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Fetches the Twitch emotes for a channel.
|
|
264
|
+
* Use `null` for the global emotes channel.
|
|
265
|
+
* @param {number} [channel] - ID of the channel.
|
|
266
|
+
* @returns {Promise<Collection<string, TwitchEmote>>} - A promise that resolves to a collection of TwitchEmotes.
|
|
267
|
+
*/
|
|
268
|
+
fetchTwitchEmotes (channel) {
|
|
269
|
+
return this._getRawTwitchEmotes(channel).then((rawEmotes) => {
|
|
270
|
+
for (const emote of rawEmotes) {
|
|
271
|
+
this._cacheTwitchEmote(channel, {
|
|
272
|
+
code: emote.name, id: emote.id, formats: emote.formats,
|
|
273
|
+
})
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return this.channels.get(channel).emotes.filter((e) => e.type === 'twitch')
|
|
277
|
+
})
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Fetches the BTTV emotes for a channel.
|
|
282
|
+
* Use `null` for the global emotes channel.
|
|
283
|
+
* @param {number} [channel] - ID of the channel.
|
|
284
|
+
* @returns {Promise<Collection<string, BTTVEmote>>} - A promise that resolves to a collection of BTTVEmotes.
|
|
285
|
+
*/
|
|
286
|
+
fetchBTTVEmotes (channel) {
|
|
287
|
+
return this._getRawBTTVEmotes(channel).then((rawEmotes) => {
|
|
288
|
+
for (const data of rawEmotes) {
|
|
289
|
+
this._cacheBTTVEmote(channel, data)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
return this.channels.get(channel).emotes.filter((e) => e.type === 'bttv')
|
|
293
|
+
})
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Fetches the FFZ emotes for a channel.
|
|
298
|
+
* @param {number} [channel] - ID of the channel.
|
|
299
|
+
* @returns {Promise<Collection<string, FFZEmote>>} - A promise that resolves to a collection of FFZEmotes.
|
|
300
|
+
*/
|
|
301
|
+
async fetchFFZEmotes (channel) {
|
|
302
|
+
// Fetch modifier emotes at least once
|
|
303
|
+
if (!this.ffzModifiersFetched) {
|
|
304
|
+
this.ffzModifiersFetched = true
|
|
305
|
+
|
|
306
|
+
await this._getRawFFZEmoteSet(Constants.FFZ.sets.Modifiers).then((rawEmotes) => {
|
|
307
|
+
for (const data of rawEmotes) {
|
|
308
|
+
this._cacheFFZEmote(null, data)
|
|
309
|
+
}
|
|
310
|
+
})
|
|
230
311
|
}
|
|
231
312
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
fetchTwitchEmotes(channel = null) {
|
|
239
|
-
return this._getRawTwitchEmotes(channel).then(rawEmotes => {
|
|
240
|
-
for (const emote of rawEmotes) {
|
|
241
|
-
this._cacheTwitchEmote(channel, {
|
|
242
|
-
code: emote.name, id: emote.id, formats: emote.formats
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
return this.channels.get(channel).emotes.filter(e => e.type === 'twitch');
|
|
247
|
-
});
|
|
248
|
-
}
|
|
313
|
+
// If no channel specified, fetch the Global set
|
|
314
|
+
if (!channel) {
|
|
315
|
+
return this._getRawFFZEmoteSet(Constants.FFZ.sets.Global).then((rawEmotes) => {
|
|
316
|
+
for (const data of rawEmotes) {
|
|
317
|
+
this._cacheFFZEmote(channel, data)
|
|
318
|
+
}
|
|
249
319
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
* Use `null` for the global emotes channel.
|
|
253
|
-
* @param {int} [channel=null] - ID of the channel.
|
|
254
|
-
* @returns {Promise<Collection<string, BTTVEmote>>}
|
|
255
|
-
*/
|
|
256
|
-
fetchBTTVEmotes(channel = null) {
|
|
257
|
-
return this._getRawBTTVEmotes(channel).then(rawEmotes => {
|
|
258
|
-
for (const data of rawEmotes) {
|
|
259
|
-
this._cacheBTTVEmote(channel, data);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
return this.channels.get(channel).emotes.filter(e => e.type === 'bttv');
|
|
263
|
-
});
|
|
320
|
+
return this.channels.get(channel).emotes.filter((e) => e.type === 'ffz')
|
|
321
|
+
})
|
|
264
322
|
}
|
|
265
323
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
324
|
+
return this._getRawFFZEmotes(channel).then((rawEmotes) => {
|
|
325
|
+
for (const data of rawEmotes) {
|
|
326
|
+
this._cacheFFZEmote(channel, data)
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return this.channels.get(channel).emotes.filter((e) => e.type === 'ffz')
|
|
330
|
+
})
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Fetches the 7TV emotes for a channel.
|
|
335
|
+
* @param {number} [channel] - ID of the channel.
|
|
336
|
+
* @param {object} [options] - Options for fetching.
|
|
337
|
+
* @param {('webp'|'avif')} [options.format] - The type file format to use (webp/avif).
|
|
338
|
+
* @returns {Promise<Collection<string, SevenTVEmote>>} - A promise that resolves to a collection of SevenTVEmotes.
|
|
339
|
+
*/
|
|
340
|
+
fetchSevenTVEmotes (channel, options) {
|
|
341
|
+
const {
|
|
342
|
+
format = 'webp',
|
|
343
|
+
} = options || {}
|
|
344
|
+
|
|
345
|
+
return this._getRawSevenTVEmotes(channel).then((rawEmotes) => {
|
|
346
|
+
if (Object.hasOwn(rawEmotes, 'emotes')) {
|
|
347
|
+
// From an emote set (like "global")
|
|
348
|
+
for (const data of rawEmotes.emotes) {
|
|
349
|
+
this._cacheSevenTVEmote(channel, data, format)
|
|
281
350
|
}
|
|
282
|
-
|
|
283
|
-
//
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
for (const data of rawEmotes) {
|
|
287
|
-
this._cacheFFZEmote(channel, data);
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
return this.channels.get(channel).emotes.filter(e => e.type === 'ffz');
|
|
291
|
-
});
|
|
351
|
+
} else {
|
|
352
|
+
// From users
|
|
353
|
+
for (const data of rawEmotes.emote_set.emotes) {
|
|
354
|
+
this._cacheSevenTVEmote(channel, data, format)
|
|
292
355
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return this.channels.get(channel).emotes.filter((e) => e.type === '7tv')
|
|
359
|
+
})
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Converts emote Objects to emotes
|
|
364
|
+
* @param {object} [emotesArray] - An array of emote objects
|
|
365
|
+
* @throws {TypeError} When an emote has an unknown type.
|
|
366
|
+
* @returns {Emote[]} - An array of Emote instances.
|
|
367
|
+
*/
|
|
368
|
+
fromObject (emotesArray) {
|
|
369
|
+
const emotes = []
|
|
370
|
+
const classMap = {
|
|
371
|
+
'bttv': { class: BTTVEmote, cache: (emoteObject, channelId, existingEmote) => this._cacheBTTVEmote(channelId, null, existingEmote) },
|
|
372
|
+
'ffz': { class: FFZEmote, cache: (emoteObject, channelId, existingEmote) => this._cacheFFZEmote(channelId, null, existingEmote) },
|
|
373
|
+
'7tv': { class: SevenTVEmote, cache: (emoteObject, channelId, existingEmote) => this._cacheSevenTVEmote(channelId, null, emoteObject.imageType, existingEmote) },
|
|
374
|
+
'twitch': { class: TwitchEmote, cache: (emoteObject, channelId, existingEmote) => this._cacheTwitchEmote(channelId, null, existingEmote) },
|
|
301
375
|
}
|
|
302
376
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
this._cacheSevenTVEmote(channel, data, format);
|
|
315
|
-
}
|
|
316
|
-
} else {
|
|
317
|
-
// From users
|
|
318
|
-
for (const data of rawEmotes.emote_set.emotes) {
|
|
319
|
-
this._cacheSevenTVEmote(channel, data, format);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
return this.channels.get(channel).emotes.filter(e => e.type === '7tv');
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
/**
|
|
328
|
-
* Converts emote Objects to emotes
|
|
329
|
-
* @param {object} [emotesArray] - An array of emote objects
|
|
330
|
-
* @throws {TypeError} When an emote has an unknown type.
|
|
331
|
-
* @returns {Emote[]}
|
|
332
|
-
*/
|
|
333
|
-
fromObject(emotesArray) {
|
|
334
|
-
const emotes = [];
|
|
335
|
-
const classMap = {
|
|
336
|
-
bttv: { class: BTTVEmote, cache: (emoteObject, channel_id, existing_emote) => this._cacheBTTVEmote(channel_id, null, existing_emote) },
|
|
337
|
-
ffz: { class: FFZEmote, cache: (emoteObject, channel_id, existing_emote) => this._cacheFFZEmote(channel_id, null, existing_emote) },
|
|
338
|
-
'7tv': { class: SevenTVEmote, cache: (emoteObject, channel_id, existing_emote) => this._cacheSevenTVEmote(channel_id, null, emoteObject.imageType, existing_emote) },
|
|
339
|
-
twitch: { class: TwitchEmote, cache: (emoteObject, channel_id, existing_emote) => this._cacheTwitchEmote(channel_id, null, existing_emote) }
|
|
340
|
-
};
|
|
341
|
-
for (const emoteObject of emotesArray) {
|
|
342
|
-
const { type } = emoteObject;
|
|
343
|
-
if (!Object.keys(classMap).includes(type)) {
|
|
344
|
-
throw new TypeError(`Unknown type: ${type}`);
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
const emoteClass = classMap[type].class;
|
|
348
|
-
this._setupChannel(emoteObject.channel_id, type === '7tv' ? emoteObject.imageType : null);
|
|
349
|
-
const emote = emoteClass.fromObject(emoteObject, this.channels.get(emoteObject.channel_id));
|
|
350
|
-
classMap[type].cache(emoteObject, emoteObject.channel_id, emote);
|
|
351
|
-
emotes.push(emote);
|
|
352
|
-
}
|
|
353
|
-
return emotes;
|
|
377
|
+
for (const emoteObject of emotesArray) {
|
|
378
|
+
const { type } = emoteObject
|
|
379
|
+
if (!Object.keys(classMap).includes(type)) {
|
|
380
|
+
throw new TypeError(`Unknown type: ${type}`)
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const emoteClass = classMap[type].class
|
|
384
|
+
this._setupChannel(emoteObject.channel_id, type === '7tv' ? emoteObject.imageType : null)
|
|
385
|
+
const emote = emoteClass.fromObject(emoteObject, this.channels.get(emoteObject.channel_id))
|
|
386
|
+
classMap[type].cache(emoteObject, emoteObject.channel_id, emote)
|
|
387
|
+
emotes.push(emote)
|
|
354
388
|
}
|
|
389
|
+
return emotes
|
|
390
|
+
}
|
|
355
391
|
}
|
|
356
392
|
|
|
357
|
-
|
|
393
|
+
export default EmoteFetcher
|