fix(extension): sync robuste content/sidepanel, diagnostic panel, preview propre v0.4.4
- content.js : écrit la sélection dans chrome.storage.session/local en plus du message runtime - sidepanel.js : lit le storage en fallback, loggue chaque étape, affiche un diagnostic panel - sidepanel.js : avertissement explicite si le content script n'est pas détecté - sidepanel.js : sépare le rendu Markdown du résumé et l'affichage texte brut de l'extrait - sidepanel.css : agrandit la zone de prévisualisation - i18n : nouvelles clés contentScriptMissing, diagnosticsTitle, copyDiagnostics - locales : correction FR (Retour, Enregistrement, Note, etc.) + version 0.4.4 partout - extract-article.ts : nettoie textContent des métadonnées (dates, temps de lecture, sources) - analyze/route.ts : excerpt propre via makeExcerpt - builds Chrome Store et Firefox regénérés en 0.4.4
This commit is contained in:
@@ -17,6 +17,42 @@ export interface ExtractedArticle {
|
||||
locale: ClipLocaleHint
|
||||
}
|
||||
|
||||
const META_PATTERNS = [
|
||||
// Dates/heures avec "mis à jour / updated / actualizado / aktualisiert"
|
||||
/\b(mis à jour|updated at|actualizado|aktualisiert am|aggiornato alle)\b[\s:|-]*.*/gi,
|
||||
// Temps de lecture
|
||||
/\b(temps de lecture|reading time|lesedauer|tiempo de lectura|tempo di lettura|czas czytania|время чтения|阅读时间|読了時間)\b[\s:|-]*.*/gi,
|
||||
// Lignes de type "Source - Aujourd'hui à 09:15 | mis à jour à 11:07"
|
||||
/^(.*?\s[-–|]\s)(aujourd['’]?hui|today|hoy|heute|oggi|vandaag|dzisiaj|сегодня|今日)\b.*$/gim,
|
||||
// Heures seules type "09:15" ou "09:15 | mis à jour..."
|
||||
/^\s*\d{1,2}:\d{2}(\s*[-|]\s*.*)?$/gm,
|
||||
]
|
||||
|
||||
export function cleanClipText(text: string): string {
|
||||
let cleaned = text.replace(/\r\n/g, '\n').replace(/\n{3,}/g, '\n\n')
|
||||
for (const pattern of META_PATTERNS) {
|
||||
cleaned = cleaned.replace(pattern, '')
|
||||
}
|
||||
return cleaned
|
||||
.split('\n')
|
||||
.map((line) => line.trim())
|
||||
.filter((line) => line.length > 0)
|
||||
.join('\n')
|
||||
.replace(/\n{3,}/g, '\n\n')
|
||||
.trim()
|
||||
}
|
||||
|
||||
export function makeExcerpt(text: string, maxLen = 500): string {
|
||||
if (text.length <= maxLen) return text
|
||||
// Préférer couper à la fin d'une phrase.
|
||||
const sentenceEnd = text.lastIndexOf('.', maxLen)
|
||||
if (sentenceEnd > maxLen * 0.6) return text.slice(0, sentenceEnd + 1).trim()
|
||||
// Sinon couper au dernier espace.
|
||||
const space = text.lastIndexOf(' ', maxLen)
|
||||
if (space > maxLen * 0.6) return text.slice(0, space).trim() + '…'
|
||||
return text.slice(0, maxLen).trim() + '…'
|
||||
}
|
||||
|
||||
export function extractArticleFromHtml(html: string, pageUrl: string): ExtractedArticle | null {
|
||||
const dom = new JSDOM(html, { url: pageUrl })
|
||||
const reader = new Readability(dom.window.document)
|
||||
@@ -48,11 +84,13 @@ export function extractArticleFromHtml(html: string, pageUrl: string): Extracted
|
||||
const rtlBlocks = applyRtlToHtmlBlocks(sanitized, mergedLocale)
|
||||
const content = wrapClipArticleHtml(rtlBlocks, mergedLocale)
|
||||
|
||||
const cleanText = cleanClipText(article.textContent || '')
|
||||
|
||||
return {
|
||||
title: (article.title || '').trim(),
|
||||
content,
|
||||
textContent: (article.textContent || '').trim(),
|
||||
excerpt: (article.excerpt || '').trim(),
|
||||
textContent: cleanText,
|
||||
excerpt: makeExcerpt(cleanText, 500),
|
||||
locale: mergedLocale,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user