webextension-store-meta
Version:
Get browser extension(webextension) item meta from Chrome Web Store and Firefox add-ons.
200 lines • 6.98 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ChromeWebStore = void 0;
const node_querystring_1 = require("node:querystring");
const domhandler_1 = require("domhandler");
const Parser_1 = require("htmlparser2/lib/Parser");
const dom_1 = require("../utils/dom");
const fetch_text_1 = require("../utils/fetch-text");
const parse_1 = require("../utils/parse");
class ChromeWebStore {
id;
options;
qs;
_dom = null;
_cache = new Map();
constructor({ id, options, qs }) {
this.id = id;
this.options = options;
this.qs = (0, node_querystring_1.stringify)(typeof qs === "string" ? (0, node_querystring_1.parse)(qs.replace(/^\?/, "")) : qs || {});
}
static async load(options) {
const instance = new ChromeWebStore(options);
await instance.load();
return instance;
}
async load() {
const url = `https://chromewebstore.google.com/detail/${this.id}?${this.qs}`;
const html = await (0, fetch_text_1.fetchText)(url, this.options);
const handler = new domhandler_1.DomHandler();
new Parser_1.Parser(handler).end(html);
this._dom = handler.dom;
return this;
}
meta() {
return {
name: this.name(),
description: this.description(),
url: this.url(),
image: this.image(),
ratingValue: this.ratingValue(),
ratingCount: this.ratingCount(),
users: this.users(),
version: this.version(),
size: this.size(),
lastUpdated: this.lastUpdated(),
};
}
name() {
return this._og("og:title");
}
description() {
return this._og("og:description");
}
url() {
let url = this._og("og:url");
if (url)
return url;
const urlElem = (0, dom_1.findOne)((elem) => elem.name === "link" && elem.attribs.rel === "canonical", this.dom);
if (urlElem) {
url = urlElem.attribs.href;
if (url) {
this._cache.set("og:url", url);
return url;
}
}
return null;
}
image() {
return this._og("og:image");
}
ratingValue() {
return this._parseRating("ratingValue");
}
ratingCount() {
return this._parseRating("ratingCount");
}
users() {
if (!this._cache.has("users")) {
const container = (0, dom_1.queryOne)(this.dom, "F9iKBc");
if (container) {
for (let i = 0; i < container.children.length; i++) {
const node = container.children[i];
if ((0, domhandler_1.isText)(node)) {
const content = (0, dom_1.getText)(node);
const match = /[\d,]+/.exec(content);
if (match) {
this._cache.set("users", match[0]);
break;
}
}
}
}
if (!this._cache.has("users")) {
this._cache.set("users", null);
}
}
return this._cache.get("users") ?? null;
}
version() {
if (!this._cache.has("version")) {
const el = (0, dom_1.queryOne)(this.dom, "nBZElf") || (0, dom_1.queryOne)(this.dom, "N3EXSc");
this._cache.set("version", (el && (0, parse_1.parseVersion)((0, dom_1.getText)(el))) || parseVersionFromManifest(this.dom));
}
return this._cache.get("version") ?? null;
}
size() {
if (!this._cache.has("size")) {
const el = (0, dom_1.queryOne)(this.dom, "ZSMSLb");
this._cache.set("size", (0, dom_1.getText)(el?.lastChild) || null);
}
return this._cache.get("size") ?? null;
}
lastUpdated() {
if (!this._cache.has("lastUpdated")) {
const el = (0, dom_1.queryOne)(this.dom, "uBIrad");
this._cache.set("lastUpdated", (0, dom_1.getText)(el?.lastChild) || null);
}
return this._cache.get("lastUpdated") ?? null;
}
get dom() {
if (!this._dom) {
throw new Error("Item not loaded. Please run `await instance.load()` first.`");
}
return this._dom;
}
_og(property) {
if (!this._cache.has(property)) {
(0, dom_1.findOne)((elem) => {
if (elem.attribs.property == null)
return false;
this._cache.set(elem.attribs.property, elem.attribs.content);
return elem.attribs.property === property;
}, this.dom);
if (!this._cache.has(property)) {
this._cache.set(property, null);
}
}
return this._cache.get(property) ?? null;
}
_parseRating(key) {
if (!this._cache.has(key)) {
const result = parseRating(this.dom);
this._cache.set("ratingValue", result?.ratingValue ?? null);
this._cache.set("ratingCount", result?.ratingCount ?? null);
}
return this._cache.get(key) ?? null;
}
}
exports.ChromeWebStore = ChromeWebStore;
exports.default = ChromeWebStore;
function parseRating(dom) {
const container = (0, dom_1.queryOne)(dom, "j3zrsd");
if (container) {
const result = {
ratingValue: null,
ratingCount: null,
};
const ratingValueEl = (0, dom_1.queryOne)(container, "Vq0ZA");
if (ratingValueEl) {
const ratingValue = (0, dom_1.getText)(ratingValueEl);
if (/^\d+\.?\d*$/.test(ratingValue)) {
result.ratingValue = ratingValue;
}
}
const ratingCountEl = (0, dom_1.queryOne)(container, "xJEoWe");
if (ratingCountEl) {
result.ratingCount = (0, dom_1.getText)(ratingCountEl).replace(/\s*ratings$/, "");
}
if (result.ratingValue !== null || result.ratingCount !== null) {
return result;
}
}
return null;
}
function parseVersionFromManifest(maybeNode) {
const nodes = Array.isArray(maybeNode) ? maybeNode : [maybeNode];
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
if (!(0, domhandler_1.isTag)(node)) {
continue;
}
if (node.tagName === "script") {
const content = (0, dom_1.getText)(node);
if (content.includes("AF_initDataCallback")) {
const match = /\\"version\\":\s*\\"([\d.]+)\\"/.exec(content);
if (match) {
return match[1];
}
}
}
if (node.children.length > 0) {
const version = parseVersionFromManifest(node.children);
if (version) {
return version;
}
}
}
return null;
}
//# sourceMappingURL=index.js.map