@mkody/twitch-emoticons 3.0.0-beta.2 → 3.0.0-beta.3
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 +74 -54
- package/dist/TwitchEmoticons.cjs +129 -37
- package/dist/TwitchEmoticons.esm.min.js +49 -2
- package/dist/TwitchEmoticons.esm.min.js.map +3 -3
- package/dist/TwitchEmoticons.min.js +49 -2
- package/dist/TwitchEmoticons.min.js.map +3 -3
- package/package.json +7 -7
- package/src/struct/Channel.js +1 -1
- package/src/struct/EmoteFetcher.js +28 -18
- package/src/struct/EmoteParser.js +4 -1
- package/src/struct/FFZEmote.js +22 -8
- package/src/struct/SevenTVEmote.js +60 -12
- package/src/struct/TwitchEmote.js +3 -3
- package/src/util/Constants.js +50 -2
package/README.md
CHANGED
|
@@ -17,29 +17,28 @@ Gets Twitch, BTTV, FFZ and 7TV emotes as well as parsing text to emotes!
|
|
|
17
17
|
|
|
18
18
|
### List of breaking changes from 2.x to 3.x
|
|
19
19
|
|
|
20
|
-
- Node.js 20 is required; we
|
|
20
|
+
- Node.js 20 is required; we have set the minimum to 20.18.1.
|
|
21
21
|
*This library is now an ECMAScript module, so you can use proper `import {...} from '...'` imports.*
|
|
22
22
|
- The initialization of `EmoteFetcher` changed to only use an object as the first parameter for options.
|
|
23
23
|
- API keys for Twitch must now be set with `twitchAppID` and `twitchAppSecret` properties.
|
|
24
24
|
- The previously available `apiClient` is now set in this object too.
|
|
25
|
-
- The defaults for `EmoteParser` changed to use the `html` template, and it
|
|
26
|
-
- The default `html` template
|
|
27
|
-
*The `size`
|
|
25
|
+
- The defaults for `EmoteParser` changed to use the `html` template, and it does not require `:colons:` by default (using `/(\w+)/` to match any words).
|
|
26
|
+
- The default `html` template does not have `twitch-emote-{size}` anymore in its `class` attribute.
|
|
27
|
+
*The `size` is inconsistent between the different sources, so it cannot be reliably used.*
|
|
28
28
|
- The `EmoteFetcher.fetchSevenTVEmotes()`, `Emote.toLink()`, and `EmoteParse.parse()` methods now have their options as an object.
|
|
29
29
|
- `fetcher.fetchSevenTVEmotes(null, { format: 'avif' })` - The first parameter is still the Twitch user ID (or `null` for global).
|
|
30
30
|
- `emote.toLink({ size: 1, forceStatic: true, themeMode: 'light' })`
|
|
31
31
|
- `parser.parse('Kappa', { size: 2, forceStatic: true, themeMode: 'dark' })` - The first parameter is still the input text.
|
|
32
32
|
- The `owner` getter for `Emote`s has been removed.
|
|
33
|
-
*It
|
|
34
|
-
- If you
|
|
35
|
-
|
|
33
|
+
*It is not reliable to get the `Channel` object, more so with 3rd-party providers since emotes might be owned by a channel that we never fetched (for shared/public emotes).*
|
|
34
|
+
- If you have exported 7TV emotes, do note that the `sizes` array changed to not include the leading `x.<format>`.
|
|
35
|
+
*The rest of the export/import is still compatible with the current implementation.*
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
### Example of code changes
|
|
39
39
|
|
|
40
|
-
Our examples are running in an ESM-based project (`"type": "module"`).
|
|
41
|
-
|
|
42
|
-
We export a CommonJS-compatible build, so you can still use `require(...)`:
|
|
40
|
+
Our examples are running in an ESM-based project (`"type": "module"`).
|
|
41
|
+
Do note that we export a CommonJS-compatible build, so you can still use `require(...)`:
|
|
43
42
|
```js
|
|
44
43
|
const { EmoteFetcher, EmoteParser } = require('@mkody/twitch-emoticons')
|
|
45
44
|
```
|
|
@@ -53,12 +52,12 @@ const { EmoteFetcher, EmoteParser } = TwitchEmoticons // but you should move awa
|
|
|
53
52
|
|
|
54
53
|
const fetcher = new EmoteFetcher('<your app ID>', '<your app secret>') // <- The first two parameters were for the Twitch app ID/secret
|
|
55
54
|
|
|
56
|
-
// Those next three lines
|
|
57
|
-
await fetcher.fetchTwitchEmotes() // Do note that CommonJS
|
|
55
|
+
// Those next three lines do not have breaking changes
|
|
56
|
+
await fetcher.fetchTwitchEmotes() // Do note that CommonJS does not handle `await` at the top level
|
|
58
57
|
const parser = new EmoteParser(fetcher)
|
|
59
58
|
const emote = emoteFetcher.emotes.get('Kappa')
|
|
60
59
|
|
|
61
|
-
console.log(emote.toLink(2)) // <- Only the size was available and
|
|
60
|
+
console.log(emote.toLink(2)) // <- Only the size was available and set as the first parameter
|
|
62
61
|
// https://static-cdn.jtvnw.net/emoticons/v2/25/default/dark/3.0
|
|
63
62
|
|
|
64
63
|
console.log(parser.parse('Hello :CoolCat:!')) // <- Used colons and returned Markdown by default
|
|
@@ -76,7 +75,7 @@ const fetcher = new EmoteFetcher({ // <- Uses an object!
|
|
|
76
75
|
twitchAppSecret: '<your app secret>',
|
|
77
76
|
})
|
|
78
77
|
|
|
79
|
-
// Those next three lines
|
|
78
|
+
// Those next three lines do not have breaking changes
|
|
80
79
|
await fetcher.fetchTwitchEmotes()
|
|
81
80
|
const parser = new EmoteParser(fetcher)
|
|
82
81
|
const emote = emoteFetcher.emotes.get('Kappa')
|
|
@@ -84,7 +83,7 @@ const emote = emoteFetcher.emotes.get('Kappa')
|
|
|
84
83
|
console.log(emote.toLink({ size: 2 })) // <- Uses an object!
|
|
85
84
|
// https://static-cdn.jtvnw.net/emoticons/v2/25/default/dark/3.0
|
|
86
85
|
|
|
87
|
-
console.log(parser.parse('Hello CoolCat!')) // <-
|
|
86
|
+
console.log(parser.parse('Hello CoolCat!')) // <- Does not require :colons: and returns HTML by default!
|
|
88
87
|
// Hello <img alt="CoolCat" title="CoolCat" class="twitch-emote" src="https://static-cdn.jtvnw.net/emoticons/v2/58127/default/dark/1.0">
|
|
89
88
|
```
|
|
90
89
|
|
|
@@ -93,8 +92,8 @@ console.log(parser.parse('Hello CoolCat!')) // <- Doesn't require :colons: and r
|
|
|
93
92
|
|
|
94
93
|
## Prerequisites
|
|
95
94
|
|
|
96
|
-
To fetch "native" Twitch
|
|
97
|
-
If you are only using BetterTTV, FrankerFaceZ and 7TV you
|
|
95
|
+
To fetch "native" emotes from Twitch.tv, you need to [create an app here](https://dev.twitch.tv/console/apps/create), it is free.
|
|
96
|
+
If you are only using BetterTTV, FrankerFaceZ and 7TV you do not need to provide Twitch app keys.
|
|
98
97
|
|
|
99
98
|
You must use a Twitch user ID instead of the username to fetch users' emotes.
|
|
100
99
|
You can use [this page to manually convert them](https://s.kdy.ch/twitchid/).
|
|
@@ -122,13 +121,13 @@ npx jsr add @mkody/twitch-emoticons
|
|
|
122
121
|
pnpm add jsr:@mkody/twitch-emoticons
|
|
123
122
|
# or
|
|
124
123
|
yarn add jsr:@mkody/twitch-emoticons
|
|
125
|
-
# or (version has to be specified while it
|
|
126
|
-
deno add jsr:@mkody/twitch-emoticons@3.0.0-beta.
|
|
124
|
+
# or (version has to be specified while it is a pre-release)
|
|
125
|
+
deno add jsr:@mkody/twitch-emoticons@3.0.0-beta.3
|
|
127
126
|
```
|
|
128
127
|
|
|
129
|
-
[npm]: https://www.npmjs.com/package/@mkody/twitch-emoticons/v/3.0.0-beta.
|
|
130
|
-
[browse on npmx]: https://npmx.dev/package/@mkody/twitch-emoticons/v/3.0.0-beta.
|
|
131
|
-
[jsr]: https://jsr.io/@mkody/twitch-emoticons@3.0.0-beta.
|
|
128
|
+
[npm]: https://www.npmjs.com/package/@mkody/twitch-emoticons/v/3.0.0-beta.3
|
|
129
|
+
[browse on npmx]: https://npmx.dev/package/@mkody/twitch-emoticons/v/3.0.0-beta.3
|
|
130
|
+
[jsr]: https://jsr.io/@mkody/twitch-emoticons@3.0.0-beta.3
|
|
132
131
|
|
|
133
132
|
|
|
134
133
|
## Quick docs
|
|
@@ -136,7 +135,7 @@ deno add jsr:@mkody/twitch-emoticons@3.0.0-beta.1
|
|
|
136
135
|
<details>
|
|
137
136
|
<summary>Click here to toggle the docs</summary>
|
|
138
137
|
|
|
139
|
-
Here
|
|
138
|
+
Here is some quick documentation to explain our two classes, the principal methods, and some settings.
|
|
140
139
|
|
|
141
140
|
> **NOTE:**
|
|
142
141
|
> If you want a more complete documentation, see: https://mkody.github.io/twitch-emoticons/
|
|
@@ -148,18 +147,19 @@ First, you need to load a list of emotes, and for that you create a new `EmoteFe
|
|
|
148
147
|
|
|
149
148
|
```js
|
|
150
149
|
const fetcher = new EmoteFetcher({
|
|
151
|
-
// If you want to use emotes from twitch.tv, you
|
|
150
|
+
// If you want to use emotes from twitch.tv, you will need to be authenticated to use their API.
|
|
152
151
|
// Option 1: Provide your app ID and secret here (get them at https://dev.twitch.tv/console/apps).
|
|
153
152
|
twitchAppID, // <string>
|
|
154
153
|
twitchAppSecret, // <string>
|
|
155
|
-
// Option 2: If you need a different way to auth or already use `@twurple/api`,
|
|
154
|
+
// Option 2: If you need a different way to auth or already use `@twurple/api`,
|
|
155
|
+
// you can provide your ApiClient object here.
|
|
156
156
|
apiClient, // <ApiClient>
|
|
157
157
|
|
|
158
158
|
// Force emotes to be static (non-animated).
|
|
159
159
|
forceStatic, // <boolean> - Default: false
|
|
160
160
|
|
|
161
161
|
// Theme mode (background color) preference for Twitch emotes.
|
|
162
|
-
twitchThemeMode // <'dark' | 'light'> - Default: 'dark'
|
|
162
|
+
twitchThemeMode, // <'dark' | 'light'> - Default: 'dark'
|
|
163
163
|
})
|
|
164
164
|
```
|
|
165
165
|
|
|
@@ -173,7 +173,7 @@ There is one method per platform; all of them return Promises (so you can use `a
|
|
|
173
173
|
- `fetcher.fetchSevenTVEmotes()`
|
|
174
174
|
|
|
175
175
|
The first parameter is the Twitch user ID of the channel you want to load emotes from.
|
|
176
|
-
If not provided or it
|
|
176
|
+
If not provided or it is `null`/falsy, it loads what we call "global emotes", which are available to all users of the platform.
|
|
177
177
|
|
|
178
178
|
Do note that `fetchSevenTVEmotes()` accepts a second parameter with an object:
|
|
179
179
|
|
|
@@ -191,8 +191,8 @@ await fetcher.fetchSevenTVEmotes(null, { format: 'avif' }) // Example of loading
|
|
|
191
191
|
|
|
192
192
|
### Parse strings to include emotes with `EmoteParser`
|
|
193
193
|
|
|
194
|
-
And now that we have our list of emotes that we can expect to find,
|
|
195
|
-
|
|
194
|
+
And now that we have our list of emotes that we can expect to find, we should use it!
|
|
195
|
+
Create an `EmoteParser` object:
|
|
196
196
|
|
|
197
197
|
```js
|
|
198
198
|
const parser = new EmoteParser(
|
|
@@ -203,16 +203,18 @@ const parser = new EmoteParser(
|
|
|
203
203
|
{
|
|
204
204
|
// What output should be used when you parse messages? There are two ways to set that up:
|
|
205
205
|
// Option 1: Use one of the provided templates:
|
|
206
|
-
// -
|
|
207
|
-
// -
|
|
208
|
-
// -
|
|
209
|
-
// -
|
|
206
|
+
// - 'html': `<img alt="{name}" title="{name}" class="twitch-emote" src="{link}">`
|
|
207
|
+
// - 'markdown': ``
|
|
208
|
+
// - 'bbcode': `[img]{link}[/img]`
|
|
209
|
+
// - 'plain': `{link}`
|
|
210
210
|
type, // <'html' | 'markdown' | 'bbcode' | 'plain'> - Default: 'html'
|
|
211
|
-
// Option 2: Make your own template;
|
|
211
|
+
// Option 2: Make your own template; this has priority over option 1.
|
|
212
|
+
// You can use those: `{link}`, `{name}`, `{size}`, `{creator}`,
|
|
213
|
+
// `{is-animated}`, `{is-nsfw}`, `{is-zero-width}`.
|
|
212
214
|
template, // <string> - Default: ''
|
|
213
215
|
|
|
214
216
|
// You can customize the regular expression used to find possible emotes.
|
|
215
|
-
match, // <RegExp>
|
|
217
|
+
match, // <RegExp> - Default: /(\w+)/g
|
|
216
218
|
},
|
|
217
219
|
)
|
|
218
220
|
```
|
|
@@ -221,11 +223,20 @@ Now that you have an EmoteParser object, you can do two things with it:
|
|
|
221
223
|
look up an `Emote` or parse text and get the output as set by `type` or `template`.
|
|
222
224
|
|
|
223
225
|
To grab a specific emote, you can do `fetcher.emotes.get('...')`, with the case-sensitive name of the emote in place of the ellipsis.
|
|
224
|
-
From there, you can read properties like `.
|
|
225
|
-
but you can also use the `.toLink()`
|
|
226
|
+
From there, you can read properties like `.id`, `.code`, `.ownerName`,
|
|
227
|
+
`.animated`, `.imageType`, or `.type`, but you can also use the `.toLink()`
|
|
228
|
+
method to… get a link!
|
|
229
|
+
|
|
230
|
+
> Note: Some extended `Emote`s have additional properties:
|
|
231
|
+
> - FFZ:
|
|
232
|
+
> - `.zeroWidth` (boolean, can overlay an another emote)
|
|
233
|
+
> - `.modifier` (boolean, emote effects, should be hidden)
|
|
234
|
+
> - 7TV:
|
|
235
|
+
> - `.zeroWidth` (boolean, can overlay an another emote)
|
|
236
|
+
> - `.nsfw` (boolean, flagged "Sexual" or "Twitch disallowed")
|
|
226
237
|
|
|
227
238
|
To parse text, you use the `parser.parse()` method.
|
|
228
|
-
The first parameter is the input text. There
|
|
239
|
+
The first parameter is the input text. There is also an optional second parameter
|
|
229
240
|
where you can provide a few settings (which can overwrite the same ones set in the `EmoteFetcher`).
|
|
230
241
|
|
|
231
242
|
```js
|
|
@@ -235,19 +246,21 @@ const parsed = parser.parse(
|
|
|
235
246
|
|
|
236
247
|
// The second parameter is an *optional* object with the settings.
|
|
237
248
|
{
|
|
238
|
-
// Size (scale) for emotes.
|
|
249
|
+
// Size (scale) for emotes.
|
|
250
|
+
// It varies by provider, and not all share the same resolution in pixels.
|
|
251
|
+
// Play with this value if you would like, but no guarantees!
|
|
239
252
|
size, // <number>
|
|
240
253
|
|
|
241
254
|
// Force emotes to be static (non-animated).
|
|
242
|
-
forceStatic, // <boolean> - Default:
|
|
255
|
+
forceStatic, // <boolean> - Default: value in EmoteFetcher or false
|
|
243
256
|
|
|
244
257
|
// Theme mode (background color) preference for Twitch emotes.
|
|
245
|
-
twitchThemeMode // <'dark' | 'light'> - Default:
|
|
258
|
+
twitchThemeMode // <'dark' | 'light'> - Default: value in EmoteFetcher or 'dark'
|
|
246
259
|
},
|
|
247
260
|
)
|
|
248
261
|
```
|
|
249
262
|
|
|
250
|
-
And that
|
|
263
|
+
And that is it for the essentials!
|
|
251
264
|
You can go through the examples below if you need to see more complete code and direct usage.
|
|
252
265
|
|
|
253
266
|
</details>
|
|
@@ -325,14 +338,21 @@ const fetcher = new EmoteFetcher({
|
|
|
325
338
|
})
|
|
326
339
|
const parser = new EmoteParser(fetcher, {
|
|
327
340
|
// Custom HTML format
|
|
328
|
-
template:
|
|
329
|
-
|
|
330
|
-
|
|
341
|
+
template: `
|
|
342
|
+
<img
|
|
343
|
+
class="emote"
|
|
344
|
+
alt="{name}"
|
|
345
|
+
src="{link}"
|
|
346
|
+
data-scale="{size}"
|
|
347
|
+
data-animated="{is-animated}"
|
|
348
|
+
data-overlay="{is-zero-width}"
|
|
349
|
+
data-nsfw="{is-nsfw}"
|
|
350
|
+
>`,
|
|
331
351
|
// Matches words (like \w) but also dashes
|
|
332
352
|
match: /([a-zA-Z0-9_\-]+)/g,
|
|
333
353
|
})
|
|
334
354
|
|
|
335
|
-
// Fetch all emotes
|
|
355
|
+
// Fetch all the emotes we want and wait for everything to complete
|
|
336
356
|
Promise.all([
|
|
337
357
|
// Twitch global
|
|
338
358
|
fetcher.fetchTwitchEmotes(),
|
|
@@ -467,9 +487,9 @@ console.log(kappa)
|
|
|
467
487
|
|
|
468
488
|
### 6. 7TV formats
|
|
469
489
|
|
|
470
|
-
7TV
|
|
490
|
+
7TV delivers emotes in either WEBP or AVIF.
|
|
471
491
|
|
|
472
|
-
By default we
|
|
492
|
+
By default we will return WEBP emotes, but you can override this.
|
|
473
493
|
|
|
474
494
|
```js
|
|
475
495
|
// (setup)
|
|
@@ -485,14 +505,14 @@ await fetcher.fetchSevenTVEmotes(44317909)
|
|
|
485
505
|
// ... which is currently the same as
|
|
486
506
|
await fetcher.fetchSevenTVEmotes(44317909, { format: 'webp' })
|
|
487
507
|
|
|
488
|
-
// Fetch
|
|
489
|
-
await fetcher.fetchSevenTVEmotes(
|
|
508
|
+
// Fetch Nerixyz's emotes in AVIF
|
|
509
|
+
await fetcher.fetchSevenTVEmotes(129546453, { format: 'avif' })
|
|
490
510
|
```
|
|
491
511
|
|
|
492
512
|
|
|
493
513
|
### 7. Export and import emote data
|
|
494
514
|
|
|
495
|
-
This can be useful to save the emotes in a cache or for offline
|
|
515
|
+
This can be useful to save the emotes in a cache or for offline access.
|
|
496
516
|
|
|
497
517
|
```js
|
|
498
518
|
// (setup)
|
|
@@ -503,7 +523,7 @@ const fetcher = new EmoteFetcher()
|
|
|
503
523
|
await fetcher.fetchSevenTVEmotes(null, { format: 'avif' })
|
|
504
524
|
|
|
505
525
|
// Then you can use .toObject() on an `Emote` to export its data.
|
|
506
|
-
// Here
|
|
526
|
+
// Here is a map to get them all in a single array.
|
|
507
527
|
const emotes = fetcher.emotes.map((emote) => emote.toObject())
|
|
508
528
|
|
|
509
529
|
// Later, with or without a fresh `EmoteFetcher`, you can use .fromObject() on the fetcher.
|
|
@@ -511,7 +531,7 @@ fetcher.fromObject(emotes)
|
|
|
511
531
|
```
|
|
512
532
|
|
|
513
533
|
> **NOTE:**
|
|
514
|
-
> For offline
|
|
534
|
+
> For offline access, you' will still need to download emotes and proxy their URLs.
|
|
515
535
|
|
|
516
536
|
</details>
|
|
517
537
|
|
|
@@ -527,4 +547,4 @@ This library uses the following:
|
|
|
527
547
|
- [Twurple](https://twurple.js.org/) and the [Twitch API](https://dev.twitch.tv/)
|
|
528
548
|
- [BetterTTV API](https://betterttv.com/developers/api)
|
|
529
549
|
- [FrankerFaceZ API](https://api.frankerfacez.com/docs/)
|
|
530
|
-
- [7TV API](https://
|
|
550
|
+
- [7TV API (v3 via GraphQL)](https://github.com/SevenTV/SevenTV/tree/main/apps/api/src/http/v3/gql)
|
package/dist/TwitchEmoticons.cjs
CHANGED
|
@@ -100,8 +100,56 @@ var Constants_default = {
|
|
|
100
100
|
CDN: (id, size = 0, forceStatic = false) => `https://cdn.betterttv.net/emote/${id}/${size + 1}x.${forceStatic ? "png" : "webp"}`
|
|
101
101
|
},
|
|
102
102
|
SevenTV: {
|
|
103
|
-
|
|
104
|
-
|
|
103
|
+
GQL: "https://7tv.io/v3/gql",
|
|
104
|
+
GlobalQuery: `
|
|
105
|
+
query GetGlobalEmotes($format: [ImageFormat!]) {
|
|
106
|
+
namedEmoteSet(name: GLOBAL) {
|
|
107
|
+
emotes {
|
|
108
|
+
id
|
|
109
|
+
name
|
|
110
|
+
flags
|
|
111
|
+
data {
|
|
112
|
+
name
|
|
113
|
+
flags
|
|
114
|
+
animated
|
|
115
|
+
host {
|
|
116
|
+
files(formats: $format) {
|
|
117
|
+
name
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
owner {
|
|
121
|
+
display_name
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}`,
|
|
127
|
+
ChannelQuery: `
|
|
128
|
+
query GetChannelEmotes($id: String!, $format: [ImageFormat!]) {
|
|
129
|
+
userByConnection(platform: TWITCH, id: $id) {
|
|
130
|
+
emote_sets(entitled: false) {
|
|
131
|
+
flags
|
|
132
|
+
emotes {
|
|
133
|
+
id
|
|
134
|
+
name
|
|
135
|
+
flags
|
|
136
|
+
data {
|
|
137
|
+
name
|
|
138
|
+
flags
|
|
139
|
+
animated
|
|
140
|
+
host {
|
|
141
|
+
files(formats: $format) {
|
|
142
|
+
name
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
owner {
|
|
146
|
+
display_name
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}`,
|
|
105
153
|
CDN: (id, format, size = 1, forceStatic = false) => `https://cdn.7tv.app/emote/${id}/${size}x${forceStatic ? "_static" : ""}.${format}`
|
|
106
154
|
},
|
|
107
155
|
FFZ: {
|
|
@@ -277,7 +325,7 @@ var Channel = class {
|
|
|
277
325
|
this.channel_id = id || null;
|
|
278
326
|
this.emotes = new Collection_default();
|
|
279
327
|
}
|
|
280
|
-
/* There are tests that those are returning Collections, but c8
|
|
328
|
+
/* There are tests that those are returning Collections, but c8 does not get it. */
|
|
281
329
|
/* c8 ignore start */
|
|
282
330
|
/**
|
|
283
331
|
* Fetches the BTTV emotes for this channel.
|
|
@@ -317,12 +365,12 @@ var FFZEmote = class _FFZEmote extends Emote_default {
|
|
|
317
365
|
this.type = "ffz";
|
|
318
366
|
}
|
|
319
367
|
_setup(data) {
|
|
320
|
-
super._setup(data);
|
|
321
368
|
this.code = data.name;
|
|
322
369
|
this.ownerName = "owner" in data ? data.owner.name : null;
|
|
323
370
|
this.sizes = "animated" in data ? Object.keys(data.animated) : Object.keys(data.urls);
|
|
324
371
|
this.animated = "animated" in data;
|
|
325
372
|
this.imageType = "animated" in data ? "webp" : "png";
|
|
373
|
+
this.zeroWidth = data.modifier && data.modifier_flags === 0;
|
|
326
374
|
this.modifier = data.modifier && (data.modifier_flags & 1) !== 0;
|
|
327
375
|
}
|
|
328
376
|
/**
|
|
@@ -353,6 +401,7 @@ var FFZEmote = class _FFZEmote extends Emote_default {
|
|
|
353
401
|
sizes: this.sizes,
|
|
354
402
|
ownerName: this.ownerName,
|
|
355
403
|
type: this.type,
|
|
404
|
+
zeroWidth: this.zeroWidth,
|
|
356
405
|
modifier: this.modifier
|
|
357
406
|
};
|
|
358
407
|
}
|
|
@@ -363,10 +412,13 @@ var FFZEmote = class _FFZEmote extends Emote_default {
|
|
|
363
412
|
* @returns {FFZEmote} - A FFZEmote instance.
|
|
364
413
|
*/
|
|
365
414
|
static fromObject(emoteObject, channel) {
|
|
366
|
-
const sizesObj = emoteObject.sizes.reduce(
|
|
367
|
-
acc
|
|
368
|
-
|
|
369
|
-
|
|
415
|
+
const sizesObj = emoteObject.sizes.reduce(
|
|
416
|
+
(acc, curr) => {
|
|
417
|
+
acc[curr] = curr;
|
|
418
|
+
return acc;
|
|
419
|
+
},
|
|
420
|
+
{}
|
|
421
|
+
);
|
|
370
422
|
return new _FFZEmote(
|
|
371
423
|
channel,
|
|
372
424
|
emoteObject.id,
|
|
@@ -376,8 +428,8 @@ var FFZEmote = class _FFZEmote extends Emote_default {
|
|
|
376
428
|
urls: sizesObj,
|
|
377
429
|
...emoteObject.animated ? { animated: sizesObj } : {},
|
|
378
430
|
owner: { name: emoteObject.ownerName },
|
|
379
|
-
modifier: emoteObject.modifier,
|
|
380
|
-
modifier_flags: emoteObject.modifier
|
|
431
|
+
modifier: emoteObject.zeroWidth || emoteObject.modifier,
|
|
432
|
+
modifier_flags: emoteObject.modifier ? 1 : 0
|
|
381
433
|
}
|
|
382
434
|
);
|
|
383
435
|
}
|
|
@@ -397,11 +449,41 @@ var SevenTVEmote = class _SevenTVEmote extends Emote_default {
|
|
|
397
449
|
this.type = "7tv";
|
|
398
450
|
}
|
|
399
451
|
_setup(data) {
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
452
|
+
const ActiveEmoteFlags = {
|
|
453
|
+
ZeroWidth: 1,
|
|
454
|
+
// 1 << 0
|
|
455
|
+
OverrideTwitchGlobal: 65536,
|
|
456
|
+
// 1 << 16
|
|
457
|
+
OverrideTwitchSubscriber: 131072,
|
|
458
|
+
// 1 << 17
|
|
459
|
+
OverrideBetterTTV: 262144
|
|
460
|
+
// 1 << 18
|
|
461
|
+
};
|
|
462
|
+
const EmoteFlags = {
|
|
463
|
+
Private: 1,
|
|
464
|
+
// 1 << 0
|
|
465
|
+
Authentic: 2,
|
|
466
|
+
// 1 << 1
|
|
467
|
+
ZeroWidth: 256,
|
|
468
|
+
// 1 << 8
|
|
469
|
+
Sexual: 65536,
|
|
470
|
+
// 1 << 16
|
|
471
|
+
Epilepsy: 131072,
|
|
472
|
+
// 1 << 17
|
|
473
|
+
Edgy: 262144,
|
|
474
|
+
// 1 << 18
|
|
475
|
+
TwitchDisallowed: 16777216
|
|
476
|
+
// 1 << 24
|
|
477
|
+
};
|
|
478
|
+
this.code = data.name || data.data.name;
|
|
479
|
+
this.ownerName = data.data.owner?.display_name || null;
|
|
480
|
+
this.sizes = data.data.host.files.map((el) => el.name.replace(/x\.(\w+)/, "")).sort((a, b) => Number(a) - Number(b));
|
|
481
|
+
if (this.sizes.length === 0) {
|
|
482
|
+
this.sizes = ["1", "2", "3", "4"];
|
|
483
|
+
}
|
|
484
|
+
this.animated = Boolean(data.data.animated);
|
|
485
|
+
this.nsfw = (data.data.flags & EmoteFlags.Sexual) !== 0 || (data.data.flags & EmoteFlags.TwitchDisallowed) !== 0;
|
|
486
|
+
this.zeroWidth = (data.flags & ActiveEmoteFlags.ZeroWidth) !== 0 || (data.data.flags & EmoteFlags.ZeroWidth) !== 0;
|
|
405
487
|
this.imageType = this.channel.format;
|
|
406
488
|
}
|
|
407
489
|
/**
|
|
@@ -428,6 +510,8 @@ var SevenTVEmote = class _SevenTVEmote extends Emote_default {
|
|
|
428
510
|
return {
|
|
429
511
|
...super.toObject(),
|
|
430
512
|
animated: this.animated,
|
|
513
|
+
nsfw: this.nsfw,
|
|
514
|
+
zeroWidth: this.zeroWidth,
|
|
431
515
|
sizes: this.sizes,
|
|
432
516
|
ownerName: this.ownerName,
|
|
433
517
|
type: this.type,
|
|
@@ -442,21 +526,22 @@ var SevenTVEmote = class _SevenTVEmote extends Emote_default {
|
|
|
442
526
|
*/
|
|
443
527
|
static fromObject(emoteObject, channel) {
|
|
444
528
|
const sizes = emoteObject.sizes.map((size) => {
|
|
445
|
-
return {
|
|
529
|
+
return { name: size };
|
|
446
530
|
});
|
|
531
|
+
const flags = (emoteObject.nsfw ? 65536 : 0) | (emoteObject.zeroWidth ? 256 : 0);
|
|
447
532
|
return new _SevenTVEmote(
|
|
448
533
|
channel,
|
|
449
534
|
emoteObject.id,
|
|
450
535
|
{
|
|
451
|
-
code: emoteObject.code,
|
|
452
536
|
name: emoteObject.code,
|
|
453
537
|
data: {
|
|
454
538
|
animated: emoteObject.animated,
|
|
455
|
-
|
|
456
|
-
display_name: emoteObject.ownerName
|
|
457
|
-
},
|
|
539
|
+
flags,
|
|
458
540
|
host: {
|
|
459
541
|
files: sizes
|
|
542
|
+
},
|
|
543
|
+
owner: {
|
|
544
|
+
display_name: emoteObject.ownerName
|
|
460
545
|
}
|
|
461
546
|
}
|
|
462
547
|
}
|
|
@@ -480,8 +565,8 @@ var TwitchEmote = class _TwitchEmote extends Emote_default {
|
|
|
480
565
|
_setup(data) {
|
|
481
566
|
super._setup(data);
|
|
482
567
|
this.set = data.emoticon_set;
|
|
483
|
-
this.animated = "animated"
|
|
484
|
-
this.imageType = "animated"
|
|
568
|
+
this.animated = data.formats?.includes("animated") || false;
|
|
569
|
+
this.imageType = data.formats?.includes("animated") ? "gif" : "png";
|
|
485
570
|
}
|
|
486
571
|
/**
|
|
487
572
|
* Gets the image link of the emote.
|
|
@@ -526,7 +611,7 @@ var TwitchEmote = class _TwitchEmote extends Emote_default {
|
|
|
526
611
|
code: emoteObject.code,
|
|
527
612
|
animated: emoteObject.animated,
|
|
528
613
|
emoticon_set: emoteObject.set,
|
|
529
|
-
formats: emoteObject.animated ?
|
|
614
|
+
formats: emoteObject.animated ? ["static", "animated"] : ["static"]
|
|
530
615
|
}
|
|
531
616
|
);
|
|
532
617
|
}
|
|
@@ -698,18 +783,30 @@ var EmoteFetcher = class {
|
|
|
698
783
|
* Gets the raw 7TV emotes data for a channel.
|
|
699
784
|
* @private
|
|
700
785
|
* @param {number} [id] - ID of the channel.
|
|
786
|
+
* @param {('webp'|'avif')} [format] - The type file format to use (webp/avif).
|
|
701
787
|
* @returns {Promise<object[]>} - A promise that resolves to an array of raw 7TV emote data.
|
|
702
788
|
*/
|
|
703
|
-
_getRawSevenTVEmotes(id) {
|
|
704
|
-
|
|
705
|
-
|
|
789
|
+
_getRawSevenTVEmotes(id, format) {
|
|
790
|
+
return fetch(
|
|
791
|
+
Constants_default.SevenTV.GQL,
|
|
792
|
+
{
|
|
793
|
+
method: "POST",
|
|
794
|
+
headers: {
|
|
795
|
+
"content-type": "application/json"
|
|
796
|
+
},
|
|
797
|
+
body: JSON.stringify({
|
|
798
|
+
query: id ? Constants_default.SevenTV.ChannelQuery : Constants_default.SevenTV.GlobalQuery,
|
|
799
|
+
variables: id ? { id: String(id), format: [format.toUpperCase()] } : { format: [format.toUpperCase()] }
|
|
800
|
+
})
|
|
801
|
+
}
|
|
802
|
+
).then((response) => response.json());
|
|
706
803
|
}
|
|
707
804
|
/**
|
|
708
805
|
* Converts and caches a raw 7TV emote.
|
|
709
806
|
* @private
|
|
710
807
|
* @param {number} channelId - ID of the channel.
|
|
711
808
|
* @param {object} data - Raw data.
|
|
712
|
-
* @param {
|
|
809
|
+
* @param {('webp'|'avif')} format - The type file format to use (webp/avif).
|
|
713
810
|
* @param {SevenTVEmote} [existingEmote] - Existing emote to cache.
|
|
714
811
|
* @returns {SevenTVEmote} - A SevenTVEmote instance.
|
|
715
812
|
*/
|
|
@@ -792,15 +889,10 @@ var EmoteFetcher = class {
|
|
|
792
889
|
const {
|
|
793
890
|
format = "webp"
|
|
794
891
|
} = options || {};
|
|
795
|
-
return this._getRawSevenTVEmotes(channel).then((rawEmotes) => {
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
}
|
|
800
|
-
} else {
|
|
801
|
-
for (const data of rawEmotes.emote_set.emotes) {
|
|
802
|
-
this._cacheSevenTVEmote(channel, data, format);
|
|
803
|
-
}
|
|
892
|
+
return this._getRawSevenTVEmotes(channel, format).then((rawEmotes) => {
|
|
893
|
+
const emoteItems = channel ? rawEmotes?.data?.userByConnection?.emote_sets?.find((set) => set.flags === 0)?.emotes : rawEmotes?.data?.namedEmoteSet?.emotes;
|
|
894
|
+
for (const data of Array.isArray(emoteItems) ? emoteItems : []) {
|
|
895
|
+
this._cacheSevenTVEmote(channel, data, format);
|
|
804
896
|
}
|
|
805
897
|
return this.channels.get(channel).emotes.filter((e) => e.type === "7tv");
|
|
806
898
|
});
|
|
@@ -914,7 +1006,7 @@ var EmoteParser = class {
|
|
|
914
1006
|
if (emote.modifier) return "";
|
|
915
1007
|
const template = this.options.template || Constants_default.Templates[this.options.type];
|
|
916
1008
|
const link = emote.toLink({ size, forceStatic, themeMode });
|
|
917
|
-
const res = template.replaceAll("{link}", link).replaceAll("{name}", emote.code).replaceAll("{size}", size).replaceAll("{creator}", emote.ownerName || "global");
|
|
1009
|
+
const res = template.replaceAll("{link}", link).replaceAll("{name}", emote.code).replaceAll("{size}", size).replaceAll("{creator}", emote.ownerName || "global").replaceAll("{is-animated}", emote.animated ? "true" : "false").replaceAll("{is-zero-width}", emote.zeroWidth ? "true" : "false").replaceAll("{is-nsfw}", emote.nsfw ? "true" : "false");
|
|
918
1010
|
return res;
|
|
919
1011
|
});
|
|
920
1012
|
return parsed;
|