{"id":21326234,"url":"https://github.com/masylum/cheer-reader","last_synced_at":"2026-01-03T02:08:44.660Z","repository":{"id":246516743,"uuid":"821346222","full_name":"masylum/cheer-reader","owner":"masylum","description":"A port of readability.js for cheerio","archived":false,"fork":false,"pushed_at":"2024-10-23T08:09:04.000Z","size":5377,"stargazers_count":13,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-22T12:32:40.843Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/masylum.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-06-28T10:34:34.000Z","updated_at":"2025-01-15T09:35:16.000Z","dependencies_parsed_at":"2024-09-13T18:53:03.960Z","dependency_job_id":"427befb2-145d-4057-9939-bc05e8b347f6","html_url":"https://github.com/masylum/cheer-reader","commit_stats":null,"previous_names":["masylum/cheer-reader"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/masylum%2Fcheer-reader","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/masylum%2Fcheer-reader/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/masylum%2Fcheer-reader/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/masylum%2Fcheer-reader/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/masylum","download_url":"https://codeload.github.com/masylum/cheer-reader/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243806041,"owners_count":20350775,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-21T21:08:52.544Z","updated_at":"2026-01-03T02:08:44.611Z","avatar_url":"https://github.com/masylum.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"![cheer-reader](https://github.com/masylum/cheer-reader/blob/main/img/cheer-reader.png?raw=true)\n\nThis library is a port of the [readability.js](https://github.com/mozilla/readability) library\nthat uses [cheerio](https://cheerio.js.org) instead of native DOM APIs.\n\nThe goals of this port are the following:\n\n-   **Portability**: Most runtimes and Web Workers don't support DOM apis.\n    By using cheerio, we ensure that you can run readability wherever you want.\n    If your goal is to run it in the main thread of the browser, you can stick to the original\n    implementation.\n-   **Performance**: For non-native runtimes, we rely in JSDOM to simulate native DOM APIs. JSDOM\n    does a lot besides parsing HTML, and is pretty heavy and slow. **cheerio** instead is lightweight\n    and fast. Overall, I've experienced that this port performs 6-8x times faster and consumes a lot\n    less memory than the original one. You can even use [htmlparser2](https://github.com/fb55/htmlparser2)\n    if you need more performance.\n-   **Compatibility**: In order to avoid using JSOM, you could use readability's [JSDOMParser](https://github.com/mozilla/readability/blob/main/JSDOMParser.js),\n    [Happy Dom](https://github.com/capricorn86/happy-dom) or [Linkedom](https://github.com/WebReflection/linkedom).\n    I had compatibility problems using those alternative implementations, but **cheerio** worked flawlesly even\n    with the most broken html documents that you can find on the internet. You even have the option to use\n    [htmlparser2](https://github.com/fb55/htmlparser2) instead of **cheerio**'s default [parse5](https://github.com/inikulin/parse5)\n    for less strict parsing.\n-   **Extensability**: The original implementation is pretty hard to read and maintain. While I didn't deviate\n    much from it, I tried to modernize the code base a little bit. I hope people can help me out, specially with\n    the `_grabArticle` gigantic method with nested while loops. I also saw a lot of issues on the repo for top pages\n    that didn't seem taken care of. It is my intention to try to fix those as I move forward.\n\nThe implementation aims to be the same and it keeps the same test set to ensure backwards compatibility.\n\n## Installation\n\n`cheer-reader` is available on jsr:\n\n```bash\nnpx jsr add @paoramen/cheer-reader\n```\n\n## Basic usage\n\nTo parse a document, you must create a new `Readability` object from a DOM document object, and then call the [`parse()`](#parse) method. Here's an example:\n\n```javascript\nimport { Readability } from 'cheer-reader'\n\nconst $ = load('html\u003e\u003cdiv\u003eyo\u003c/div\u003e\u003c/html\u003e')\nconst article = new Readability($).parse()\n```\n\n## API Reference\n\n### `new Readability($, options)`\n\nThe `options` object accepts a number of properties, all optional:\n\n-   `debug` (boolean, default `false`): whether to enable logging.\n-   `maxElemsToParse` (number, default `0` i.e. no limit): the maximum number of elements to parse.\n-   `nbTopCandidates` (number, default `5`): the number of top candidates to consider when analysing how tight the competition is among candidates.\n-   `charThreshold` (number, default `500`): the number of characters an article must have in order to return a result.\n-   `classesToPreserve` (array): a set of classes to preserve on HTML elements when the `keepClasses` options is set to `false`.\n-   `keepClasses` (boolean, default `false`): whether to preserve all classes on HTML elements. When set to `false` only classes specified in the `classesToPreserve` array are kept.\n-   `disableJSONLD` (boolean, default `false`): when extracting page metadata, cheer-reader gives precedence to Schema.org fields specified in the JSON-LD format. Set this option to `true` to skip JSON-LD parsing.\n-   `serializer` (function, default `$el =\u003e $el.html()`) controls how the `content` property returned by the `parse()` method is produced from the root DOM element. It may be useful to specify the `serializer` as the identity function (`$el =\u003e $el`) to obtain a cheerio element instead of a string for `content` if you plan to process it further.\n-   `allowedVideoRegex` (RegExp, default `undefined` ): a regular expression that matches video URLs that should be allowed to be included in the article content. If `undefined`, the default regex is applied.\n-   `linkDensityModifier` (number, default `0`): a number that is added to the base link density threshold during the shadiness checks. This can be used to penalize nodes with a high link density or vice versa.\n\nAdded options from the original implementation:\n\n-   `extraction` (boolean, default `true`): Some libraries are only interested on the metadata and don't want to pay the price of a full extraction. When you enable this option the `content`, `textContent`, `length` and `excerpt` will be `null`.\n\n### `parse()`\n\nReturns an object containing the following properties:\n\n-   `title`: article title;\n-   `content`: HTML string of processed article content;\n-   `textContent`: text content of the article, with all the HTML tags removed;\n-   `length`: length of an article, in characters;\n-   `excerpt`: article description, or short excerpt from the content;\n-   `byline`: author metadata;\n-   `dir`: content direction;\n-   `siteName`: name of the site;\n-   `lang`: content language;\n-   `publishedTime`: published time;\n\n## Security\n\nIf you're going to use `cheer-reader` with untrusted input (whether in HTML or DOM form), we **strongly** recommend you use a sanitizer library like [DOMPurify](https://github.com/cure53/DOMPurify) to avoid script injection when you use\nthe output of `cheer-reader`. We would also recommend using [CSP](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) to add further defense-in-depth\nrestrictions to what you allow the resulting content to do. The Firefox integration of\nreader mode uses both of these techniques itself. Sanitizing unsafe content out of the input is explicitly not something we aim to do as part of `cheer-reader` itself - there are other good sanitizer libraries out there, use them!\n\n## Contributing\n\nPlease see our [Contributing](CONTRIBUTING.md) document.\n\n## License\n\n    Copyright (c) 2010 Arc90 Inc\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmasylum%2Fcheer-reader","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmasylum%2Fcheer-reader","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmasylum%2Fcheer-reader/lists"}