@@ -14,10 +14,6 @@ import { CLIP_COMPONENT, ERROR_COMPONENT } from './components.js';
1414 * @returns {Promise<Buffer> } - The screenshot image buffer.
1515 */
1616async function generateMessageScreenshot ( interaction , env ) {
17- const targetId = interaction . data . target_id ;
18- const message = interaction . data . resolved . messages [ targetId ] ;
19- const member = interaction . data . resolved . members ?. [ message . author . id ] ;
20- const guildId = interaction . guild_id ;
2117 // Pick random session from open sessions
2218 let sessionId = await getRandomSession ( env . BROWSER ) ;
2319 let browser ;
@@ -49,92 +45,89 @@ async function generateMessageScreenshot(interaction, env) {
4945 url : 'https://cdn.jsdelivr.net/npm/@twemoji/api@latest/dist/twemoji.min.js' ,
5046 } ) ;
5147
52- await page . evaluate (
53- ( message , member , guildId ) => {
54- const author = message . author ;
55- const username = member ?. nick || author . global_name || author . username ;
56- const defaultUserAvatarIndex = author . discriminator
57- ? Number ( author . discriminator ) % 5 // Legacy username system
58- : ( BigInt ( author . id ) >> 22n ) % 6n ; // New username system
59- const userAvatar =
60- member ?. avatar && guildId
61- ? `https://cdn.discordapp.com/guilds/${ guildId } /users/${ author . id } /avatars/${ member . avatar } .webp`
62- : author . avatar
63- ? `https://cdn.discordapp.com/avatars/${ author . id } /${ author . avatar } .webp`
64- : `https://cdn.discordapp.com/embed/avatars/${ defaultUserAvatarIndex } .png` ;
65- const effectiveAvatarDecoration =
66- member ?. avatar_decoration_data || author . avatar_decoration_data ;
67- const avatarDecoration = effectiveAvatarDecoration
68- ? `https://cdn.discordapp.com/avatar-decoration-presets/${ effectiveAvatarDecoration . asset } .png?passthrough=false`
69- : '' ;
70- const serverTag = author . clan ?. tag || '' ;
71- const serverTagBadge = author . clan
72- ? `https://cdn.discordapp.com/guild-tag-badges/${ author . clan . identity_guild_id } /${ author . clan . badge } .webp`
73- : '' ;
74- const botTag = author . bot ;
75-
76- // TODO: Move this parsing to a separate function/module
77- // Parse message content and replace markdown with HTML
78- const messageContent = message . content
79- . replace (
80- / < a ? : ( [ ^ : > ] + ) : ( \d + ) > / g,
81- '<img src="https://cdn.discordapp.com/emojis/$2.webp" alt="$1" class="emoji">' ,
82- ) // custom emojis
83- . replace ( / ^ # # # ( .+ ) $ / gm, '<h3>$1</h3>' ) // ### header 3
84- . replace ( / ^ # # ( .+ ) $ / gm, '<h2>$1</h2>' ) // ## header 2
85- . replace ( / ^ # ( .+ ) $ / gm, '<h1>$1</h1>' ) // # header 1
86- . replace ( / ^ - # ( .+ ) $ / gm, '<small>$1</small>' ) // -# subtext
87- . replace ( / ^ > ( .+ ) $ / gm, '<blockquote>$1</blockquote>' ) // > blockquote
88- . replace ( / \[ ( [ ^ \] ] + ) \] \( ( [ ^ ) ] + ) \) / g, '<a href="$2">$1</a>' ) // [text](url)
89- . replace ( / \* \* ( .+ ?) \* \* / g, '<strong>$1</strong>' ) // **bold**
90- . replace ( / _ _ ( .+ ?) _ _ / g, '<u>$1</u>' ) // __underline__
91- . replace ( / ( \* | _ ) ( .+ ?) \1/ g, '<em>$2</em>' ) // *italic* or _italic_
92- . replace ( / \| \| ( .+ ?) \| \| / g, '<span class="spoiler">$1</span>' ) // ||spoiler||
93- . replace ( / ~ ~ ( .+ ?) ~ ~ / g, '<del>$1</del>' ) // ~~strikethrough~~
94- . replace ( / ` ` ` ( [ ^ ` ] + ?) ` ` ` / g, '<pre>$1</pre>' ) // ```code block```
95- . replace ( / ` ( [ ^ ` ] + ) ` / g, '<code>$1</code>' ) // `inline code`
96- . replace ( / \n / g, '<br>' ) ; // change \n to <br> for line breaks
97-
98- const avatarElement = document . querySelector ( '.avatar' ) ;
99- avatarElement . setAttribute ( 'src' , userAvatar ) ;
100-
101- const avatarDecorationElement =
102- document . querySelector ( '.avatar-decoration' ) ;
103- avatarDecorationElement . setAttribute ( 'src' , avatarDecoration ) ;
104-
105- const usernameElement = document . querySelector ( '.username' ) ;
106- usernameElement . firstChild . textContent = username ;
107-
108- const serverTagElement = document . getElementById ( 'server-tag' ) ;
109- if ( serverTag ) {
110- serverTagElement . querySelector ( 'span' ) . textContent = serverTag ;
111- serverTagElement
112- . querySelector ( 'img' )
113- . setAttribute ( 'src' , serverTagBadge ) ;
114- } else {
115- serverTagElement . style . display = 'none' ;
116- }
117-
118- const botTagElement = document . getElementById ( 'bot-tag' ) ;
119- if ( ! botTag ) {
120- botTagElement . style . display = 'none' ;
121- }
122-
123- // Set message element
124- const messageElement = document . querySelector ( '.message' ) ;
125- messageElement . innerHTML = messageContent ;
126-
127- // Parse message element with Twemoji
128- const twemoji = window . twemoji ;
129- twemoji . parse ( messageElement , {
130- folder : 'svg' ,
131- ext : '.svg' ,
132- } ) ;
133- } ,
134- message ,
135- member ,
136- guildId ,
137- ) ;
48+ await page . evaluate ( ( interaction ) => {
49+ const targetId = interaction . data . target_id ;
50+ const message = interaction . data . resolved . messages [ targetId ] ;
51+ const member = interaction . data . resolved . members ?. [ message . author . id ] ;
52+ const guildId = interaction . guild_id ;
53+ const author = message . author ;
54+ const username = member ?. nick || author . global_name || author . username ;
55+ const defaultUserAvatarIndex = author . discriminator
56+ ? Number ( author . discriminator ) % 5 // Legacy username system
57+ : ( BigInt ( author . id ) >> 22n ) % 6n ; // New username system
58+ const userAvatar =
59+ member ?. avatar && guildId
60+ ? `https://cdn.discordapp.com/guilds/${ guildId } /users/${ author . id } /avatars/${ member . avatar } .webp`
61+ : author . avatar
62+ ? `https://cdn.discordapp.com/avatars/${ author . id } /${ author . avatar } .webp`
63+ : `https://cdn.discordapp.com/embed/avatars/${ defaultUserAvatarIndex } .png` ;
64+ const effectiveAvatarDecoration =
65+ member ?. avatar_decoration_data || author . avatar_decoration_data ;
66+ const avatarDecoration = effectiveAvatarDecoration
67+ ? `https://cdn.discordapp.com/avatar-decoration-presets/${ effectiveAvatarDecoration . asset } .png?passthrough=false`
68+ : '' ;
69+ const serverTag = author . clan ?. tag || '' ;
70+ const serverTagBadge = author . clan
71+ ? `https://cdn.discordapp.com/guild-tag-badges/${ author . clan . identity_guild_id } /${ author . clan . badge } .webp`
72+ : '' ;
73+ const botTag = author . bot ;
74+
75+ // TODO: Move this parsing to a separate function/module
76+ // Parse message content and replace markdown with HTML
77+ const messageContent = message . content
78+ . replace (
79+ / < a ? : ( [ ^ : > ] + ) : ( \d + ) > / g,
80+ '<img src="https://cdn.discordapp.com/emojis/$2.webp" alt="$1" class="emoji">' ,
81+ ) // custom emojis
82+ . replace ( / ^ # # # ( .+ ) $ / gm, '<h3>$1</h3>' ) // ### header 3
83+ . replace ( / ^ # # ( .+ ) $ / gm, '<h2>$1</h2>' ) // ## header 2
84+ . replace ( / ^ # ( .+ ) $ / gm, '<h1>$1</h1>' ) // # header 1
85+ . replace ( / ^ - # ( .+ ) $ / gm, '<small>$1</small>' ) // -# subtext
86+ . replace ( / ^ > ( .+ ) $ / gm, '<blockquote>$1</blockquote>' ) // > blockquote
87+ . replace ( / \[ ( [ ^ \] ] + ) \] \( ( [ ^ ) ] + ) \) / g, '<a href="$2">$1</a>' ) // [text](url)
88+ . replace ( / \* \* ( .+ ?) \* \* / g, '<strong>$1</strong>' ) // **bold**
89+ . replace ( / _ _ ( .+ ?) _ _ / g, '<u>$1</u>' ) // __underline__
90+ . replace ( / ( \* | _ ) ( .+ ?) \1/ g, '<em>$2</em>' ) // *italic* or _italic_
91+ . replace ( / \| \| ( .+ ?) \| \| / g, '<span class="spoiler">$1</span>' ) // ||spoiler||
92+ . replace ( / ~ ~ ( .+ ?) ~ ~ / g, '<del>$1</del>' ) // ~~strikethrough~~
93+ . replace ( / ` ` ` ( [ ^ ` ] + ?) ` ` ` / g, '<pre>$1</pre>' ) // ```code block```
94+ . replace ( / ` ( [ ^ ` ] + ) ` / g, '<code>$1</code>' ) // `inline code`
95+ . replace ( / \n / g, '<br>' ) ; // change \n to <br> for line breaks
96+
97+ const avatarElement = document . querySelector ( '.avatar' ) ;
98+ avatarElement . setAttribute ( 'src' , userAvatar ) ;
99+
100+ const avatarDecorationElement =
101+ document . querySelector ( '.avatar-decoration' ) ;
102+ avatarDecorationElement . setAttribute ( 'src' , avatarDecoration ) ;
103+
104+ const usernameElement = document . querySelector ( '.username' ) ;
105+ usernameElement . firstChild . textContent = username ;
106+
107+ const serverTagElement = document . getElementById ( 'server-tag' ) ;
108+ if ( serverTag ) {
109+ serverTagElement . querySelector ( 'span' ) . textContent = serverTag ;
110+ serverTagElement . querySelector ( 'img' ) . setAttribute ( 'src' , serverTagBadge ) ;
111+ } else {
112+ serverTagElement . style . display = 'none' ;
113+ }
114+
115+ const botTagElement = document . getElementById ( 'bot-tag' ) ;
116+ if ( ! botTag ) {
117+ botTagElement . style . display = 'none' ;
118+ }
119+
120+ // Set message element
121+ const messageElement = document . querySelector ( '.message' ) ;
122+ messageElement . innerHTML = messageContent ;
123+
124+ // Parse message element with Twemoji
125+ const twemoji = window . twemoji ;
126+ twemoji . parse ( messageElement , {
127+ folder : 'svg' ,
128+ ext : '.svg' ,
129+ } ) ;
130+ } , interaction ) ;
138131
139132 // Wait for images to load
140133 await page . waitForNetworkIdle ( ) ;
0 commit comments