diff --git a/.eslintignore b/.eslintignore index 5bd03380..e0983f1a 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,4 +1,5 @@ node_modules *.d.ts -/docs +/docs/.vitepress/cache +/docs/.vitepress/dist /dist diff --git a/.vscode/settings.json b/.vscode/settings.json index 51273625..04aeebc1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,6 +3,8 @@ // 使用 eslint 格式化代码 "eslint.enable": true, + "eslint.validate": ["javascript", "html", "vue", "typescript"], + "[vue]": { "editor.defaultFormatter": "dbaeumer.vscode-eslint" }, diff --git a/alias.ts b/alias.ts new file mode 100644 index 00000000..66e9a568 --- /dev/null +++ b/alias.ts @@ -0,0 +1,12 @@ +import { resolve } from 'path'; + +function r(p: string) { + return resolve(__dirname, p); +} + +export const alias: Record = { + '@any-reader/core': r('./packages/core/src'), + '@any-reader/shared': r('./packages/shared/src'), + '@any-reader/rule-utils': r('./packages/rule-utils/src'), + '@any-reader/epub': r('./packages/epub/src') +}; diff --git a/docs/index.md b/docs/index.md index c862ec8d..1a11398f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -29,8 +29,8 @@ corepack enable # 安装依赖 pnpm i -# 编译 解析库、工具库、前端模板 -pnpm run build +# 运行网页版 +pnpm run web:dev ``` ### 源码目录结构 diff --git a/docs/package.json b/docs/package.json index 4b17185e..760890bc 100644 --- a/docs/package.json +++ b/docs/package.json @@ -9,6 +9,7 @@ "docs:preview": "vitepress preview" }, "devDependencies": { + "@any-reader/core": "workspace:^", "mermaid": "^11.2.0", "vitepress": "^1.3.4", "vitepress-plugin-mermaid": "^2.0.16" diff --git a/docs/vite.config.ts b/docs/vite.config.ts index 3558433f..83c01d06 100644 --- a/docs/vite.config.ts +++ b/docs/vite.config.ts @@ -1,4 +1,5 @@ import { defineConfig } from 'vite'; +import { alias } from '../alias'; export default defineConfig({ optimizeDeps: { @@ -8,5 +9,9 @@ export default defineConfig({ hmr: { overlay: false } + }, + + resolve: { + alias } }); diff --git a/packages/core/__test__/analyzer.test.ts b/packages/core/__test__/analyzer.test.ts index c5593f2b..d45929e6 100644 --- a/packages/core/__test__/analyzer.test.ts +++ b/packages/core/__test__/analyzer.test.ts @@ -1,7 +1,10 @@ import { describe, expect, it } from 'vitest'; import { createAnalyzerManager } from '../src'; +import { JSEngine } from '../src/analyzer/JSEngine'; -const analyzerManager = createAnalyzerManager(); +const analyzerManager = createAnalyzerManager({ + JSEngine +}); describe('analyzer', () => { it('CSS', async () => { diff --git a/packages/core/build.config.ts b/packages/core/build.config.ts index cbf623f6..5e9983a0 100644 --- a/packages/core/build.config.ts +++ b/packages/core/build.config.ts @@ -1,7 +1,7 @@ import { defineBuildConfig } from 'unbuild'; export default defineBuildConfig({ - entries: ['src/index'], + entries: ['src/index', 'src/browser/index'], clean: true, declaration: true, rollup: { diff --git a/packages/core/package.json b/packages/core/package.json index 763c8182..3f6e65c9 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -14,6 +14,10 @@ ".": { "require": "./dist/index.cjs", "import": "./dist/index.mjs" + }, + "./browser": { + "require": "./dist/browser/index.cjs", + "import": "./dist/browser/index.mjs" } }, "main": "./dist/index.cjs", @@ -27,6 +31,7 @@ "stub": "unbuild --stub" }, "dependencies": { + "@any-reader/rule-utils": "workspace:^", "@xmldom/xmldom": "^0.9.2", "axios": "^1.7.7", "chardet": "^2.0.0", @@ -41,7 +46,6 @@ "xpath.js": "^1.1.0" }, "devDependencies": { - "@any-reader/rule-utils": "workspace:^", "@types/content-type": "^1.1.8", "@types/crypto-js": "^4.2.2", "@types/xmldom": "^0.1.34", diff --git a/packages/core/src/analyzer.ts b/packages/core/src/analyzer.ts index 5e99801a..6af3bbd1 100644 --- a/packages/core/src/analyzer.ts +++ b/packages/core/src/analyzer.ts @@ -2,19 +2,22 @@ import { AnalyzerFilter } from './analyzer/AnalyzerFilter'; import { AnalyzerHtml } from './analyzer/AnalyzerHtml'; import { AnalyzerJS } from './analyzer/AnalyzerJS'; import { AnalyzerJSONPath } from './analyzer/AnalyzerJSONPath'; -import { AnalyzerManager, Analyzers } from './analyzer/AnalyzerManager'; import { AnalyzerRegExp } from './analyzer/AnalyzerRegExp'; import { AnalyzerReplace } from './analyzer/AnalyzerReplace'; import { AnalyzerXPath } from './analyzer/AnalyzerXPath'; import { AnalyzerWeb } from './analyzer/AnalyzerWeb'; -import { ILogger, LogLevel, NoLogger } from './logger'; +import { AnalyzerManager, AnalyzerManagerOption } from './analyzer/AnalyzerManager'; +import { LogLevel, NoLogger } from './logger'; +import { JSEngine } from './analyzer/JSEngine'; export { analyzerUrl } from './analyzer/analyzerUrl'; +export { AnalyzerHtml, AnalyzerJS, AnalyzerJSONPath, AnalyzerRegExp, AnalyzerReplace, AnalyzerXPath, AnalyzerFilter, AnalyzerWeb }; -export function createAnalyzerManager(params: { analyzers?: Analyzers[]; logger?: ILogger; logLevel?: LogLevel } = {}): AnalyzerManager { +export function createAnalyzerManager(params: Partial = {}): AnalyzerManager { return new AnalyzerManager({ logger: params.logger || new NoLogger(), logLevel: params.logLevel || LogLevel.Off, + JSEngine: params.JSEngine || JSEngine, analyzers: params.analyzers || [ { pattern: /^@css:/i, diff --git a/packages/core/src/analyzer/Analyzer.ts b/packages/core/src/analyzer/Analyzer.ts index 887e6054..451f5292 100644 --- a/packages/core/src/analyzer/Analyzer.ts +++ b/packages/core/src/analyzer/Analyzer.ts @@ -1,3 +1,5 @@ +import type { JSEngine } from '../sandbox/JSEngine'; + export abstract class IAnalyzer { abstract parse(content: string): void; abstract getString(rule: string): Promise; @@ -6,6 +8,12 @@ export abstract class IAnalyzer { } export class Analyzer implements IAnalyzer { + JSEngine: typeof JSEngine; + + constructor(options: { JSEngine: typeof JSEngine }) { + this.JSEngine = options.JSEngine; + } + parse(_: string): void { throw new Error('Method not implemented.'); } diff --git a/packages/core/src/analyzer/AnalyzerFilter.ts b/packages/core/src/analyzer/AnalyzerFilter.ts index 3de306e5..c1688c95 100644 --- a/packages/core/src/analyzer/AnalyzerFilter.ts +++ b/packages/core/src/analyzer/AnalyzerFilter.ts @@ -1,7 +1,7 @@ import puppeteer from 'puppeteer'; -import type { Analyzer } from './Analyzer'; +import { Analyzer } from './Analyzer'; -export class AnalyzerFilter implements Analyzer { +export class AnalyzerFilter extends Analyzer { private _content!: string; private _url!: string; diff --git a/packages/core/src/analyzer/AnalyzerHtml.ts b/packages/core/src/analyzer/AnalyzerHtml.ts index bde7eab3..f9dce929 100644 --- a/packages/core/src/analyzer/AnalyzerHtml.ts +++ b/packages/core/src/analyzer/AnalyzerHtml.ts @@ -1,5 +1,5 @@ import { load } from 'cheerio'; -import type { Analyzer } from './Analyzer'; +import { Analyzer } from './Analyzer'; function htmlDecode(str: string) { return str @@ -21,7 +21,7 @@ function getHtmlString(html: string) { return htmlDecode(html.replaceAll(/<\/?(?:div|p|br|hr|h\d|article|b|dd|dl)[^>]*>/g, '\n').replace(//gim, '')); } -export class AnalyzerHtml implements Analyzer { +export class AnalyzerHtml extends Analyzer { _content!: string; parse(content: string | string[]) { diff --git a/packages/core/src/analyzer/AnalyzerJS.ts b/packages/core/src/analyzer/AnalyzerJS.ts index 5c716fe8..460e347e 100644 --- a/packages/core/src/analyzer/AnalyzerJS.ts +++ b/packages/core/src/analyzer/AnalyzerJS.ts @@ -1,7 +1,6 @@ -import { JSEngine } from './JSEngine'; -import type { Analyzer } from './Analyzer'; +import { Analyzer } from './Analyzer'; -export class AnalyzerJS implements Analyzer { +export class AnalyzerJS extends Analyzer { _content!: any; parse(content: any) { @@ -14,11 +13,11 @@ export class AnalyzerJS implements Analyzer { } async getStringList(rule: string): Promise { - return this.getElements(rule); + return this.getElements(rule) as Promise; } async getElements(rule: string) { - return await JSEngine.evaluate(rule, { + return await this.JSEngine.evaluate(rule, { result: this._content }); } diff --git a/packages/core/src/analyzer/AnalyzerJSONPath.ts b/packages/core/src/analyzer/AnalyzerJSONPath.ts index f7e9e2ee..0be5a332 100644 --- a/packages/core/src/analyzer/AnalyzerJSONPath.ts +++ b/packages/core/src/analyzer/AnalyzerJSONPath.ts @@ -1,7 +1,7 @@ import { JSONPath } from 'jsonpath-plus'; -import type { Analyzer } from './Analyzer'; +import { Analyzer } from './Analyzer'; -export class AnalyzerJSONPath implements Analyzer { +export class AnalyzerJSONPath extends Analyzer { _content!: any; parse(content: string | any) { diff --git a/packages/core/src/analyzer/AnalyzerManager.ts b/packages/core/src/analyzer/AnalyzerManager.ts index 24f18012..65017c90 100644 --- a/packages/core/src/analyzer/AnalyzerManager.ts +++ b/packages/core/src/analyzer/AnalyzerManager.ts @@ -2,6 +2,7 @@ import { AnalyzerException } from '../exception/AnalyzerException'; import { ILogger, LogLevel } from '../logger'; import type { Analyzer } from './Analyzer'; import { AnalyzerJS } from './AnalyzerJS'; +import type { JSEngine } from '../sandbox/JSEngine'; const RULE_TYPE_PATTERN = /@js:|@hetu:|@web:|@webview:|@css:|@json:|@http:|@xpath:|@match:|@regex:|@regexp:|@filter:|@replace:|@encode:|@decode:|^/gi; @@ -26,15 +27,24 @@ export interface Analyzers { Analyzer: typeof Analyzer; } +export interface AnalyzerManagerOption { + analyzers: Analyzers[]; + logger: ILogger; + logLevel: LogLevel; + JSEngine: typeof JSEngine; +} + export class AnalyzerManager { public analyzers: Analyzers[]; public logger: ILogger; public logLevel: LogLevel; + public JSEngine: typeof JSEngine; - constructor(params: { analyzers: Analyzers[]; logger: ILogger; logLevel: LogLevel }) { + constructor(params: AnalyzerManagerOption) { this.analyzers = params.analyzers || []; this.logger = params.logger || console; this.logLevel = params.logLevel || LogLevel.Off; + this.JSEngine = params.JSEngine; } getAnalyzer(rule: string) { @@ -57,9 +67,25 @@ export class AnalyzerManager { r = r.replace(analyzer.replace || analyzer.pattern, ''); const position = r.indexOf('##'); if (position > -1) { - ruleList.push(new SingleRule(new analyzer.Analyzer(), r.substring(0, position), r.substring(position + 2))); + ruleList.push( + new SingleRule( + new analyzer.Analyzer({ + JSEngine: this.JSEngine + }), + r.substring(0, position), + r.substring(position + 2) + ) + ); } else { - ruleList.push(new SingleRule(new analyzer.Analyzer(), r, '')); + ruleList.push( + new SingleRule( + new analyzer.Analyzer({ + JSEngine: this.JSEngine + }), + r, + '' + ) + ); } } return ruleList.reverse(); @@ -96,7 +122,7 @@ export class AnalyzerManager { } } - async getElements(rule: string, body: string): Promise { + public async getElements(rule: string, body: string): Promise { let temp: string | string[] = body; for (const r of this.splitRuleReversed(rule)) { @@ -141,7 +167,7 @@ export class AnalyzerManager { } } - async getString(rule: string, body: string): Promise { + public async getString(rule: string, body: string): Promise { if (!rule) return ''; const expressionPattern = /\{\{(.*?)\}\}/g; @@ -180,7 +206,7 @@ export class AnalyzerManager { } } - async getStringList(rule: string, body: string): Promise { + public async getStringList(rule: string, body: string): Promise { if (!rule) return []; const expressionPattern = /\{\{(.*?)\}\}/g; @@ -209,7 +235,12 @@ export class AnalyzerManager { return Array.isArray(temp) ? temp : [temp]; } - async getUrl(rule: string, host: string, body: string): Promise { + public async parseJsUrl(url: string) { + if (url.startsWith('@js:')) return await this.JSEngine.evaluate(url.substring(4)); + return url; + } + + public async getUrl(rule: string, host = '', body = ''): Promise { let url = await this.getString(rule, body); if (typeof url !== 'string') return url; diff --git a/packages/core/src/analyzer/AnalyzerRegExp.ts b/packages/core/src/analyzer/AnalyzerRegExp.ts index 36df98e5..c36ae981 100644 --- a/packages/core/src/analyzer/AnalyzerRegExp.ts +++ b/packages/core/src/analyzer/AnalyzerRegExp.ts @@ -1,6 +1,6 @@ -import type { Analyzer } from './Analyzer'; +import { Analyzer } from './Analyzer'; -export class AnalyzerRegExp implements Analyzer { +export class AnalyzerRegExp extends Analyzer { _content!: string; parse(content: string) { diff --git a/packages/core/src/analyzer/AnalyzerReplace.ts b/packages/core/src/analyzer/AnalyzerReplace.ts index e19011fc..aef8d9c2 100644 --- a/packages/core/src/analyzer/AnalyzerReplace.ts +++ b/packages/core/src/analyzer/AnalyzerReplace.ts @@ -1,6 +1,6 @@ -import type { Analyzer } from './Analyzer'; +import { Analyzer } from './Analyzer'; -export class AnalyzerReplace implements Analyzer { +export class AnalyzerReplace extends Analyzer { private _content!: string; replaceSmart(replace: string) { diff --git a/packages/core/src/analyzer/AnalyzerWeb.ts b/packages/core/src/analyzer/AnalyzerWeb.ts index c647a95b..28b9db30 100644 --- a/packages/core/src/analyzer/AnalyzerWeb.ts +++ b/packages/core/src/analyzer/AnalyzerWeb.ts @@ -1,9 +1,8 @@ import type { Rule } from '@any-reader/rule-utils'; -import type { Analyzer } from './Analyzer'; +import { Analyzer } from './Analyzer'; import { analyzerUrl } from './analyzerUrl'; -import { JSEngine } from './JSEngine'; -export class AnalyzerWeb implements Analyzer { +export class AnalyzerWeb extends Analyzer { _content!: string; parse(content: string) { @@ -11,7 +10,7 @@ export class AnalyzerWeb implements Analyzer { } async getString(rule: string): Promise { - return (await analyzerUrl(rule, '', '', JSEngine.environment.rule as Rule)).body; + return (await analyzerUrl(rule, '', '', this.JSEngine.environment.rule as Rule)).body; } getStringList(_: string): Promise { diff --git a/packages/core/src/analyzer/AnalyzerXPath.ts b/packages/core/src/analyzer/AnalyzerXPath.ts index 2420e570..ef73db47 100644 --- a/packages/core/src/analyzer/AnalyzerXPath.ts +++ b/packages/core/src/analyzer/AnalyzerXPath.ts @@ -1,8 +1,8 @@ import xpath from 'xpath.js'; import { DOMParser, MIME_TYPE } from '@xmldom/xmldom'; -import type { Analyzer } from './Analyzer'; +import { Analyzer } from './Analyzer'; -export class AnalyzerXPath implements Analyzer { +export class AnalyzerXPath extends Analyzer { _content!: string; parse(content: string | string[]) { diff --git a/packages/core/src/analyzer/JSEngine.ts b/packages/core/src/analyzer/JSEngine.ts index 73bc73b2..091b512e 100644 --- a/packages/core/src/analyzer/JSEngine.ts +++ b/packages/core/src/analyzer/JSEngine.ts @@ -5,8 +5,9 @@ import type { Rule } from '@any-reader/rule-utils'; import { AnalyzerXPath } from '../analyzer/AnalyzerXPath'; import { JsVmException } from '../exception/JsVmException'; import { __http__ } from './request'; +import { JSEngine as BaseJSEngine } from '../sandbox/JSEngine'; -export class JSEngine { +export class JSEngine extends BaseJSEngine { static environment: any = {}; static VMCtx: any; @@ -33,7 +34,9 @@ export class JSEngine { }, http, xpath: async (html: string, xpath: string): Promise => { - const analyzer = new AnalyzerXPath(); + const analyzer = new AnalyzerXPath({ + JSEngine: null as unknown as typeof JSEngine + }); analyzer.parse(html); return await analyzer.getStringList(xpath); } diff --git a/packages/core/src/analyzer/RuleManager.ts b/packages/core/src/analyzer/RuleManager.ts index 6ce95674..1ad6016a 100644 --- a/packages/core/src/analyzer/RuleManager.ts +++ b/packages/core/src/analyzer/RuleManager.ts @@ -1,6 +1,5 @@ import { ContentType } from '@any-reader/rule-utils'; import type { Rule } from '@any-reader/rule-utils'; -import { JSEngine } from './JSEngine'; import type { AnalyzerManager } from './AnalyzerManager'; import { fetch, parseRequest } from './request'; import { ChapterItem, DiscoverItem, IParser } from '../parser/parser'; @@ -16,8 +15,9 @@ export class RuleManager implements IParser { constructor(rule: Rule, analyzerManager: AnalyzerManager) { this.rule = rule; this._nextUrl = new Map(); - JSEngine.init(); - JSEngine.setEnvironment({ + this.analyzerManager = analyzerManager; + this.JSEngine.init(); + this.JSEngine.setEnvironment({ host: this.rule.host, $host: this.rule.host, cookie: this.rule.cookies, @@ -27,25 +27,23 @@ export class RuleManager implements IParser { $pageSize: 20, searchPage: 1 }); - this.analyzerManager = analyzerManager; - this.analyzerManager.logLevel >= LogLevel.Debug && this.analyzerManager.logger.debug(`[init] rule:${rule.name}`); + this.analyzerManager.logLevel >= LogLevel.Debug && this.analyzerManager.logger.debug(`[初始化规则] ${rule.id} ${rule.name}`); + } + + private get JSEngine() { + return this.analyzerManager.JSEngine; } private async request(params: any) { - this.analyzerManager.logLevel >= LogLevel.Debug && this.analyzerManager.logger.debug(`[request] params:${JSON.stringify(params || {})}`); + this.analyzerManager.logLevel >= LogLevel.Debug && this.analyzerManager.logger.debug(`[网络请求] -> ${JSON.stringify(params || {})}`); const res = await fetch(params); - this.analyzerManager.logLevel >= LogLevel.Debug && this.analyzerManager.logger.debug(`[request] query:${String(res.body)}`); + this.analyzerManager.logLevel >= LogLevel.Debug && this.analyzerManager.logger.debug(`[网络请求] <- ${String(res.body)}`); return res; } - private async parseJsUrl(url: string) { - if (url.startsWith('@js:')) url = await JSEngine.evaluate(url.substring(4)); - return url; - } - async search(query: string, page = 1, pageSize = 20) { // const hasNextUrlRule = this.rule.searchNextUrl !== null && this.rule.searchNextUrl.length > 0; - this.analyzerManager.logLevel >= LogLevel.Debug && this.analyzerManager.logger.debug(`[search] query:${query}`); + this.analyzerManager.logLevel >= LogLevel.Debug && this.analyzerManager.logger.debug(`[搜索] ${query}`); let searchRule = ''; let url = this.rule.searchUrl; @@ -75,18 +73,15 @@ export class RuleManager implements IParser { let searchUrl = ''; let body = ''; - JSEngine.setEnvironment({ + this.JSEngine.setEnvironment({ page, $keyword: query, keyword: query, searchKey: query }); - this.analyzerManager.logLevel >= LogLevel.Debug && this.analyzerManager.logger.debug(`[search] searchRule:${searchRule}`); if (this.rule.searchUrl !== 'null') { - const res = await this.request(parseRequest(await this.parseJsUrl(searchRule), query, '', this.rule, page, pageSize)); - this.analyzerManager.logLevel >= LogLevel.Debug && this.analyzerManager.logger.debug(`[search] params:${JSON.stringify(res.params || {})}`); - this.analyzerManager.logLevel >= LogLevel.Debug && this.analyzerManager.logger.debug(`[search] body:${String(res.body)}`); + const res = await this.request(parseRequest(await this.analyzerManager.parseJsUrl(searchRule), query, '', this.rule, page, pageSize)); body = res.body; searchUrl = res.params.url as string; } @@ -95,9 +90,7 @@ export class RuleManager implements IParser { // next = await this.analyzerManager.getString(this.rule.searchNextUrl, body); // } - this.analyzerManager.logLevel >= LogLevel.Debug && this.analyzerManager.logger.debug(`[search] rule.searchList:${this.rule.searchList}`); const list = await this.getList(body, this.rule.searchList); - this.analyzerManager.logLevel >= LogLevel.Debug && this.analyzerManager.logger.debug(`[search] list:${JSON.stringify(list || [])}}`); const result = []; for (const item of list) { @@ -124,7 +117,7 @@ export class RuleManager implements IParser { async getChapter(result: string, page = 1): Promise { this.analyzerManager.logLevel >= LogLevel.Debug && this.analyzerManager.logger.debug(`[getChapter] result:${result}`); - JSEngine.setEnvironment({ + this.JSEngine.setEnvironment({ result }); if (this.rule.chapterUrl === '正文') { @@ -140,19 +133,19 @@ export class RuleManager implements IParser { const chapterUrl = this.rule.chapterUrl || result; let body = ''; - JSEngine.setEnvironment({ + this.JSEngine.setEnvironment({ page }); if (chapterUrl !== 'null') { - const res = await this.request(parseRequest(await this.parseJsUrl(chapterUrl), '', result, this.rule, page)); + const res = await this.request(parseRequest(await this.analyzerManager.parseJsUrl(chapterUrl), '', result, this.rule, page)); body = res.body; - JSEngine.setEnvironment({ + this.JSEngine.setEnvironment({ baseUrl: res.params.url }); } - JSEngine.setEnvironment({ + this.JSEngine.setEnvironment({ lastResult: result, result: body }); @@ -183,7 +176,7 @@ export class RuleManager implements IParser { async getContent(lastResult: string): Promise { this.analyzerManager.logLevel >= LogLevel.Debug && this.analyzerManager.logger.debug(`[getChapter] result:${lastResult}`); - JSEngine.setEnvironment({ + this.JSEngine.setEnvironment({ result: lastResult }); const hasNextUrlRule = !!this.rule.contentNextUrl; @@ -215,12 +208,12 @@ export class RuleManager implements IParser { let body = ''; if (contentUrlRule !== 'null') { - const res = await this.request(parseRequest(await this.parseJsUrl(contentUrlRule), '', lastResult, this.rule)); + const res = await this.request(parseRequest(await this.analyzerManager.parseJsUrl(contentUrlRule), '', lastResult, this.rule)); contentUrl = res.params.url; body = res.body; } - JSEngine.setEnvironment({ + this.JSEngine.setEnvironment({ page, lastResult: lastResult, result: body, @@ -260,11 +253,11 @@ export class RuleManager implements IParser { let discoverUrl = this.rule.discoverUrl.trimStart(); if (discoverUrl.startsWith('@js:')) { - JSEngine.setEnvironment({ + this.JSEngine.setEnvironment({ page: 1, baseUrl: this.rule.host }); - discoverUrl = await JSEngine.evaluate(`${discoverUrl.substring(4)};`); + discoverUrl = (await this.JSEngine.evaluate(`${discoverUrl.substring(4)};`)) as string; } const discovers = Array.isArray(discoverUrl) @@ -337,7 +330,7 @@ export class RuleManager implements IParser { // 获取分类下内容 async discover(url: string, page = 1) { - JSEngine.setEnvironment({ + this.JSEngine.setEnvironment({ result: url }); const hasNextUrlRule = this.rule.discoverNextUrl !== undefined && this.rule.discoverNextUrl.length > 0; @@ -358,11 +351,11 @@ export class RuleManager implements IParser { let body = ''; if (discoverRule !== 'null') { - const { body: res } = await this.request(parseRequest(await this.parseJsUrl(discoverRule), '', '', this.rule)); + const { body: res } = await this.request(parseRequest(await this.analyzerManager.parseJsUrl(discoverRule), '', '', this.rule)); body = res; } - JSEngine.setEnvironment({ + this.JSEngine.setEnvironment({ page: 1, lastResult: url, result: body, diff --git a/packages/core/src/browser/analyzer.ts b/packages/core/src/browser/analyzer.ts new file mode 100644 index 00000000..46788491 --- /dev/null +++ b/packages/core/src/browser/analyzer.ts @@ -0,0 +1,56 @@ +import { AnalyzerHtml } from '../analyzer/AnalyzerHtml'; +import { AnalyzerJS } from '../analyzer/AnalyzerJS'; +import { AnalyzerJSONPath } from '../analyzer/AnalyzerJSONPath'; +import { AnalyzerRegExp } from '../analyzer/AnalyzerRegExp'; +import { AnalyzerReplace } from '../analyzer/AnalyzerReplace'; +import { AnalyzerXPath } from '../analyzer/AnalyzerXPath'; +import { AnalyzerManager, AnalyzerManagerOption } from '../analyzer/AnalyzerManager'; +import { LogLevel, NoLogger } from '../logger'; +import { JSEngine } from '../analyzer/JSEngine'; + +export { AnalyzerHtml, AnalyzerJS, AnalyzerJSONPath, AnalyzerRegExp, AnalyzerReplace, AnalyzerXPath }; + +export function createAnalyzerManager(params: Partial = {}): AnalyzerManager { + return new AnalyzerManager({ + logger: params.logger || new NoLogger(), + logLevel: params.logLevel || LogLevel.Off, + JSEngine: params.JSEngine || JSEngine, + analyzers: params.analyzers || [ + { + pattern: /^@css:/i, + Analyzer: AnalyzerHtml + }, + { + pattern: /^@json:|^\$/i, + replace: /^@json:/i, + Analyzer: AnalyzerJSONPath + }, + + { + pattern: /^@xpath:|^\//i, + replace: /^@xpath:/i, + Analyzer: AnalyzerXPath + }, + { + pattern: /^@regexp:|^@regex:|^:/i, + Analyzer: AnalyzerRegExp + }, + { + pattern: /^@js:/i, + Analyzer: AnalyzerJS + }, + // { + // pattern: /^@filter:/i, + // Analyzer: AnalyzerFilter + // }, + { + pattern: /^@replace:/i, + Analyzer: AnalyzerReplace + } + // { + // pattern: /^@web:|@webview:/i, + // Analyzer: AnalyzerWeb + // } + ] + }); +} diff --git a/packages/core/src/browser/analyzer/JSEngine.ts b/packages/core/src/browser/analyzer/JSEngine.ts new file mode 100644 index 00000000..c6ad9eb7 --- /dev/null +++ b/packages/core/src/browser/analyzer/JSEngine.ts @@ -0,0 +1,12 @@ +import { JSEngine as BaseJSEngine } from '../../sandbox/JSEngine'; + +// TODO: JSEngine +export class JSEngine extends BaseJSEngine { + static setEnvironment() {} + + static init() {} + + static async evaluate(command: string, _context: any = {}) { + return eval(command); + } +} diff --git a/packages/core/src/browser/index.ts b/packages/core/src/browser/index.ts new file mode 100644 index 00000000..6d2c8617 --- /dev/null +++ b/packages/core/src/browser/index.ts @@ -0,0 +1,16 @@ +import type { Rule } from '@any-reader/rule-utils'; + +import { AnalyzerManager } from '../analyzer/AnalyzerManager'; +import IPTV from '../parser/iptv'; +import { RuleManager } from '../analyzer/RuleManager'; +import { createAnalyzerManager } from './analyzer'; + +export * from './analyzer'; + +export function createRuleManager(rule: Rule, analyzerManager?: AnalyzerManager) { + // if (rule.loadJs && typeof rule.loadJs === 'string' && /^\/\/\s*@any-reader\/parser\/iptv\s*$/.test(rule.loadJs)) { + if (rule.loadJs === '// @any-reader/parser/iptv') { + return new IPTV(rule); + } + return new RuleManager(rule, analyzerManager || createAnalyzerManager({})); +} diff --git a/packages/core/src/sandbox/JSEngine.ts b/packages/core/src/sandbox/JSEngine.ts new file mode 100644 index 00000000..ab80f60a --- /dev/null +++ b/packages/core/src/sandbox/JSEngine.ts @@ -0,0 +1,11 @@ +export class JSEngine { + static environment: any; + + static init() {} + + static setEnvironment(_arg0: any) {} + + static async evaluate(..._arg0: any): Promise { + throw new Error('Method not implemented.'); + } +} diff --git a/packages/shared/src/app.ts b/packages/shared/src/app.ts index 07b7b78d..eb4267da 100644 --- a/packages/shared/src/app.ts +++ b/packages/shared/src/app.ts @@ -79,12 +79,12 @@ async function runApp(app: App, register: any) { const callName = [route.method.toLowerCase(), route.route].join('@'); register(callName, async (...arg: any) => { const instance: any = new Controller(app); - app.analyzerManager.logLevel >= LogLevel.Debug && app.analyzerManager.logger.debug(`[api] ${callName} ${JSON.stringify(arg)}`); + app.analyzerManager.logLevel >= LogLevel.Debug && app.analyzerManager.logger.debug(`[call] ${callName} ${JSON.stringify(arg)}`); return await instance[route.methodName](...arg) .then((res: any) => result(res)) .catch((err: Error) => { - app.analyzerManager.logLevel >= LogLevel.Error && err.message && app.analyzerManager.logger.error(err.message); + app.analyzerManager.logLevel >= LogLevel.Error && err.message && app.analyzerManager.logger.error(`[错误] ${err.message}`); let message = err?.message || 'error'; if (err instanceof FetchException) message = '网络请求异常'; else if (err instanceof JsVmException) message = '执行脚本异常'; diff --git a/packages/web/.gitignore b/packages/web/.gitignore index 69dce891..a4ac41d5 100644 --- a/packages/web/.gitignore +++ b/packages/web/.gitignore @@ -29,3 +29,4 @@ coverage # /auto-imports.d.ts # /.eslintrc-auto-import.json +/components.d.ts \ No newline at end of file diff --git a/packages/web/components.d.ts b/packages/web/components.d.ts deleted file mode 100644 index fa8336ef..00000000 --- a/packages/web/components.d.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* eslint-disable */ -// @ts-nocheck -// Generated by unplugin-vue-components -// Read more: https://github.com/vuejs/core/pull/3399 -export {} - -/* prettier-ignore */ -declare module 'vue' { - export interface GlobalComponents { - AApp: typeof import('ant-design-vue/es')['App'] - AButton: typeof import('ant-design-vue/es')['Button'] - ACheckboxGroup: typeof import('ant-design-vue/es')['CheckboxGroup'] - AConfigProvider: typeof import('ant-design-vue/es')['ConfigProvider'] - ADivider: typeof import('ant-design-vue/es')['Divider'] - ADropdown: typeof import('ant-design-vue/es')['Dropdown'] - AEmpty: typeof import('ant-design-vue/es')['Empty'] - AFloatButton: typeof import('ant-design-vue/es')['FloatButton'] - AFloatButtonGroup: typeof import('ant-design-vue/es')['FloatButtonGroup'] - AForm: typeof import('ant-design-vue/es')['Form'] - AFormItem: typeof import('ant-design-vue/es')['FormItem'] - AImage: typeof import('ant-design-vue/es')['Image'] - AInput: typeof import('ant-design-vue/es')['Input'] - AInputGroup: typeof import('ant-design-vue/es')['InputGroup'] - AInputNumber: typeof import('ant-design-vue/es')['InputNumber'] - AInputSearch: typeof import('ant-design-vue/es')['InputSearch'] - AMenu: typeof import('ant-design-vue/es')['Menu'] - AMenuDivider: typeof import('ant-design-vue/es')['MenuDivider'] - AMenuItem: typeof import('ant-design-vue/es')['MenuItem'] - ARadioButton: typeof import('ant-design-vue/es')['RadioButton'] - ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup'] - ASelect: typeof import('ant-design-vue/es')['Select'] - ASelectOption: typeof import('ant-design-vue/es')['SelectOption'] - ASpin: typeof import('ant-design-vue/es')['Spin'] - ASwitch: typeof import('ant-design-vue/es')['Switch'] - ATable: typeof import('ant-design-vue/es')['Table'] - ATextarea: typeof import('ant-design-vue/es')['Textarea'] - BugOutlined: typeof import('@ant-design/icons-vue')['BugOutlined'] - CopyOutlined: typeof import('@ant-design/icons-vue')['CopyOutlined'] - DownOutlined: typeof import('@ant-design/icons-vue')['DownOutlined'] - EditOutlined: typeof import('@ant-design/icons-vue')['EditOutlined'] - LeftOutlined: typeof import('@ant-design/icons-vue')['LeftOutlined'] - PlusOutlined: typeof import('@ant-design/icons-vue')['PlusOutlined'] - PushpinOutlined: typeof import('@ant-design/icons-vue')['PushpinOutlined'] - ReloadOutlined: typeof import('@ant-design/icons-vue')['ReloadOutlined'] - RightOutlined: typeof import('@ant-design/icons-vue')['RightOutlined'] - RouterLink: typeof import('vue-router')['RouterLink'] - RouterView: typeof import('vue-router')['RouterView'] - SettingOutlined: typeof import('@ant-design/icons-vue')['SettingOutlined'] - StarFilled: typeof import('@ant-design/icons-vue')['StarFilled'] - StarOutlined: typeof import('@ant-design/icons-vue')['StarOutlined'] - StopOutlined: typeof import('@ant-design/icons-vue')['StopOutlined'] - } -} diff --git a/packages/web/src/pages/pc/category/index.vue b/packages/web/src/pages/pc/category/index.vue index 9e9a3786..27444535 100644 --- a/packages/web/src/pages/pc/category/index.vue +++ b/packages/web/src/pages/pc/category/index.vue @@ -1,6 +1,6 @@ - + @@ -99,11 +99,14 @@ + + + +