From 5e05c4e9aa6df3f42118acb8a11a205ee57bfc4e Mon Sep 17 00:00:00 2001 From: Schnitzel5 Date: Sat, 11 Oct 2025 21:59:46 +0200 Subject: [PATCH] some refactoring --- lib/eval/lnreader/js_cheerio.dart | 72 +++++++++++++++++++++++++---- lib/eval/lnreader/js_libs.dart | 4 ++ lib/eval/lnreader/js_polyfills.dart | 14 +++++- lib/eval/lnreader/m_plugin.dart | 9 ++-- lib/eval/lnreader/service.dart | 3 -- 5 files changed, 85 insertions(+), 17 deletions(-) diff --git a/lib/eval/lnreader/js_cheerio.dart b/lib/eval/lnreader/js_cheerio.dart index 597d2b72..ff5e0729 100644 --- a/lib/eval/lnreader/js_cheerio.dart +++ b/lib/eval/lnreader/js_cheerio.dart @@ -219,17 +219,45 @@ class ElementCollection { this.elements = elements; } + text() { + return this.map(function(i, el) { + return el.text(); + }).toArray().join("\\n") ?? ""; + } + + html() { + return this.first()?.html(); + } + + outerHtml() { + return this.first()?.outerHtml(); + } + + attr(name) { + return this.first()?.attr(name); + } + + hasClass(cls) { + return this.first()?.hasClass(cls); + } + each(fn) { this.elements.forEach((el, i) => fn(i, el)); return this; } map(fn) { - return this.elements.map((el, i) => fn(el, i)); + return new ElementCollection(this.elements.map((el, i) => fn(i, el))); } filter(fn) { - return new ElementCollection(this.elements.filter((el, i) => fn(el, i))); + return new ElementCollection(this.elements.filter(function (el, i) { + try { + return fn(i, el); + } catch (_) { + return false; + } + })); } addClass(cls) { @@ -309,37 +337,62 @@ class ElementCollection { } first() { - return this.elements[0] || null; + return this.get(0); } last() { - return this.elements[this.elements.length - 1] || null; + return this.get(this.elements.length - 1); } get(index) { - return this.elements[index] || null; + return this.elements[index] || new Stub(); } length() { return this.elements.length; } + toArray() { + return this.elements; + } + [Symbol.iterator]() { return this.elements[Symbol.iterator](); } } +class Stub { + text() { + return null; + } + html() { + return null; + } + outerHtml() { + return null; + } + val() { + return null; + } + attr(name) { + return null; + } + hasClass(cls) { + return false; + } +} + function load(html) { const rootKey = sendMessage("load", JSON.stringify([html])); const root = new Element(rootKey); const \$ = function(input) { - if (typeof input === "string") { - return root.find(input); // returns ElementCollection - } else if (input instanceof ElementCollection) { + if (input instanceof ElementCollection) { return input; } else if (input instanceof Element) { return input; + } else if (typeof input === "string") { + return root.find(input); // returns ElementCollection } else if (input && input._key) { return new ElementCollection([new Element(input._key)]); } else { @@ -347,6 +400,9 @@ function load(html) { } }; + \$.html = function() { + return root.html(); + }; \$.root = root; \$.Element = Element; \$.Collection = ElementCollection; diff --git a/lib/eval/lnreader/js_libs.dart b/lib/eval/lnreader/js_libs.dart index 1c7f9bc6..23d1fd65 100644 --- a/lib/eval/lnreader/js_libs.dart +++ b/lib/eval/lnreader/js_libs.dart @@ -72,6 +72,10 @@ String.prototype.substringBetween = function(left, right) { return this.substring(leftIndex, rightIndex); } +async function jsonStringify(fn) { + return JSON.stringify(await fn()); +} + const isUrlAbsolute = url => { if (url) { if (url.indexOf("//") === 0) { diff --git a/lib/eval/lnreader/js_polyfills.dart b/lib/eval/lnreader/js_polyfills.dart index 4ccd38ea..f887dc79 100644 --- a/lib/eval/lnreader/js_polyfills.dart +++ b/lib/eval/lnreader/js_polyfills.dart @@ -6,7 +6,19 @@ class JsPolyfills { void init() { runtime.evaluate(''' -const global="object"==typeof globalThis?globalThis:"object"==typeof window?window:"object"==typeof self?self:this,_FormData=global.FormData,_send=global.XMLHttpRequest&&global.XMLHttpRequest.prototype.send,_fetch=global.Request&&global.fetch,_sendBeacon=global.navigator&&global.navigator.sendBeacon,_match=global.Element&&global.Element.prototype,stringTag=global.Symbol&&Symbol.toStringTag;function ensureArgs(e,t){if(e.lengthe.replace(/\n/g,"%0A").replace(/\r/g,"%0D").replace(/"/g,"%22");class FormData{constructor(e){this._data=[];const t=this;e&&each(e.elements,(e=>{if(e.name&&!e.disabled&&"submit"!==e.type&&"button"!==e.type&&!e.matches("form fieldset[disabled] *"))if("file"===e.type){each(e.files&&e.files.length?e.files:[new File([],"",{type:"application/octet-stream"})],(a=>{t.append(e.name,a)}))}else if("select-multiple"===e.type||"select-one"===e.type)each(e.options,(a=>{!a.disabled&&a.selected&&t.append(e.name,a.value)}));else if("checkbox"===e.type||"radio"===e.type)e.checked&&t.append(e.name,e.value);else{const a="textarea"===e.type?normalizeLinefeeds(e.value):e.value;t.append(e.name,a)}}))}append(e,t,a){ensureArgs(arguments,2),this._data.push(normalizeArgs(e,t,a))}delete(e){ensureArgs(arguments,1);const t=[];e=String(e),each(this._data,(a=>{a[0]!==e&&t.push(a)})),this._data=t}*entries(){for(var e=0;e{a[0]===e&&t.push(a[1])})),t}has(e){ensureArgs(arguments,1),e=String(e);for(let t=0;t{t[0]===e?s&&(s=!n.push(r)):n.push(t)})),s&&n.push(r),this._data=n}*values(){for(const[,e]of this)yield e}_asNative(){const e=new _FormData;for(const[t,a]of this)e.append(t,a);return e}_blob(){const e="----formdata-polyfill-"+Math.random(),t=[],a=`--\${e}\r\nContent-Disposition: form-data; name="`;return this.forEach(((e,n)=>"string"==typeof e?t.push(a+escape(normalizeLinefeeds(n))+`"\r\n\r\n\${normalizeLinefeeds(e)}\r\n`):t.push(a+escape(normalizeLinefeeds(n))+`"; filename="\${escape(e.name)}"\r\nContent-Type: \${e.type||"application/octet-stream"}\r\n\r\n`,e,"\r\n"))),t.push(`--\${e}--`),new Blob(t,{type:"multipart/form-data; boundary="+e})}[Symbol.iterator](){return this.entries()}toString(){return"[object FormData]"}}stringTag&&(FormData.prototype[stringTag]="FormData"); +class FormData { + constructor() { + this.params = {}; + } + + append(key, value) { + this.params[key] = value; + } + + toJSON() { + return this.params; + } +} '''); runtime.evaluate(''' /**! diff --git a/lib/eval/lnreader/m_plugin.dart b/lib/eval/lnreader/m_plugin.dart index aece88a8..8999d284 100644 --- a/lib/eval/lnreader/m_plugin.dart +++ b/lib/eval/lnreader/m_plugin.dart @@ -1,5 +1,3 @@ -import 'dart:convert'; - class ChapterItem { String name; String path; @@ -20,9 +18,10 @@ class ChapterItem { name: json['name'], path: json['path'], releaseTime: json['releaseTime'], - chapterNumber: - int.tryParse(json['chapterNumber']) ?? - (json['chapterNumber'] as num?)?.toInt(), + chapterNumber: json['chapterNumber'] != null + ? (json['chapterNumber'] as num?)?.toInt() ?? + int.tryParse(json['chapterNumber']) + : null, page: json['page'], ); } diff --git a/lib/eval/lnreader/service.dart b/lib/eval/lnreader/service.dart index 92c7cf0f..9bd9a50e 100644 --- a/lib/eval/lnreader/service.dart +++ b/lib/eval/lnreader/service.dart @@ -45,9 +45,6 @@ module={},exports=Function("return this")(),Object.defineProperties(module,{name JsHtmlParser(runtime).init(); JsCheerio(runtime).init(); runtime.evaluate(''' -async function jsonStringify(fn) { - return JSON.stringify(await fn()); -} const require = (package) => { switch (package) { case "htmlparser2":