Skip to content

Commit 94cf6a2

Browse files
committed
feat(chat): GIFs in Dashboard
1 parent 2d92185 commit 94cf6a2

7 files changed

Lines changed: 69 additions & 6 deletions

File tree

‎src/backend/chat/chat-helpers.ts‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ class FirebotChatHelpers {
246246
const sharedChatRoom = SharedChatCache.participants[sharedChatRoomId];
247247
const isSharedChatMessage = sharedChatRoomId != null && sharedChatRoomId !== AccountAccess.getAccounts().streamer.userId;
248248
const isGigantified = msg.tags.get("msg-id") === "gigantified-emote-message";
249+
const isGif = msg.tags.has("gifs") && !!msg.tags.get("gifs")?.length;
249250
const firebotChatMessage: FirebotChatMessage = {
250251
id: msg.tags.get("id"),
251252
username: msg.userInfo.userName,
@@ -258,6 +259,7 @@ class FirebotChatHelpers {
258259
isHiddenFromChatFeed: false,
259260
isReply: msg.tags.has("reply-parent-msg-id"),
260261
isGigantified: isGigantified,
262+
isGif: isGif,
261263
replyParentMessageId: msg.tags.get("reply-parent-msg-id"),
262264
replyParentMessageText: msg.tags.get("reply-parent-msg-body"),
263265
replyParentMessageSenderUserId: msg.tags.get("reply-parent-user-id"),
@@ -310,8 +312,10 @@ class FirebotChatHelpers {
310312
msg._params[1].value = msgText;
311313
}
312314

313-
const messageParts = this._parseMessageParts(firebotChatMessage,
314-
parseChatMessage(msgText, msg.emoteOffsets, TwitchEventSubChatHelpers.twitchCheermotes?.getPossibleNames()));
315+
const messageParts = firebotChatMessage.isGif === true
316+
? [{ type: "gif", text: msgText, url: msg.tags.get("gifs").split("|")[2] } as FirebotParsedMessagePart]
317+
: this._parseMessageParts(firebotChatMessage,
318+
parseChatMessage(msgText, msg.emoteOffsets, TwitchEventSubChatHelpers.twitchCheermotes?.getPossibleNames()));
315319

316320
firebotChatMessage.parts = messageParts;
317321

‎src/backend/streaming-platforms/twitch/api/eventsub/eventsub-chat-helpers.ts‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import type {
1616
EventSubChatMessageCheermote,
1717
EventSubChatMessageCheermotePart,
1818
EventSubChatMessageEmotePart,
19+
EventSubChatMessageGifPart,
1920
EventSubChatMessageMentionPart,
2021
EventSubChatMessagePart
2122
} from "../twurple-private-types";
@@ -25,6 +26,7 @@ import type {
2526
FirebotChatMessage,
2627
FirebotChatMessageCheermotePart,
2728
FirebotChatMessageEmotePart,
29+
FirebotChatMessageGifPart,
2830
FirebotChatMessageMentionPart,
2931
FirebotChatMessagePart,
3032
FirebotChatMessageTextPart,
@@ -396,6 +398,14 @@ class TwitchEventSubChatHelpers {
396398
(p as EventSubChatMessageMentionPart)
397399
);
398400
break;
401+
402+
case "gif":
403+
this.parseEventSubGif(
404+
part,
405+
(p as EventSubChatMessageGifPart),
406+
message.rawText
407+
);
408+
break;
399409
}
400410

401411
return part;
@@ -478,6 +488,16 @@ class TwitchEventSubChatHelpers {
478488
part.userDisplayName = mentionPart.mention.user_name;
479489
}
480490

491+
private parseEventSubGif(
492+
part: FirebotChatMessageGifPart,
493+
gifPart: EventSubChatMessageGifPart,
494+
text: string
495+
): void {
496+
part.url = gifPart.gif.url;
497+
part.id = gifPart.gif.gif_id;
498+
part.text = text;
499+
}
500+
481501
private parseChatBadges(badgeData: Record<string, string>): ChatBadge[] {
482502
if (this._badgeCache == null) {
483503
return [];

‎src/backend/streaming-platforms/twitch/api/resource/chat.ts‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,12 @@ export class TwitchChatApi extends ApiResourceBase {
555555
userLogin: f.mention.user_login,
556556
userName: f.mention.user_name
557557
}
558+
: null,
559+
gif: f.type === "gif"
560+
? {
561+
gifId: f.gif.gif_id,
562+
url: f.gif.url
563+
}
558564
: null
559565
};
560566
})

‎src/backend/streaming-platforms/twitch/api/twurple-private-types.d.ts‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,18 @@ export interface EventSubChatMessageMentionPart {
4444
mention: EventSubChatMessageMention;
4545
}
4646

47-
export type EventSubChatMessagePart = EventSubChatMessageTextPart | EventSubChatMessageCheermotePart | EventSubChatMessageEmotePart | EventSubChatMessageMentionPart;
47+
export interface EventSubChatMessageGif {
48+
gif_id: string;
49+
url: string;
50+
}
51+
52+
export interface EventSubChatMessageGifPart {
53+
type: 'gif';
54+
text: string;
55+
gif: EventSubChatMessageGif;
56+
}
57+
58+
export type EventSubChatMessagePart = EventSubChatMessageTextPart | EventSubChatMessageCheermotePart | EventSubChatMessageEmotePart | EventSubChatMessageMentionPart | EventSubChatMessageGifPart;
4859

4960
export type EventSubChannelBitsUseMessagePart = EventSubChatMessageTextPart | EventSubChatMessageCheermotePart | EventSubChatMessageEmotePart;
5061

‎src/gui/app/directives/chat/feed items/chat-message.js‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@
178178
{{$ctrl.message.timestampDisplay}}
179179
</span>
180180
</div>
181-
<div class="chatContent" ng-class="{ gigantify: $ctrl.message.isGigantified }">
181+
<div class="chatContent" ng-class="{ gigantify: $ctrl.message.isGigantified, 'chat-gif': $ctrl.message.isGif }">
182182
<span ng-repeat="part in $ctrl.message.parts" class="chat-content-wrap">
183183
184184
<span ng-if="part.type === 'text'" style="{{$ctrl.chatSizeStyle}}{{$ctrl.fontFamilyStyle}}" ng-class="{ highlightText: part.flagged }">{{part.text}}</span>
@@ -235,6 +235,15 @@
235235
<img ng-src="{{part.url}}" style="height: 100%;" alt="{{part.name || part.text || ''}}" />
236236
</span>
237237
<span ng-if="part.origin === '7TV' && !$ctrl.showSevenTvEmotes" style="{{$ctrl.chatSizeStyle}}{{$ctrl.fontFamilyStyle}}">{{part.name}}</span>
238+
239+
<span
240+
ng-if="part.type === 'gif'"
241+
class="gif-image"
242+
uib-tooltip="GIF: {{part.text}}"
243+
tooltip-append-to-body="true"
244+
>
245+
<img ng-src="{{part.url}}" style="height: 100%;" alt="{{part.text}}" />
246+
</span>
238247
</span>
239248
</div>
240249
<div ng-show="$ctrl.message.whisper" class="muted">(Whispered to {{ $ctrl.message.whisperTarget }})</div>

‎src/gui/scss/core/_chat.scss‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,11 @@
255255
height: 8rem !important;
256256
}
257257

258+
.chat-gif :last-child > .gif-image {
259+
display: block !important;
260+
height: 16rem !important;
261+
}
262+
258263
.chat-username {
259264
display: flex;
260265
font-weight: bold;

‎src/types/chat.ts‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ type FirebotChatMessagePartType =
44
| "emote"
55
| "third-party-emote"
66
| "cheermote"
7-
| "mention";
7+
| "mention"
8+
| "gif";
89

910
type FirebotChatMessagePartBase = {
1011
type: FirebotChatMessagePartType;
@@ -46,12 +47,18 @@ export type FirebotChatMessageMentionPart = FirebotChatMessagePartBase & {
4647
userDisplayName: string;
4748
};
4849

50+
export type FirebotChatMessageGifPart = FirebotChatMessagePartBase & {
51+
type: "gif";
52+
url: string;
53+
};
54+
4955
export type FirebotChatMessagePart =
5056
| FirebotChatMessageTextPart
5157
| FirebotChatMessageLinkPart
5258
| FirebotChatMessageEmotePart
5359
| FirebotChatMessageCheermotePart
54-
| FirebotChatMessageMentionPart;
60+
| FirebotChatMessageMentionPart
61+
| FirebotChatMessageGifPart;
5562

5663
export type FirebotParsedMessagePart = {
5764
type: string;
@@ -144,6 +151,7 @@ export type FirebotChatMessage = {
144151
imageUrl: string;
145152
};
146153
isGigantified?: boolean;
154+
isGif?: boolean;
147155
};
148156

149157
export type FirebotEmote = {

0 commit comments

Comments
 (0)