From 1898d4738edc0b7b78ba1ddc96b1ccbf31f02602 Mon Sep 17 00:00:00 2001 From: Oliver Blanthorn Date: Sun, 30 Aug 2026 19:21:23 +0200 Subject: [PATCH] Fix #5514: switch from readability to defuddle --- browser-targets.json | 2 +- package.json | 2 +- src/excmds.ts | 8 ++- src/reader.ts | 29 ++++++-- yarn.lock | 157 +++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 185 insertions(+), 13 deletions(-) diff --git a/browser-targets.json b/browser-targets.json index df4a116f..f2672c86 100644 --- a/browser-targets.json +++ b/browser-targets.json @@ -1,6 +1,6 @@ { "firefox": { - "minimumVersion": "94.0", + "minimumVersion": "121.0", "manifestVersionPath": [ "applications", "gecko", diff --git a/package.json b/package.json index 4d74aaa8..4625b1a8 100644 --- a/package.json +++ b/package.json @@ -12,11 +12,11 @@ "stream": "stream-browserify" }, "dependencies": { - "@mozilla/readability": "^0.5.0", "cleanslate": "git+https://github.com/tridactyl/cleanslate.git#master", "compute-scroll-into-view": "^3.0.0", "csp-serdes": "github:cmcaine/csp-serdes", "css": "^3.0.0", + "defuddle": "^0.19.3", "editor-adapter": "git+https://github.com/tridactyl/editor-adapter.git#master", "esbuild": "^0.20.2", "fuse.js": "^7.0.0", diff --git a/src/excmds.ts b/src/excmds.ts index b0cb8933..5431ed95 100644 --- a/src/excmds.ts +++ b/src/excmds.ts @@ -6627,7 +6627,7 @@ export async function extoptions(...optionNameArgs: string[]) { } //#content_helper -import { Readability } from "@mozilla/readability" +import Defuddle from "defuddle" /** * @hidden @@ -6636,7 +6636,11 @@ import { Readability } from "@mozilla/readability" export async function readerurl(article: any = undefined) { if (!article) { document.querySelectorAll(".TridactylStatusIndicator").forEach(ind => ind.parentNode.removeChild(ind)) - article = new Readability(document.cloneNode(true) as any as Document).parse() + const { content, title, site, author, image } = new Defuddle( + document.cloneNode(true) as Document, + { url: window.location.href }, + ).parse() + article = { content, title, site, author, image } article["link"] = window.location.href article["favicon"] = (await ownTab()).favIconUrl } diff --git a/src/reader.ts b/src/reader.ts index 11558528..676a0132 100644 --- a/src/reader.ts +++ b/src/reader.ts @@ -44,6 +44,25 @@ async function updatePage() { else if (link.target.toLowerCase() === "_blank") link.relList.add("noopener") else link.target = "_top" }) + if (article.image) { + let coverUrl: URL | undefined + try { + coverUrl = new URL(article.image, article.link ?? document.baseURI) + } catch { + coverUrl = undefined + } + const cover = document.createElement("img") + if ( + coverUrl !== undefined && + ["http:", "https:", "data:"].includes(coverUrl.protocol) && + !Array.from(content.content.querySelectorAll("img")).some( + image => image.src === coverUrl.href, + ) + ) { + cover.src = coverUrl.href + content.content.prepend(cover) + } + } article.content = content.innerHTML let headerHtml = "" if (article.title !== undefined) { @@ -55,22 +74,22 @@ async function updatePage() { !(article.title ?? "").includes(article.link) ) { document.title = - [article.siteName, article.title].filter(Boolean).join(": ") + + [article.site, article.title].filter(Boolean).join(": ") + " :: " + article.link } else { - document.title = [article.siteName, article.title] + document.title = [article.site, article.title] .filter(Boolean) .join(": ") } title.textContent = article.title header.appendChild(title) - if (article.byline !== undefined) { + if (article.author !== undefined) { const author = document.createElement("p") - author.textContent = article.byline + author.textContent = article.author header.appendChild(author) } - const {text, words} = readingTime(article.textContent ?? "") + const { text, words } = readingTime(content.content.textContent ?? "") const readingtime = document.createElement("p") readingtime.textContent = `${words} words, ${text}` header.appendChild(readingtime) diff --git a/yarn.lock b/yarn.lock index f081f486..39cae942 100644 --- a/yarn.lock +++ b/yarn.lock @@ -889,10 +889,10 @@ resolved "https://registry.yarnpkg.com/@mdn/browser-compat-data/-/browser-compat-data-5.5.7.tgz#984652af52cbe7c111c376d519b5ce765d444003" integrity sha512-DoHTZ/TjtNfUu9eiqJd+x3IcCQrhS+yOYU436TKUnlE36jZwNbK535D1CmTsSYdi/UcdCWNm5KRQZ9g1tlZCPw== -"@mozilla/readability@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@mozilla/readability/-/readability-0.5.0.tgz#a6d5055bbadd0f329cc3e72089d4f176ed96c1d5" - integrity sha512-Z+CZ3QaosfFaTqvhQsIktyGrjFjSC0Fa4EMph4mqKnWhmyoGICsV/8QK+8HpXut6zV7zwfWwqDmEjtk1Qf6EgQ== +"@mixmark-io/domino@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@mixmark-io/domino/-/domino-2.2.0.tgz#4e8ec69bf1afeb7a14f0628b7e2c0f35bdb336c3" + integrity sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw== "@nodelib/fs.scandir@2.1.3": version "2.1.3" @@ -1338,6 +1338,11 @@ loglevel-plugin-prefix "^0.8.4" strip-ansi "^7.1.0" +"@xmldom/xmldom@^0.9.10": + version "0.9.12" + resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.9.12.tgz#1f84c07cb95ccf28202299f77b5fd7fc257151e8" + integrity sha512-5AXjrcMClTryPe9LgZrygpB1lj7s0S9E0+W+AHaVKAVyHanafK86iPSvG5xHVSp/jC+VH1UXu0TAEmY279xH7A== + "@zip.js/zip.js@^2.7.53": version "2.7.54" resolved "https://registry.yarnpkg.com/@zip.js/zip.js/-/zip.js-2.7.54.tgz#ef0f46644b1a084155473b0d7710c80a892c2687" @@ -1835,6 +1840,11 @@ boolbase@^1.0.0: resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= +boolbase@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-2.0.0.tgz#832968d211d5c008d833b86e049bb3943036e5b1" + integrity sha512-DkVaaQHymRhpYEYo9x1oo7Q7B0Y6KJUsjm3c9eTyFDby4MHLBTwZ6ZDWBel5zrYxj1WsZgC5oLpiz+93MluXeA== + boxen@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/boxen/-/boxen-7.0.0.tgz#9e5f8c26e716793fc96edcf7cf754cdf5e3fbf32" @@ -2198,6 +2208,11 @@ commander@2.9.0: dependencies: graceful-readlink ">= 1.0.0" +commander@^12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3" + integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA== + commander@^2.19.0, commander@^2.20.3, commander@^2.6.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -2330,11 +2345,27 @@ css-select@^5.1.0: domutils "^3.0.1" nth-check "^2.0.1" +css-select@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-7.0.0.tgz#7532bab5977b1f0e83bc16036661dbe0968b4dec" + integrity sha512-snmjEVXy+1LnwXdxhYvTMj1d9tOh4HxkA1YmoayVBeeyR2C14Pum7fcxJIm4SswYspVy866eYNwlH6xC3/VH5g== + dependencies: + boolbase "^2.0.0" + css-what "^8.0.0" + domhandler "^6.0.1" + domutils "^4.0.2" + nth-check "^3.0.1" + css-what@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== +css-what@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-8.0.0.tgz#237889d60c4afef4736892f39e133ab4c8c21f0c" + integrity sha512-DH0Bqq3DNp5tdOReuNyAA+Ev4Y2GS5FMbZpeTLP6C4CDi0h5nL0BmUPChXw3o/qbHLDWHl49sbNqQVY7bMSDdw== + css@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/css/-/css-3.0.0.tgz#4447a4d58fdd03367c516ca9f64ae365cee4aa5d" @@ -2531,6 +2562,18 @@ define-properties@^1.2.0: has-property-descriptors "^1.0.0" object-keys "^1.1.1" +defuddle@^0.19.3: + version "0.19.3" + resolved "https://registry.yarnpkg.com/defuddle/-/defuddle-0.19.3.tgz#ca7c71b1eaeab8a47ff702bb6ed18b19a3fdd05b" + integrity sha512-5ZbOQ/B+iiRRqSQWwmCx/zEuqZOA/5q7gxyE2/4O2Bxq7nUC0PgKw9EdyxqWbFF1nrrrYemSeR25jg4TmA2fsA== + dependencies: + commander "^12.1.0" + optionalDependencies: + linkedom "^0.18.12" + mathml-to-latex "^1.8.0" + temml "^0.13.3" + turndown "^7.2.0" + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -2581,11 +2624,25 @@ dom-serializer@^2.0.0: domhandler "^5.0.2" entities "^4.2.0" +dom-serializer@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-3.1.1.tgz#54be70ee4fcc2da010f488165e62294798dc57d3" + integrity sha512-4MEa38/QexBob6gFNwu+EGdWvhJ1OKuNwdYY3Y3NyeWDQfnGeDYQUDfIRzWu5B5gsv03so2Uxd28YC6zrsx3Lw== + dependencies: + domelementtype "^3.0.0" + domhandler "^6.0.0" + entities "^8.0.0" + domelementtype@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== +domelementtype@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-3.0.0.tgz#e6c0a24bd39ca5eb7ea67a98d2f699497d7bcc55" + integrity sha512-umCQid3jKbDmVjx8jGaW7uUykm4DEUeyV21hPxNMo2nV955DhUThwqyOIDtreepP31hl84X7G5U9ZfsWvIB3Pg== + domexception@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/domexception/-/domexception-4.0.0.tgz#4ad1be56ccadc86fc76d033353999a8037d03673" @@ -2600,6 +2657,13 @@ domhandler@^5.0.1, domhandler@^5.0.2, domhandler@^5.0.3: dependencies: domelementtype "^2.3.0" +domhandler@^6.0.0, domhandler@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-6.0.1.tgz#75f351a03a6e10c35e08418f9cf0d287e00797cf" + integrity sha512-gYzvtM72ZtxQO0T048kd6HWSbbGCNOUwcnfQ01cqIJ4X2IYKFFHZ5mKvrQETcFXxsRObZulDaKmy//R7TPtsBg== + dependencies: + domelementtype "^3.0.0" + domutils@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.0.1.tgz#696b3875238338cb186b6c0612bd4901c89a4f1c" @@ -2609,6 +2673,24 @@ domutils@^3.0.1: domelementtype "^2.3.0" domhandler "^5.0.1" +domutils@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.2.2.tgz#edbfe2b668b0c1d97c24baf0f1062b132221bc78" + integrity sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw== + dependencies: + dom-serializer "^2.0.0" + domelementtype "^2.3.0" + domhandler "^5.0.3" + +domutils@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-4.0.2.tgz#0c1ac1fdbe8f554a60a6f5eb143ee85630327c94" + integrity sha512-qI4JLRKnSzqFqr7hAlS5xQDusBCjKSEG4t4+7aNrIQMHBcsC2TGEhuyABJdYkgSewL57PNLYEiibY2iPKhKpaA== + dependencies: + dom-serializer "^3.0.0" + domelementtype "^3.0.0" + domhandler "^6.0.0" + dot-prop@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-6.0.1.tgz#fc26b3cf142b9e59b74dbd39ed66ce620c681083" @@ -2707,6 +2789,16 @@ entities@^6.0.0: resolved "https://registry.yarnpkg.com/entities/-/entities-6.0.1.tgz#c28c34a43379ca7f61d074130b2f5f7020a30694" integrity sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g== +entities@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/entities/-/entities-7.0.1.tgz#26e8a88889db63417dcb9a1e79a3f1bc92b5976b" + integrity sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA== + +entities@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-8.0.0.tgz#c1df5fe3602429747fa233d0dd26f142f0ce4743" + integrity sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA== + error-ex@^1.3.1, error-ex@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" @@ -3847,6 +3939,21 @@ html-escaper@^2.0.0: resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.0.tgz#71e87f931de3fe09e56661ab9a29aadec707b491" integrity sha512-a4u9BeERWGu/S8JiWEAQcdrg9v4QArtP9keViQjGMdff20fBdd8waotXaNmODqBe6uZ3Nafi7K/ho4gCQHV3Ig== +html-escaper@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-3.0.3.tgz#4d336674652beb1dcbc29ef6b6ba7f6be6fdfed6" + integrity sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ== + +htmlparser2@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-10.1.0.tgz#fe3f2e12c73b6e462d4e10395db9c1119e4d6ae4" + integrity sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.3" + domutils "^3.2.2" + entities "^7.0.1" + htmlparser2@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-8.0.1.tgz#abaa985474fcefe269bc761a779b544d7196d010" @@ -5030,6 +5137,17 @@ lines-and-columns@^2.0.2: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-2.0.3.tgz#b2f0badedb556b747020ab8ea7f0373e22efac1b" integrity sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w== +linkedom@^0.18.12: + version "0.18.13" + resolved "https://registry.yarnpkg.com/linkedom/-/linkedom-0.18.13.tgz#db4582d42d5606961dd8e596fc273bd8c06f50df" + integrity sha512-ES/o9qotMpzpN2MHs+Iq/JcVoOj8Fa5wiQYrTdFpvAnwXL0g66XHHUc9WUMk6nAlBtGsFQ24ne+SYnvnaQ2FSw== + dependencies: + css-select "^7.0.0" + cssom "^0.5.0" + html-escaper "^3.0.3" + htmlparser2 "^10.1.0" + uhyphen "^0.2.0" + linkify-it@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-5.0.2.tgz#d3be0a693af3da9df3883f1e346a0e97461a8c19" @@ -5168,6 +5286,13 @@ math-intrinsics@^1.1.0: resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== +mathml-to-latex@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/mathml-to-latex/-/mathml-to-latex-1.8.0.tgz#1007f1cb3f6c47453d5c52dbbcb90a823380c6be" + integrity sha512-gQ0uK3zqB8HwlfaXJkEL5rgaZNbKUiBMmBP/B/W+b+t6KcseLSuYb1b0BjLgS9ZiQa24ePkqTX8/6FaQuDL7wQ== + dependencies: + "@xmldom/xmldom" "^0.9.10" + mdurl@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-2.0.0.tgz#80676ec0433025dd3e17ee983d0fe8de5a2237e0" @@ -5464,6 +5589,13 @@ nth-check@^2.0.1: dependencies: boolbase "^1.0.0" +nth-check@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-3.0.1.tgz#a5ede96060f7f0b74d7d3d8425f2a8f0610c5776" + integrity sha512-GX0gsdbGVCgnRgbeGaubfjpBXyYRWOOCVeYh08bSQvDZqxz5ndXs1OTfAt/h36G1xvI94YIspsI0sVFqAV9+RQ== + dependencies: + boolbase "^2.0.0" + nwsapi@^2.2.2: version "2.2.24" resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.24.tgz#f8927043d4c9b516abdebe804a32c8d1f9484d1f" @@ -6786,6 +6918,11 @@ tar-stream@^3.1.5: fast-fifo "^1.2.0" streamx "^2.15.0" +temml@^0.13.3: + version "0.13.5" + resolved "https://registry.yarnpkg.com/temml/-/temml-0.13.5.tgz#96c53c4ece59ae719859e2a5074b6d4251cee423" + integrity sha512-aPkDDgunanpLNL0ql32HbolqLep+w8DRcVXRql7rWrMt/PhczdLgL4UBYYVU3BYjCNjkGq4EqwIicu/zWr1iOg== + test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" @@ -6939,6 +7076,13 @@ tunnel-agent@^0.6.0: dependencies: safe-buffer "^5.0.1" +turndown@^7.2.0: + version "7.2.4" + resolved "https://registry.yarnpkg.com/turndown/-/turndown-7.2.4.tgz#42d98202aefa8c188c997b586bc6da78bdf27ea2" + integrity sha512-I8yFsfRzmzK0WV1pNNOA4A7y4RDfFxPRxb3t+e3ui14qSGOxGtiSP6GjeX+Y6CHb7HYaFj7ECUD7VE5kQMZWGQ== + dependencies: + "@mixmark-io/domino" "^2.2.0" + tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" @@ -7063,6 +7207,11 @@ uglify-js@^3.1.4: resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.19.3.tgz#82315e9bbc6f2b25888858acd1fff8441035b77f" integrity sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ== +uhyphen@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/uhyphen/-/uhyphen-0.2.0.tgz#8fdf0623314486e020a3c00ee5cc7a12fe722b81" + integrity sha512-qz3o9CHXmJJPGBdqzab7qAYuW8kQGKNEuoHFYrBwV6hWIMcpAmxDLXojcHfFr9US1Pe6zUswEIJIbLI610fuqA== + unbox-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e"