From 50d5c77f8d2eda9b94243fee54316e127bc2d487 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 29 Nov 2025 10:23:55 +0000 Subject: [PATCH 1/3] fix: Corriger l'alignement vertical des emojis dans les stories Facebook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Le problème était causé par un calcul incorrect du positionnement des emojis lorsque textBaseline est défini à 'middle'. Le code calculait la position comme si le baseline était en mode standard (alphabetic), ce qui décalait les emojis verticalement. Changement: emojiY = y - (emojiSize / 2) au lieu de y - fontSize * 0.8 Cela centre correctement l'emoji autour du point Y qui représente le centre du texte en mode 'middle'. --- server/services/emojiRenderer.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/server/services/emojiRenderer.ts b/server/services/emojiRenderer.ts index 909dc03..ae9f190 100644 --- a/server/services/emojiRenderer.ts +++ b/server/services/emojiRenderer.ts @@ -110,11 +110,12 @@ export class EmojiRenderer { try { const emojiBuffer = await this.getEmojiImage(segment.url); const emojiImage = await loadImage(emojiBuffer); - - // Draw emoji slightly above baseline to align with text + + // Draw emoji centered vertically with text + // When textBaseline is 'middle', y represents the vertical center const emojiSize = fontSize; - const emojiY = y - fontSize * 0.8; // Adjust vertical position - + const emojiY = y - (emojiSize / 2); // Center the emoji around y + ctx.drawImage(emojiImage, currentX, emojiY, emojiSize, emojiSize); currentX += emojiSize; } catch (error) { From 53054ccd87b6f38e96c668304ec0651b5379b35d Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 29 Nov 2025 10:27:01 +0000 Subject: [PATCH 2/3] =?UTF-8?q?debug:=20Ajouter=20des=20logs=20d=C3=A9tail?= =?UTF-8?q?l=C3=A9s=20pour=20diagnostiquer=20le=20probl=C3=A8me=20d'emojis?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ajout de logs pour tracer: - Le parsing des emojis (combien détectés, URLs générées) - Le téléchargement des images (succès/échec, codes HTTP) - Le rendu final (succès/erreur avec détails) Cela permettra d'identifier si le problème vient de: - URLs Twemoji incorrectes - Échec de téléchargement depuis le CDN - Problème de chargement/décodage de l'image --- server/services/emojiRenderer.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/server/services/emojiRenderer.ts b/server/services/emojiRenderer.ts index ae9f190..648c880 100644 --- a/server/services/emojiRenderer.ts +++ b/server/services/emojiRenderer.ts @@ -19,6 +19,8 @@ export class EmojiRenderer { */ private parseTextWithEmojis(text: string): EmojiSegment[] { const emojis = parse(text); + console.log(`📝 Parse texte: "${text}" => ${emojis.length} emoji(s) trouvé(s)`); + if (emojis.length === 0) { return [{ type: 'text', content: text }]; } @@ -27,6 +29,8 @@ export class EmojiRenderer { let lastIndex = 0; for (const emoji of emojis) { + console.log(` - Emoji détecté: "${emoji.text}" => URL: ${emoji.url}`); + // Add text before emoji if (emoji.indices[0] > lastIndex) { const textContent = text.substring(lastIndex, emoji.indices[0]); @@ -64,7 +68,15 @@ export class EmojiRenderer { return this.emojiCache.get(url)!; } + console.log('🔍 Téléchargement emoji depuis:', url); const response = await fetch(url); + + if (!response.ok) { + console.error(`❌ Erreur téléchargement emoji: ${response.status} ${response.statusText}`); + throw new Error(`Failed to fetch emoji: ${response.status}`); + } + + console.log('✅ Emoji téléchargé avec succès'); const buffer = Buffer.from(await response.arrayBuffer()); this.emojiCache.set(url, buffer); return buffer; @@ -118,8 +130,10 @@ export class EmojiRenderer { ctx.drawImage(emojiImage, currentX, emojiY, emojiSize, emojiSize); currentX += emojiSize; + console.log(`✅ Emoji "${segment.content}" dessiné avec succès`); } catch (error) { - console.error('Error loading emoji:', error); + console.error(`❌ Erreur lors du chargement/rendu de l'emoji "${segment.content}":`, error); + console.error(' URL:', segment.url); // Fallback: draw text representation ctx.fillText(segment.content, currentX, y); currentX += ctx.measureText(segment.content).width; From 4506c2b7c4542e4026e996e53eb958fb9a44a2d1 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 29 Nov 2025 10:35:09 +0000 Subject: [PATCH 3/3] fix: Corriger l'affichage des emojis dans les stories Facebook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problème: Les emojis s'affichaient comme des carrés bizarres dans les stories publiées sur Facebook (alors que la prévisualisation fonctionnait). Cause: Le téléchargement des images emoji depuis le CDN Twemoji par défaut échouait lors de la génération de l'image de story côté serveur. Solution: 1. Utilisation d'un CDN plus fiable (jsDelivr) au lieu du CDN Twemoji par défaut 2. Ajout d'une logique de retry (3 tentatives avec exponential backoff) 3. Ajout d'un timeout de 10 secondes pour éviter les blocages 4. Meilleure gestion des erreurs avec logs détaillés 5. Cache des emojis téléchargés pour améliorer les performances Les emojis devraient maintenant s'afficher correctement dans les stories Facebook publiées depuis l'application. --- server/services/emojiRenderer.ts | 77 ++++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 18 deletions(-) diff --git a/server/services/emojiRenderer.ts b/server/services/emojiRenderer.ts index 648c880..e17cb57 100644 --- a/server/services/emojiRenderer.ts +++ b/server/services/emojiRenderer.ts @@ -19,7 +19,10 @@ export class EmojiRenderer { */ private parseTextWithEmojis(text: string): EmojiSegment[] { const emojis = parse(text); - console.log(`📝 Parse texte: "${text}" => ${emojis.length} emoji(s) trouvé(s)`); + + if (emojis.length > 0) { + console.log(`📝 Texte avec ${emojis.length} emoji(s) détecté(s)`); + } if (emojis.length === 0) { return [{ type: 'text', content: text }]; @@ -29,8 +32,6 @@ export class EmojiRenderer { let lastIndex = 0; for (const emoji of emojis) { - console.log(` - Emoji détecté: "${emoji.text}" => URL: ${emoji.url}`); - // Add text before emoji if (emoji.indices[0] > lastIndex) { const textContent = text.substring(lastIndex, emoji.indices[0]); @@ -61,25 +62,67 @@ export class EmojiRenderer { } /** - * Download and cache emoji image + * Convert default Twemoji URL to jsDelivr CDN (more reliable) + * Example: https://twemoji.maxcdn.com/v/latest/72x72/1f600.png + * Becomes: https://cdn.jsdelivr.net/gh/twitter/twemoji@latest/assets/72x72/1f600.png + */ + private convertToReliableCDN(url: string): string { + // Extract the emoji filename (e.g., "1f600.png") + const match = url.match(/\/([a-f0-9\-]+\.png)$/i); + if (!match) return url; + + const filename = match[1]; + // Use jsDelivr CDN which is more reliable + return `https://cdn.jsdelivr.net/gh/twitter/twemoji@latest/assets/72x72/${filename}`; + } + + /** + * Download and cache emoji image with retry logic */ private async getEmojiImage(url: string): Promise { - if (this.emojiCache.has(url)) { - return this.emojiCache.get(url)!; + // Use reliable CDN URL + const reliableUrl = this.convertToReliableCDN(url); + + if (this.emojiCache.has(reliableUrl)) { + return this.emojiCache.get(reliableUrl)!; } - console.log('🔍 Téléchargement emoji depuis:', url); - const response = await fetch(url); + console.log('🔍 Téléchargement emoji depuis:', reliableUrl); - if (!response.ok) { - console.error(`❌ Erreur téléchargement emoji: ${response.status} ${response.statusText}`); - throw new Error(`Failed to fetch emoji: ${response.status}`); + // Retry logic: try up to 3 times + let lastError: Error | null = null; + for (let attempt = 1; attempt <= 3; attempt++) { + try { + const controller = new AbortController(); + const timeout = setTimeout(() => controller.abort(), 10000); // 10 second timeout + + const response = await fetch(reliableUrl, { + signal: controller.signal + }); + + clearTimeout(timeout); + + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + + console.log('✅ Emoji téléchargé avec succès'); + const buffer = Buffer.from(await response.arrayBuffer()); + this.emojiCache.set(reliableUrl, buffer); + return buffer; + } catch (error) { + lastError = error as Error; + console.warn(`⚠️ Tentative ${attempt}/3 échouée:`, error instanceof Error ? error.message : error); + + if (attempt < 3) { + // Wait before retry (exponential backoff: 500ms, 1000ms) + await new Promise(resolve => setTimeout(resolve, attempt * 500)); + } + } } - console.log('✅ Emoji téléchargé avec succès'); - const buffer = Buffer.from(await response.arrayBuffer()); - this.emojiCache.set(url, buffer); - return buffer; + console.error(`❌ Échec téléchargement emoji après 3 tentatives:`, lastError); + throw lastError || new Error('Failed to fetch emoji'); } /** @@ -130,10 +173,8 @@ export class EmojiRenderer { ctx.drawImage(emojiImage, currentX, emojiY, emojiSize, emojiSize); currentX += emojiSize; - console.log(`✅ Emoji "${segment.content}" dessiné avec succès`); } catch (error) { - console.error(`❌ Erreur lors du chargement/rendu de l'emoji "${segment.content}":`, error); - console.error(' URL:', segment.url); + console.error(`❌ Impossible de charger l'emoji "${segment.content}":`, error instanceof Error ? error.message : error); // Fallback: draw text representation ctx.fillText(segment.content, currentX, y); currentX += ctx.measureText(segment.content).width;