@bebranded/bb-contents 1.0.84 → 1.0.86

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.
Files changed (2) hide show
  1. package/bb-contents.js +72 -30
  2. package/package.json +1 -1
package/bb-contents.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * BeBranded Contents
3
3
  * Contenus additionnels français pour Webflow
4
- * @version 1.0.84
4
+ * @version 1.0.86
5
5
  * @author BeBranded
6
6
  * @license MIT
7
7
  * @website https://www.bebranded.xyz
@@ -32,11 +32,11 @@
32
32
  window._bbContentsInitialized = true;
33
33
 
34
34
  // Log de démarrage simple (une seule fois)
35
- console.log('bb-contents | v1.0.84');
35
+ console.log('bb-contents | v1.0.86');
36
36
 
37
37
  // Configuration
38
38
  const config = {
39
- version: '1.0.84',
39
+ version: '1.0.86',
40
40
  debug: false, // Debug désactivé pour rendu propre
41
41
  prefix: 'bb-', // utilisé pour générer les sélecteurs (data-bb-*)
42
42
  youtubeEndpoint: null, // URL du worker YouTube (à définir par l'utilisateur)
@@ -385,13 +385,25 @@
385
385
  const totalImages = images.length;
386
386
 
387
387
 
388
- // Forcer le chargement de toutes les images
388
+ // OPTIMISATION: Charger les images sans forcer les dimensions
389
389
  images.forEach(img => {
390
390
  if (img.dataset.src && !img.src) {
391
391
  img.src = img.dataset.src;
392
392
  img.loading = 'eager';
393
393
  }
394
+
395
+ // OPTIMISATION: Préserver les styles CSS existants (object-fit, etc.)
396
+ const originalObjectFit = img.style.objectFit || getComputedStyle(img).objectFit;
397
+ const originalObjectPosition = img.style.objectPosition || getComputedStyle(img).objectPosition;
398
+
394
399
  img.onload = () => {
400
+ // OPTIMISATION: Restaurer les styles CSS après chargement
401
+ if (originalObjectFit && originalObjectFit !== 'none') {
402
+ img.style.objectFit = originalObjectFit;
403
+ }
404
+ if (originalObjectPosition && originalObjectPosition !== 'initial') {
405
+ img.style.objectPosition = originalObjectPosition;
406
+ }
395
407
  imagesLoaded++;
396
408
  };
397
409
  img.onerror = () => {
@@ -973,21 +985,36 @@
973
985
 
974
986
  // Module YouTube Feed
975
987
  youtube: {
976
- // Détection des bots pour éviter les appels API inutiles
988
+ // OPTIMISATION: Détection améliorée des bots pour éviter les appels API inutiles
977
989
  isBot: function() {
978
990
  const userAgent = navigator.userAgent.toLowerCase();
979
991
  const botPatterns = [
980
992
  'bot', 'crawler', 'spider', 'scraper', 'googlebot', 'bingbot', 'slurp',
981
993
  'duckduckbot', 'baiduspider', 'yandexbot', 'facebookexternalhit', 'twitterbot',
982
- 'linkedinbot', 'whatsapp', 'telegrambot', 'discordbot', 'slackbot'
994
+ 'linkedinbot', 'whatsapp', 'telegrambot', 'discordbot', 'slackbot', 'headless',
995
+ 'phantom', 'selenium', 'puppeteer', 'playwright', 'lighthouse', 'gtmetrix',
996
+ 'pagespeed', 'pingdom', 'uptime', 'monitor', 'check', 'test'
983
997
  ];
984
998
 
985
- return botPatterns.some(pattern => userAgent.includes(pattern)) ||
999
+ // Vérifications supplémentaires pour détecter plus de bots
1000
+ const isBot = botPatterns.some(pattern => userAgent.includes(pattern)) ||
986
1001
  navigator.webdriver ||
987
- !navigator.userAgent;
1002
+ !navigator.userAgent ||
1003
+ !window.chrome || // Détecte les navigateurs headless
1004
+ navigator.userAgent.includes('HeadlessChrome') ||
1005
+ window.navigator.plugins.length === 0; // Bots n'ont souvent pas de plugins
1006
+
1007
+ if (isBot) {
1008
+ // Log pour debug (en mode debug seulement)
1009
+ if (bbContents.config.debug) {
1010
+ bbContents.utils.log('Bot détecté, pas d\'appel API YouTube');
1011
+ }
1012
+ }
1013
+
1014
+ return isBot;
988
1015
  },
989
1016
 
990
- // Gestion du cache localStorage
1017
+ // OPTIMISATION: Cache amélioré avec protection contre les appels multiples
991
1018
  cache: {
992
1019
  get: function(key) {
993
1020
  try {
@@ -997,7 +1024,7 @@
997
1024
  const data = JSON.parse(cached);
998
1025
  const now = Date.now();
999
1026
 
1000
- // Cache expiré après 24h
1027
+ // OPTIMISATION: Cache plus long (24h maintenu)
1001
1028
  if (now - data.timestamp > 24 * 60 * 60 * 1000) {
1002
1029
  localStorage.removeItem(key);
1003
1030
  return null;
@@ -1022,6 +1049,21 @@
1022
1049
  }
1023
1050
  },
1024
1051
 
1052
+ // OPTIMISATION: Protection globale contre les appels multiples
1053
+ _activeRequests: new Set(),
1054
+
1055
+ isRequestActive: function(cacheKey) {
1056
+ return this._activeRequests.has(cacheKey);
1057
+ },
1058
+
1059
+ markRequestActive: function(cacheKey) {
1060
+ this._activeRequests.add(cacheKey);
1061
+ },
1062
+
1063
+ markRequestComplete: function(cacheKey) {
1064
+ this._activeRequests.delete(cacheKey);
1065
+ },
1066
+
1025
1067
  detect: function(scope) {
1026
1068
  return scope.querySelector('[bb-youtube-channel]') !== null;
1027
1069
  },
@@ -1075,18 +1117,18 @@
1075
1117
  }
1076
1118
 
1077
1119
  if (!endpoint) {
1078
- // Attendre que la configuration soit définie (max 5 secondes)
1120
+ // OPTIMISATION: Réduire drastiquement les retries (de 50 à 10)
1079
1121
  const retryCount = element.getAttribute('data-youtube-retry-count') || '0';
1080
1122
  const retries = parseInt(retryCount);
1081
1123
 
1082
- if (retries < 50) { // 50 * 100ms = 5 secondes max
1124
+ if (retries < 10) { // 10 * 500ms = 5 secondes max (plus espacé)
1083
1125
  element.innerHTML = '<div style="padding: 20px; text-align: center; color: #6b7280;">Configuration YouTube en cours...</div>';
1084
1126
  element.setAttribute('data-youtube-retry-count', (retries + 1).toString());
1085
1127
 
1086
- // Réessayer dans 100ms
1128
+ // OPTIMISATION: Espacer les retries (500ms au lieu de 100ms)
1087
1129
  setTimeout(() => {
1088
1130
  this.initElement(element);
1089
- }, 100);
1131
+ }, 500);
1090
1132
  return;
1091
1133
  } else {
1092
1134
  // Timeout après 5 secondes
@@ -1129,29 +1171,28 @@
1129
1171
  return;
1130
1172
  }
1131
1173
 
1132
- // Vérifier si un appel API est déjà en cours pour cette clé
1133
- const loadingKey = `loading_${cacheKey}`;
1134
- if (window[loadingKey]) {
1135
- // Attendre que l'autre appel se termine
1136
- const checkLoading = () => {
1137
- if (!window[loadingKey]) {
1174
+ // OPTIMISATION: Protection globale contre les appels multiples
1175
+ if (this.isRequestActive(cacheKey)) {
1176
+ // Un appel est déjà en cours pour cette clé, attendre
1177
+ const checkActive = () => {
1178
+ if (!this.isRequestActive(cacheKey)) {
1138
1179
  // L'autre appel est terminé, vérifier le cache
1139
1180
  const newCachedData = this.cache.get(cacheKey);
1140
1181
  if (newCachedData && newCachedData.value) {
1141
1182
  this.generateYouTubeFeed(container, template, newCachedData.value, allowShorts, language);
1142
- } else {
1183
+ } else {
1143
1184
  container.innerHTML = '<div style="padding: 20px; text-align: center; color: #6b7280;">Erreur de chargement</div>';
1144
1185
  }
1145
1186
  } else {
1146
- setTimeout(checkLoading, 100);
1187
+ setTimeout(checkActive, 200); // Vérifier moins souvent
1147
1188
  }
1148
1189
  };
1149
- checkLoading();
1190
+ checkActive();
1150
1191
  return;
1151
1192
  }
1152
1193
 
1153
1194
  // Marquer qu'un appel API est en cours
1154
- window[loadingKey] = true;
1195
+ this.markRequestActive(cacheKey);
1155
1196
 
1156
1197
  // Afficher un loader
1157
1198
  container.innerHTML = '<div style="padding: 20px; text-align: center; color: #6b7280;">Chargement des vidéos YouTube...</div>';
@@ -1169,20 +1210,20 @@
1169
1210
  throw new Error(data.error.message || 'Erreur API YouTube');
1170
1211
  }
1171
1212
 
1172
- // Sauvegarder en cache pour 24h
1213
+ // OPTIMISATION: Sauvegarder en cache pour 24h
1173
1214
  this.cache.set(cacheKey, data);
1174
1215
  // Données YouTube mises en cache pour 24h (économie API)
1175
1216
 
1176
1217
  this.generateYouTubeFeed(container, template, data, allowShorts, language);
1177
1218
 
1178
- // Libérer le verrou
1179
- window[loadingKey] = false;
1219
+ // OPTIMISATION: Libérer le verrou avec la nouvelle méthode
1220
+ this.markRequestComplete(cacheKey);
1180
1221
  })
1181
1222
  .catch(error => {
1182
1223
  // Erreur dans le module youtube
1183
1224
 
1184
- // Libérer le verrou en cas d'erreur
1185
- window[loadingKey] = false;
1225
+ // OPTIMISATION: Libérer le verrou en cas d'erreur
1226
+ this.markRequestComplete(cacheKey);
1186
1227
 
1187
1228
  // En cas d'erreur, essayer de récupérer du cache même expiré
1188
1229
  const expiredCache = localStorage.getItem(cacheKey);
@@ -1372,7 +1413,7 @@
1372
1413
  return textarea.value;
1373
1414
  },
1374
1415
 
1375
- // Nettoyer le cache expiré
1416
+ // OPTIMISATION: Nettoyer le cache expiré (48h)
1376
1417
  cleanCache: function() {
1377
1418
  try {
1378
1419
  const keys = Object.keys(localStorage);
@@ -1383,6 +1424,7 @@
1383
1424
  if (key.startsWith('youtube_')) {
1384
1425
  try {
1385
1426
  const cached = JSON.parse(localStorage.getItem(key));
1427
+ // OPTIMISATION: Cache 24h maintenu
1386
1428
  if (now - cached.timestamp > 24 * 60 * 60 * 1000) {
1387
1429
  localStorage.removeItem(key);
1388
1430
  cleaned++;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bebranded/bb-contents",
3
- "version": "1.0.84",
3
+ "version": "1.0.86",
4
4
  "description": "Contenus additionnels français pour Webflow",
5
5
  "main": "bb-contents.js",
6
6
  "scripts": {