@@ -6,6 +6,7 @@ const showTwitch = getURLParam("showTwitch", false);
66
77const showTwitchMessages = getURLParam ( "showTwitchMessages" , true ) ;
88const showTwitchFollows = getURLParam ( "showTwitchFollows" , true ) ;
9+ const showTwitchWatchStreak = getURLParam ( "showTwitchWatchStreak" , false ) ;
910const showTwitchBits = getURLParam ( "showTwitchBits" , true ) ;
1011const showTwitchAnnouncements = getURLParam ( "showTwitchAnnouncements" , true ) ;
1112const showTwitchSubs = getURLParam ( "showTwitchSubs" , true ) ;
@@ -47,6 +48,9 @@ const twitchMessageHandlers = {
4748 'Twitch.ChatMessage' : ( response ) => {
4849 twitchChatMessage ( response . data ) ;
4950 } ,
51+ 'Twitch.WatchStreak' : ( response ) => {
52+ twitchWatchStreakMessage ( response . data ) ;
53+ } ,
5054 'Twitch.Follow' : ( response ) => {
5155 twitchFollowMessage ( response . data ) ;
5256 } ,
@@ -256,6 +260,44 @@ async function twitchChatMessage(data) {
256260
257261
258262
263+
264+ async function twitchWatchStreakMessage ( data ) {
265+
266+ if ( showTwitchWatchStreak == false ) return ;
267+
268+ const template = eventTemplate ;
269+ const clone = template . content . cloneNode ( true ) ;
270+ const messageId = data . msgId ;
271+ const userId = data . userName . toLowerCase ( ) ;
272+
273+ const {
274+ header,
275+ platform,
276+ user,
277+ action,
278+ value,
279+ 'actual-message' : message
280+ } = Object . fromEntries (
281+ [ ...clone . querySelectorAll ( '[class]' ) ]
282+ . map ( el => [ el . className , el ] )
283+ ) ;
284+
285+ const classes = [ 'twitch' , 'watch-streak' ] ;
286+
287+ header . remove ( ) ;
288+
289+ user . textContent = data . displayName ;
290+
291+ action . innerHTML = ` watched ` ;
292+ value . innerHTML = `<strong>${ data . watchStreak } consecutive streams</strong> this month` ;
293+ message . textContent = data . message ;
294+ await getTwitchEmotesForWatchedStreakMessage ( data , message ) ;
295+
296+ addEventItem ( 'twitch' , clone , classes , userId , messageId ) ;
297+ }
298+
299+
300+
259301async function twitchChatMessageGiantEmote ( data ) {
260302
261303 if ( showTwitchMessages == false ) return ;
@@ -899,6 +941,61 @@ async function getTwitchEmotes(data, messageElement) {
899941
900942
901943
944+ async function getTwitchEmotesForWatchedStreakMessage ( data , messageElement ) {
945+ const message = data . message ;
946+ const emotes = ( data . emotes || [ ] ) . sort ( ( a , b ) => a . startIndex - b . startIndex ) ;
947+
948+ // Limpa o conteúdo (vamos recriar com nodes)
949+ messageElement . innerHTML = "" ;
950+
951+ let lastIndex = 0 ;
952+
953+ for ( const emote of emotes ) {
954+ // texto antes do emote
955+ if ( lastIndex < emote . startIndex ) {
956+ const text = message . slice ( lastIndex , emote . startIndex ) ;
957+ messageElement . appendChild ( document . createTextNode ( text ) ) ;
958+ }
959+
960+ let emoteUrl = emote . imageUrl ;
961+
962+ // Detecta Twemoji
963+ const isTwemoji =
964+ String ( emote . type || "" ) . toLowerCase ( ) === "twemoji" ||
965+ / ( t w e m o j i | j d e c k e d ) / i. test ( emote . imageUrl || "" ) ;
966+
967+ if ( isTwemoji ) {
968+ const codePoints = Array . from ( emote . name ) . map ( c => c . codePointAt ( 0 ) . toString ( 16 ) ) ;
969+ let fileName = codePoints . join ( "-" ) ;
970+ fileName = fileName . replace ( / - f e 0 f / g, "" ) ; // remove FE0F
971+ emoteUrl = `https://cdn.jsdelivr.net/gh/twitter/[email protected] /assets/72x72/${ fileName } .png` ; 972+ }
973+
974+ if ( ! emoteUrl || emoteUrl . trim ( ) === "" ) {
975+ messageElement . appendChild ( document . createTextNode ( emote . name ) ) ;
976+ }
977+ else {
978+ const img = document . createElement ( "img" ) ;
979+ img . src = emoteUrl ;
980+ img . alt = emote . name ;
981+ img . className = "emote" ;
982+ img . dataset . emoteId = emote . id || "" ;
983+ img . onerror = ( ) => ( img . outerHTML = emote . name ) ;
984+ messageElement . appendChild ( img ) ;
985+ }
986+
987+ lastIndex = emote . endIndex + 1 ;
988+ }
989+
990+ // texto final depois do último emote
991+ if ( lastIndex < message . length ) {
992+ const text = message . slice ( lastIndex ) ;
993+ messageElement . appendChild ( document . createTextNode ( text ) ) ;
994+ }
995+ }
996+
997+
998+
902999
9031000
9041001async function getTwitchEmotesOnParts ( data , messageElement ) {
0 commit comments