diff --git a/esbuild.config.mjs b/esbuild.config.mjs index aaf5ad6..105f4cd 100644 --- a/esbuild.config.mjs +++ b/esbuild.config.mjs @@ -35,7 +35,7 @@ esbuild.build({ '@codemirror/panel', '@codemirror/rangeset', '@codemirror/rectangular-selection', - '@codemirror/search', + '@codemirror/searcher', '@codemirror/state', '@codemirror/stream-parser', '@codemirror/text', diff --git a/package-lock.json b/package-lock.json index 41f0185..3f598be 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,19 @@ { "name": "obsidian-douban-plugin", - "version": "1.9.3", + "version": "1.9.6", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "obsidian-douban-plugin", - "version": "1.9.3", + "version": "1.9.6", "license": "MIT", "dependencies": { "@notable/html2markdown": "^1.1.3", "@popperjs/core": "^2.11.6", "cheerio": "^1.0.0-rc.11", "follow-redirects": "^1.15.3", + "iconv-lite": "^0.6.3", "schema-dts": "^1.1.0" }, "devDependencies": { @@ -3290,6 +3291,17 @@ "node": ">=10.17.0" } }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", @@ -4872,6 +4884,11 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, "node_modules/schema-dts": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/schema-dts/-/schema-dts-1.1.0.tgz", @@ -7844,6 +7861,14 @@ "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, "ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", @@ -9020,6 +9045,11 @@ "queue-microtask": "^1.2.2" } }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, "schema-dts": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/schema-dts/-/schema-dts-1.1.0.tgz", diff --git a/src/org/wanxp/constant/Constsant.ts b/src/org/wanxp/constant/Constsant.ts index 120b3a2..f59b0c7 100644 --- a/src/org/wanxp/constant/Constsant.ts +++ b/src/org/wanxp/constant/Constsant.ts @@ -54,6 +54,7 @@ export const ESTIMATE_TIME_PER_WITH_REQUEST_SLOW: number = ESTIMATE_TIME_PER + B */ export const ESTIMATE_TIME_PER_WITH_REQUEST: number = ESTIMATE_TIME_PER + BasicConst.CALL_DOUBAN_DELAY + BasicConst.CALL_DOUBAN_DELAY_RANGE / 2; + /** * 模板类型 */ @@ -176,6 +177,20 @@ export enum PropertyName { content = "content", } +/** + * 名称模式选项 + */ +export const SearchTypeRecords: { [key in SupportType]: string } = { + [SupportType.ALL]: i18nHelper.getMessage('ALL'), + [SupportType.MOVIE]: i18nHelper.getMessage('MOVIE_AND_TELEPLAY'), + [SupportType.BOOK]: i18nHelper.getMessage('BOOK'), + [SupportType.MUSIC]: i18nHelper.getMessage('MUSIC'), + [SupportType.NOTE]: i18nHelper.getMessage('NOTE'), + [SupportType.GAME]: i18nHelper.getMessage('GAME'), + [SupportType.TELEPLAY]: i18nHelper.getMessage('TELEPLAY'), + [SupportType.THEATER]: i18nHelper.getMessage('THEATER'), +} + /** * 名称模式选项 */ @@ -296,7 +311,7 @@ export const DoubanSearchResultSubjectNextPageNeedLogin: DoubanSearchResultSubje url: NavigateType.nextNeedLogin } -export const SEARCH_ITEM_PAGE_SIZE: number = 20; +export const SEARCH_ITEM_PAGE_SIZE: number = 10; /** * 豆瓣默认请求头 diff --git a/src/org/wanxp/douban/data/model/SearchPage.ts b/src/org/wanxp/douban/data/model/SearchPage.ts index dd874af..1f4aee8 100644 --- a/src/org/wanxp/douban/data/model/SearchPage.ts +++ b/src/org/wanxp/douban/data/model/SearchPage.ts @@ -1,16 +1,21 @@ import {SearchPageInfo} from "./SearchPageInfo"; +import {SupportType} from "../../../constant/Constsant"; export class SearchPage extends SearchPageInfo{ private _list:any[]; - constructor(total: number, pageNum: number, pageSize: number, list: any[]) { - super(total, pageNum, pageSize); + constructor(total: number, pageNum: number, pageSize: number, type:SupportType, list: any[]) { + super(total, pageNum, pageSize, type); this._list = list; } public get list() { return this._list; } + + public static empty(type:SupportType):SearchPage { + return new SearchPage(0, 0, 0, type, []); + } } diff --git a/src/org/wanxp/douban/data/model/SearchPageInfo.ts b/src/org/wanxp/douban/data/model/SearchPageInfo.ts index 4825c71..a2ac50c 100644 --- a/src/org/wanxp/douban/data/model/SearchPageInfo.ts +++ b/src/org/wanxp/douban/data/model/SearchPageInfo.ts @@ -1,15 +1,19 @@ +import {SupportType} from "../../../constant/Constsant"; + export class SearchPageInfo { private _total: number; private _pageSize: number; private _pageNum: number; private _hasNext: boolean; + private _type: SupportType; - constructor(total: number, pageNum: number, pageSize: number) { + constructor(total: number, pageNum: number, pageSize: number, type: SupportType) { this._total = total; this._pageNum = pageNum; this._pageSize = pageSize; this._hasNext = ((pageNum + 1) * pageSize) < total; + this._type = type; } public nextPage(): SearchPageInfo { @@ -17,7 +21,7 @@ export class SearchPageInfo { return this; } return new SearchPageInfo(this.total, this._pageNum + 1, - this._pageSize); + this._pageSize, this._type); } public previousPage(): SearchPageInfo { @@ -25,7 +29,12 @@ export class SearchPageInfo { return this; } return new SearchPageInfo(this.total, this._pageNum - 1, - this._pageSize); + this._pageSize, this._type); + } + + public typePage(type: SupportType): SearchPageInfo { + return new SearchPageInfo(this.total, 0, + this._pageSize, this._type); } @@ -53,4 +62,18 @@ export class SearchPageInfo { get pageNum(): number { return this._pageNum; } + + get type(): SupportType { + return this._type; + } + + allPage() { + if (this._pageNum == 0) { + return this; + } + return new SearchPageInfo(this.total, this._pageNum - 1, + this._pageSize, SupportType.ALL); + } + + } diff --git a/src/org/wanxp/douban/data/search/DoubanSearchFuzzySuggestModal.ts b/src/org/wanxp/douban/data/search/DoubanSearchFuzzySuggestModal.ts index 84aaa6b..6914f68 100644 --- a/src/org/wanxp/douban/data/search/DoubanSearchFuzzySuggestModal.ts +++ b/src/org/wanxp/douban/data/search/DoubanSearchFuzzySuggestModal.ts @@ -2,7 +2,7 @@ import { DoubanSearchResultSubjectNextPage, DoubanSearchResultSubjectNextPageNeedLogin, DoubanSearchResultSubjectPreviousPage, - NavigateType + NavigateType, SEARCH_ITEM_PAGE_SIZE, SupportType } from "../../../constant/Constsant"; import {FuzzySuggestModal, RequestUrlParam, request} from "obsidian"; @@ -11,13 +11,9 @@ import DoubanSearchResultSubject from "../model/DoubanSearchResultSubject"; import HandleContext from "../model/HandleContext"; import {SearchPage} from "../model/SearchPage"; import {SearchPageInfo} from "../model/SearchPageInfo"; -import Searcher from "./Search"; -import User from "../../user/User"; -import {flat} from "builtin-modules"; import {i18nHelper} from "../../../lang/helper"; -import {init} from "cjs-module-lexer"; -import {load} from "cheerio"; import {log} from "src/org/wanxp/utils/Logutil"; +import SearcherV2 from "./SearchV2"; export {DoubanFuzzySuggester} @@ -61,6 +57,12 @@ class DoubanFuzzySuggester extends FuzzySuggestModal } return; } + if(this.isTypeSelect(item)) { + if (await this.handleTypeSelect(item)) { + this.start(); + } + return; + } this.plugin.showStatus(i18nHelper.getMessage('140204', item.title)); this.context.listItem = item; if (item) { @@ -87,29 +89,28 @@ class DoubanFuzzySuggester extends FuzzySuggestModal break; } if (result) { - const searchPageResult: SearchPage = - await Searcher.loadSearchItem(this.searchItem, currentPage.start, this.plugin.settings, this.plugin.settingsManager); - this.context.searchPage = new SearchPageInfo(searchPageResult.total, currentPage.pageNum, searchPageResult.pageSize); - this.updatePageResult(searchPageResult); + // const searchPageResult: SearchPage = + // await SearcherV2.loadSearchItem(this.searchItem, currentPage.start, SEARCH_ITEM_PAGE_SIZE, this.plugin.settings, this.plugin.settingsManager); + // this.context.searchPage = new SearchPageInfo(searchPageResult.total, currentPage.pageNum, searchPageResult.pageSize, item.type); + // this.updatePageResult(searchPageResult); } return result; } private updatePageResult(searchPageResult: SearchPage) { - this.initItems(searchPageResult.list); + this.initItems(searchPageResult); } - public showSearchList(doubanSearchResultExtractList: DoubanSearchResultSubject[]) { - this.initItems(doubanSearchResultExtractList); + public showSearchPage(searchPage: SearchPage) { + this.initItems(searchPage); this.start(); } - private initItems(doubanSearchResultExtractList: DoubanSearchResultSubject[]) { - let doubanList: DoubanSearchResultSubject[] = doubanSearchResultExtractList; - const {searchPage} = this.context; + private initItems(searchPage: SearchPage) { + const doubanList: DoubanSearchResultSubject[] = searchPage.list; if (searchPage.hasNext) { if (this.plugin.userComponent.isLogin()) { doubanList.push(DoubanSearchResultSubjectNextPage) @@ -117,6 +118,7 @@ class DoubanFuzzySuggester extends FuzzySuggestModal doubanList.push(DoubanSearchResultSubjectNextPageNeedLogin) } } + this.initTypeSelect(doubanList, searchPage); if (searchPage.hasPrevious) { doubanList.unshift(DoubanSearchResultSubjectPreviousPage); } @@ -124,6 +126,12 @@ class DoubanFuzzySuggester extends FuzzySuggestModal } + private initTypeSelect(doubanList: DoubanSearchResultSubject[], searchPage: SearchPage) { + if (SupportType.ALL == searchPage.type) { + + } + } + public start(): void { try { this.open(); @@ -132,4 +140,29 @@ class DoubanFuzzySuggester extends FuzzySuggestModal } } + private isTypeSelect(item: DoubanSearchResultSubject) { + return item.type == "type"; + } + + private async handleTypeSelect(item: DoubanSearchResultSubject) { + const {searchPage} = this.context; + let currentPage:SearchPageInfo = searchPage; + let result:boolean = false; + switch (item.url) { + case SupportType.ALL: + currentPage = searchPage.previousPage(); + result = true; + break; + case NavigateType.next: + currentPage = searchPage.nextPage(); + result = true; + break; + case NavigateType.nextNeedLogin: + log.warn(i18nHelper.getMessage("140304")); + break; + } + if (result) { + } + return result; + } } diff --git a/src/org/wanxp/douban/data/search/DoubanSearchModal.ts b/src/org/wanxp/douban/data/search/DoubanSearchModal.ts index 6bcbc73..9795643 100644 --- a/src/org/wanxp/douban/data/search/DoubanSearchModal.ts +++ b/src/org/wanxp/douban/data/search/DoubanSearchModal.ts @@ -1,11 +1,13 @@ -import {App, Modal, TextComponent} from "obsidian"; +import {App, DropdownComponent, Modal, TextComponent} from "obsidian"; import DoubanPlugin from "../../../main"; import {i18nHelper} from "src/org/wanxp/lang/helper"; import HandleContext from "../model/HandleContext"; +import {SearchTypeRecords, SupportType} from "../../../constant/Constsant"; export class DoubanSearchModal extends Modal { searchTerm: string; + searchType: SupportType = SupportType.ALL; plugin: DoubanPlugin; context: HandleContext @@ -19,14 +21,25 @@ export class DoubanSearchModal extends Modal { let {contentEl} = this; contentEl.createEl("h3", {text: i18nHelper.getMessage('110003')}); + const content = contentEl.createDiv("content"); - const inputs = contentEl.createDiv("inputs"); + const typeSelect = content.createDiv("type-select"); + const typeSelectInput = new DropdownComponent(typeSelect) + .addOptions(SearchTypeRecords) + .setValue(SupportType.ALL) + .onChange((value:SupportType) => { + this.searchType = value; + }); + typeSelect.addClass('obsidian_douban_search_input'); + + + const inputs = content.createDiv("inputs"); const searchInput = new TextComponent(inputs).onChange((searchTerm) => { this.searchTerm = searchTerm; }); - searchInput.inputEl.addClass("obsidian_douban_search_input"); + inputs.addClass("obsidian_douban_search_input"); + searchInput.inputEl.size = 40; - searchInput.inputEl.focus(); searchInput.inputEl.addEventListener("keydown", (event) => { if (event.key === "Enter") { this.close(); @@ -34,6 +47,9 @@ export class DoubanSearchModal extends Modal { }); + + + const controls = contentEl.createDiv("controls"); const searchButton = controls.createEl("button", { text: i18nHelper.getMessage('110004'), @@ -48,6 +64,7 @@ export class DoubanSearchModal extends Modal { const cancelButton = controls.createEl("button", {text: i18nHelper.getMessage('110005')}); cancelButton.addEventListener("click", this.close.bind(this)); cancelButton.addClass("obsidian_douban_search_button"); + searchInput.inputEl.focus(); } @@ -56,7 +73,7 @@ export class DoubanSearchModal extends Modal { let {contentEl} = this; contentEl.empty(); if (this.searchTerm) { - await this.plugin.search(this.searchTerm, this.context); + await this.plugin.search(this.searchTerm, this.searchType, this.context); } } diff --git a/src/org/wanxp/douban/data/search/Search.ts b/src/org/wanxp/douban/data/search/Search.ts index 88e2f2c..5b63ab8 100644 --- a/src/org/wanxp/douban/data/search/Search.ts +++ b/src/org/wanxp/douban/data/search/Search.ts @@ -11,9 +11,10 @@ import {i18nHelper} from "../../../lang/helper"; import {load} from 'cheerio'; import {log} from 'src/org/wanxp/utils/Logutil'; import HttpUtil from "../../../utils/HttpUtil"; +import {SupportType} from "../../../constant/Constsant"; export default class Searcher { - static search(searchItem: string, doubanSettings: DoubanPluginSetting, settingsManager:SettingsManager): Promise { + static search(searchItem: string, type:SupportType, doubanSettings: DoubanPluginSetting, settingsManager:SettingsManager): Promise { return HttpUtil.httpRequestGet(DEFAULT_SETTINGS.searchUrl + searchItem, settingsManager.getHeaders(), settingsManager) .then(load) .then(SearchParserHandler.parseSearch) @@ -23,11 +24,11 @@ export default class Searcher { }; - static loadSearchItem(searchItem: string, start:number, doubanSettings: DoubanPluginSetting, settingsManager:SettingsManager): Promise { + static loadSearchItem(searchItem: string, type:SupportType, start:number, doubanSettings: DoubanPluginSetting, settingsManager:SettingsManager): Promise { const url:string = `https://www.douban.com/j/search?q=${searchItem}&start=${start}&subtype=item`; log.debug(`请求更多页面:${url}`); return HttpUtil.httpRequestGet(url, settingsManager.getHeaders(), settingsManager) - .then(e=>SearchParserHandler.parseSearchJson(e, start)) + .then(e=>SearchParserHandler.parseSearchJson(e, type, start)) .catch(e => { throw log.error(i18nHelper.getMessage('130101').replace('{0}', e.toString()), e); }); diff --git a/src/org/wanxp/douban/data/search/SearchParser.ts b/src/org/wanxp/douban/data/search/SearchParser.ts index 60acbca..73cfb97 100644 --- a/src/org/wanxp/douban/data/search/SearchParser.ts +++ b/src/org/wanxp/douban/data/search/SearchParser.ts @@ -1,7 +1,7 @@ import {CheerioAPI, load} from "cheerio"; import DoubanSearchResultSubject from "../model/DoubanSearchResultSubject"; import {SearchPage} from "../model/SearchPage"; -import {SEARCH_ITEM_PAGE_SIZE} from "../../../constant/Constsant"; +import {SEARCH_ITEM_PAGE_SIZE, SupportType} from "../../../constant/Constsant"; import {log} from "../../../utils/Logutil"; export default class SearchParserHandler { @@ -38,7 +38,7 @@ export default class SearchParserHandler { }) }; - static parseSearchJson(result: string, start:number): SearchPage { + static parseSearchJson(result: string, type:SupportType, start:number): SearchPage { log.debug("解析给多页面结果"); const data:{total:number, limit:number, more:boolean, items:string[]} = JSON.parse(result); const list:string[] = data.items; @@ -46,7 +46,7 @@ export default class SearchParserHandler { .map(e => load(e)) .map(e=>this.parseSearch(e)) .map(e => e? e[0]:null); - return new SearchPage(data.total, start / data.limit, data.limit, resultList); + return new SearchPage(data.total, start / data.limit, data.limit, type, resultList); }; } diff --git a/src/org/wanxp/douban/data/search/SearchParserV2.ts b/src/org/wanxp/douban/data/search/SearchParserV2.ts new file mode 100644 index 0000000..88ca62d --- /dev/null +++ b/src/org/wanxp/douban/data/search/SearchParserV2.ts @@ -0,0 +1,29 @@ +import DoubanSearchResultSubject from "../model/DoubanSearchResultSubject"; + +export default class SearchParserHandlerV2 { + + static itemMapToSearchResult(items:any):DoubanSearchResultSubject[] { + if (!items) { + return []; + } + return items.map((i: any) => { + const target:any = i.target; + const result: DoubanSearchResultSubject = { + id: target.id ??'', + title: target.title ?? '-', + score: target.rating && target.rating.value ? Number(target.rating.value) : null, + cast: target.card_subtitle?? '', + type: i.type_name ?? '-', + desc: '-', + url: target.uri? (target.uri.replaceAll('douban://', 'https://')) : 'https://www.douban.com', + image: "", + imageUrl: "", + publisher: "", + datePublished: undefined, + genre: [] + }; + return result; + }) + } + +} diff --git a/src/org/wanxp/douban/data/search/SearchV2.ts b/src/org/wanxp/douban/data/search/SearchV2.ts new file mode 100644 index 0000000..ed76dea --- /dev/null +++ b/src/org/wanxp/douban/data/search/SearchV2.ts @@ -0,0 +1,17 @@ + +import {DoubanPluginSetting} from "../../setting/model/DoubanPluginSetting"; +import {SearchPage} from "../model/SearchPage"; +import SettingsManager from "../../setting/SettingsManager"; +import {SupportType} from "../../../constant/Constsant"; +import {SearchPageFetcher} from "./searcher/SearchPageFetcher"; +import {SearchResultPageParser} from "./parser/SearchResultPageParser"; + +export default class SearcherV2 { + static search(searchItem: string, searchType: SupportType, pageNum:number, pageSize:number, doubanSettings: DoubanPluginSetting, settingsManager:SettingsManager): Promise { + return new SearchPageFetcher(settingsManager) + .fetch(searchItem, searchType, pageNum, pageSize) + .then(e => new SearchResultPageParser() + .parse(e, searchType, pageNum, pageSize)); + } + +} diff --git a/src/org/wanxp/douban/data/search/parser/FistAllPageSearchResultPageParser.ts b/src/org/wanxp/douban/data/search/parser/FistAllPageSearchResultPageParser.ts new file mode 100644 index 0000000..0d2a85b --- /dev/null +++ b/src/org/wanxp/douban/data/search/parser/FistAllPageSearchResultPageParser.ts @@ -0,0 +1,24 @@ +import {SupportType} from "../../../../constant/Constsant"; +import {SearchResultPageParserInterface} from "./SearchResultPageParserInterface"; +import {SearchPage} from "../../model/SearchPage"; +import SearchParserHandlerV2 from "../SearchParserV2"; + +export class FistAllPageSearchResultPageParser implements SearchResultPageParserInterface { + support(type:SupportType, pageNum:number):boolean { + return pageNum == 1 && type == SupportType.ALL; + } + parse(source:string, type:SupportType, pageNum:number, pageSize:number):SearchPage { + const {subjects} = JSON.parse(source); + if (!subjects) { + return SearchPage.empty(type); + } + const {items} = subjects; + if (!items ||items.length == 0) { + return SearchPage.empty(type); + } + const doubanSearchResultSubjects = SearchParserHandlerV2.itemMapToSearchResult(items); + return new SearchPage(items.length, pageNum, pageSize, type, doubanSearchResultSubjects); + } + + +} diff --git a/src/org/wanxp/douban/data/search/parser/OtherAllPageSearchResultPageParser.ts b/src/org/wanxp/douban/data/search/parser/OtherAllPageSearchResultPageParser.ts new file mode 100644 index 0000000..a40a883 --- /dev/null +++ b/src/org/wanxp/douban/data/search/parser/OtherAllPageSearchResultPageParser.ts @@ -0,0 +1,22 @@ +import {SupportType} from "../../../../constant/Constsant"; +import {SearchResultPageParserInterface} from "./SearchResultPageParserInterface"; +import {log} from "../../../../utils/Logutil"; +import {SearchPage} from "../../model/SearchPage"; +import SearchParserHandlerV2 from "../SearchParserV2"; + +export class OtherAllPageSearchResultPageParser implements SearchResultPageParserInterface { + support(type:SupportType, pageNum:number):boolean { + return pageNum > 1 && type == SupportType.ALL; + } + parse(source:string, type:SupportType, pageNum:number, pageSize:number):SearchPage { + log.debug("解析给多页面结果"); + const {contents} = JSON.parse(source); + if (!contents) { + return new SearchPage(0, 0, 0, type, []); + } + const data:{total:number, start:number, count:number, items:any[]} = contents; + const doubanSearchResultSubjects = SearchParserHandlerV2.itemMapToSearchResult(data.items); + return new SearchPage(data.total, pageNum, pageSize, type, doubanSearchResultSubjects); + } + +} diff --git a/src/org/wanxp/douban/data/search/parser/SearchResultPageParser.ts b/src/org/wanxp/douban/data/search/parser/SearchResultPageParser.ts new file mode 100644 index 0000000..3168776 --- /dev/null +++ b/src/org/wanxp/douban/data/search/parser/SearchResultPageParser.ts @@ -0,0 +1,25 @@ +import {SearchResultPageParserInterface} from "./SearchResultPageParserInterface"; +import {FistAllPageSearchResultPageParser} from "./FistAllPageSearchResultPageParser"; +import {OtherAllPageSearchResultPageParser} from "./OtherAllPageSearchResultPageParser"; +import {SearchPage} from "../../model/SearchPage"; +import {SupportType} from "../../../../constant/Constsant"; + +export class SearchResultPageParser { + + private parsers:SearchResultPageParserInterface[] = []; + + constructor() { + this.parsers.push(new FistAllPageSearchResultPageParser()); + this.parsers.push(new OtherAllPageSearchResultPageParser()); + } + + public parse(source:string, type:SupportType, pageNum:number, pageSize:number):SearchPage { + for (const parser of this.parsers) { + if (parser.support(type, pageNum)) { + return parser.parse(source, type, pageNum, pageSize); + } + } + throw new Error(`not support type:${type} pageNum:${pageNum}`); + } + +} diff --git a/src/org/wanxp/douban/data/search/parser/SearchResultPageParserInterface.ts b/src/org/wanxp/douban/data/search/parser/SearchResultPageParserInterface.ts new file mode 100644 index 0000000..714336b --- /dev/null +++ b/src/org/wanxp/douban/data/search/parser/SearchResultPageParserInterface.ts @@ -0,0 +1,9 @@ +import {SearchPage} from "../../model/SearchPage"; +import {SupportType} from "../../../../constant/Constsant"; +import DoubanSearchResultSubject from "../../model/DoubanSearchResultSubject"; + +export interface SearchResultPageParserInterface { + support(type:SupportType, pageNum:number):boolean; + + parse(source:string, type:SupportType, pageNum:number, pageSize:number):SearchPage; +} diff --git a/src/org/wanxp/douban/data/search/searcher/AbstractSearchPageFetcher.ts b/src/org/wanxp/douban/data/search/searcher/AbstractSearchPageFetcher.ts new file mode 100644 index 0000000..6436e1a --- /dev/null +++ b/src/org/wanxp/douban/data/search/searcher/AbstractSearchPageFetcher.ts @@ -0,0 +1,32 @@ +import { SupportType } from "src/org/wanxp/constant/Constsant"; +import SettingsManager from "../../../setting/SettingsManager"; +import {SearchPageFetcherInterface} from "./SearchPageFetcherInterface"; +import HttpUtil from "../../../../utils/HttpUtil"; +import {log} from "../../../../utils/Logutil"; +import {i18nHelper} from "../../../../lang/helper"; + +export abstract class AbstractSearchPageFetcher implements SearchPageFetcherInterface { + + protected settingsManager: SettingsManager; + + constructor(settingsManager: SettingsManager) { + this.settingsManager = settingsManager; + } + + support(type: SupportType): boolean { + throw new Error("Method not implemented."); + } + fetch(keyword: string, pageNum: number, pageSize: number): Promise { + const url:string = this.getUrl(keyword, pageNum, pageSize); + if (!url) { + return Promise.resolve(""); + } + return HttpUtil.httpRequestGet(url, this.settingsManager.getHeaders(), this.settingsManager) + .catch(e => { + throw log.error(i18nHelper.getMessage('130101').replace('{0}', e.toString()), e); + }); } + + abstract getUrl(keyword: string, pageNum: number, pageSize: number):string; + + +} diff --git a/src/org/wanxp/douban/data/search/searcher/BookPageSearchPageFetcher.ts b/src/org/wanxp/douban/data/search/searcher/BookPageSearchPageFetcher.ts new file mode 100644 index 0000000..36560e5 --- /dev/null +++ b/src/org/wanxp/douban/data/search/searcher/BookPageSearchPageFetcher.ts @@ -0,0 +1,13 @@ +import {AbstractSearchPageFetcher} from "./AbstractSearchPageFetcher"; +import { SupportType } from "src/org/wanxp/constant/Constsant"; + +export class BookPageSearchPageFetcher extends AbstractSearchPageFetcher { + getUrl(keyword: string, pageNum: number, pageSize: number): string { + return `https://www.douban.com/j/search?q=${keyword}&start=${pageNum * pageSize}&cat=1001`; + } + support(type: SupportType): boolean { + return type == SupportType.MOVIE; + } + + +} diff --git a/src/org/wanxp/douban/data/search/searcher/FistAllPageSearchPageFetcher.ts b/src/org/wanxp/douban/data/search/searcher/FistAllPageSearchPageFetcher.ts new file mode 100644 index 0000000..65b3578 --- /dev/null +++ b/src/org/wanxp/douban/data/search/searcher/FistAllPageSearchPageFetcher.ts @@ -0,0 +1,13 @@ +import {AbstractSearchPageFetcher} from "./AbstractSearchPageFetcher"; +import { SupportType } from "src/org/wanxp/constant/Constsant"; + +export class FistAllPageSearchPageFetcher extends AbstractSearchPageFetcher { + getUrl(keyword: string, pageNum: number, pageSize: number): string { + return `https://m.douban.com/rexxar/api/v2/search?q=${keyword}&start=${pageNum}&count=${pageSize}`; + } + support(type: SupportType): boolean { + return type == SupportType.ALL; + } + + +} diff --git a/src/org/wanxp/douban/data/search/searcher/MoviePageSearchPageFetcher.ts b/src/org/wanxp/douban/data/search/searcher/MoviePageSearchPageFetcher.ts new file mode 100644 index 0000000..8dd476b --- /dev/null +++ b/src/org/wanxp/douban/data/search/searcher/MoviePageSearchPageFetcher.ts @@ -0,0 +1,13 @@ +import {AbstractSearchPageFetcher} from "./AbstractSearchPageFetcher"; +import { SupportType } from "src/org/wanxp/constant/Constsant"; + +export class MoviePageSearchPageFetcher extends AbstractSearchPageFetcher { + getUrl(keyword: string, pageNum: number, pageSize: number): string { + return `https://www.douban.com/j/search?q=${keyword}&start=${pageNum * pageSize}&cat=1002`; + } + support(type: SupportType): boolean { + return type == SupportType.MOVIE; + } + + +} diff --git a/src/org/wanxp/douban/data/search/searcher/SearchPageFetcher.ts b/src/org/wanxp/douban/data/search/searcher/SearchPageFetcher.ts new file mode 100644 index 0000000..35f684a --- /dev/null +++ b/src/org/wanxp/douban/data/search/searcher/SearchPageFetcher.ts @@ -0,0 +1,28 @@ +import {SearchPageFetcherInterface} from "./SearchPageFetcherInterface"; +import {FistAllPageSearchPageFetcher} from "./FistAllPageSearchPageFetcher"; +import SettingsManager from "../../../setting/SettingsManager"; +import {SupportType} from "../../../../constant/Constsant"; +import {MoviePageSearchPageFetcher} from "./MoviePageSearchPageFetcher"; +import {BookPageSearchPageFetcher} from "./BookPageSearchPageFetcher"; + +export class SearchPageFetcher { + + private fetchers:SearchPageFetcherInterface[] = []; + + constructor(settingsManager:SettingsManager) { + this.fetchers.push(new FistAllPageSearchPageFetcher(settingsManager)); + this.fetchers.push(new MoviePageSearchPageFetcher(settingsManager)); + this.fetchers.push(new BookPageSearchPageFetcher(settingsManager)) + } + + fetch(keyword:string, type:SupportType, pageNum:number, pageSize:number):Promise { + for (const fetcher of this.fetchers) { + if (fetcher.support(type)) { + return fetcher.fetch(keyword, pageNum, pageSize); + } + } + throw new Error(`not support type:${type} pageNum:${pageNum}`); + } + + +} diff --git a/src/org/wanxp/douban/data/search/searcher/SearchPageFetcherInterface.ts b/src/org/wanxp/douban/data/search/searcher/SearchPageFetcherInterface.ts new file mode 100644 index 0000000..0d5dfdb --- /dev/null +++ b/src/org/wanxp/douban/data/search/searcher/SearchPageFetcherInterface.ts @@ -0,0 +1,9 @@ +import {SupportType} from "../../../../constant/Constsant"; + +export interface SearchPageFetcherInterface { + + support(type:SupportType):boolean; + + fetch(keyword:string, pageNum:number, pageSize:number):Promise; + +} diff --git a/src/org/wanxp/lang/locale/en.ts b/src/org/wanxp/lang/locale/en.ts index 43926e6..0b0619e 100644 --- a/src/org/wanxp/lang/locale/en.ts +++ b/src/org/wanxp/lang/locale/en.ts @@ -1,13 +1,13 @@ //简体中文 export default { //main.ts - '110001': 'search douban by current file name', - '110002': 'search douban and import to current file', + '110001': 'searcher douban by current file name', + '110002': 'searcher douban and import to current file', '110003': `Enter Search Term:`, '110004': `Search`, '110005': `Cancel`, '110006': `sync douban personal book-movie-music to Obsidian`, - '110101': 'search douban and create file', + '110101': 'searcher douban and create file', '110201': `{0} already exists`, '110202': `{0} template can not read`, '110103': 'sync personal data from douban', @@ -557,6 +557,10 @@ PS: This file could be delete if you want to. 'NOTE': `note`, 'GAME': `game`, 'TELEPLAY': `teleplay`, + 'THEATER': `theater`, + + 'MOVIE_AND_TELEPLAY': `movie&teleplay`, + 'DAY': `D`, 'HOUR': `H`, diff --git a/src/org/wanxp/lang/locale/zh-cn.ts b/src/org/wanxp/lang/locale/zh-cn.ts index 62cc705..4a35a49 100644 --- a/src/org/wanxp/lang/locale/zh-cn.ts +++ b/src/org/wanxp/lang/locale/zh-cn.ts @@ -562,6 +562,9 @@ export default { 'NOTE': `笔记`, 'GAME': `游戏`, 'TELEPLAY': `电视剧`, + 'THEATER': `戏剧`, + 'MOVIE_AND_TELEPLAY': `影视剧`, + 'DAY': `天`, 'HOUR': `时`, diff --git a/src/org/wanxp/main.ts b/src/org/wanxp/main.ts index 3531c73..59592a1 100644 --- a/src/org/wanxp/main.ts +++ b/src/org/wanxp/main.ts @@ -1,4 +1,12 @@ -import {Action, BasicConst, SearchHandleMode, SubjectHandledStatus, SyncTypeRecords} from "./constant/Constsant"; +import { + Action, + BasicConst, + SEARCH_ITEM_PAGE_SIZE, + SearchHandleMode, + SubjectHandledStatus, + SupportType, + SyncTypeRecords +} from "./constant/Constsant"; import {Editor, Notice, Plugin} from "obsidian"; import {DEFAULT_SETTINGS} from "./constant/DefaultSettings"; @@ -6,7 +14,6 @@ import {DoubanFuzzySuggester} from "./douban/data/search/DoubanSearchFuzzySugges import {DoubanPluginSetting} from "./douban/setting/model/DoubanPluginSetting"; import {DoubanSearchChooseItemHandler} from "./douban/data/handler/DoubanSearchChooseItemHandler"; import {DoubanSearchModal} from "./douban/data/search/DoubanSearchModal"; -import DoubanSearchResultSubject from "./douban/data/model/DoubanSearchResultSubject"; import {DoubanSettingTab} from "./douban/setting/DoubanSettingTab"; import DoubanSubject from "./douban/data/model/DoubanSubject"; import {DoubanSyncModal} from "./douban/component/DoubanSyncModal"; @@ -16,8 +23,6 @@ import GlobalStatusHolder from "./douban/model/GlobalStatusHolder"; import HandleContext from "./douban/data/model/HandleContext"; import HandleResult from "./douban/data/model/HandleResult"; import NetFileHandler from "./net/NetFileHandler"; -import {SearchPageInfo} from "./douban/data/model/SearchPageInfo"; -import Searcher from "./douban/data/search/Search"; import SettingsManager from "./douban/setting/SettingsManager"; import {SyncConfig} from "./douban/sync/model/SyncConfig"; import SyncHandler from "./douban/sync/handler/SyncHandler"; @@ -26,6 +31,8 @@ import {i18nHelper} from './lang/helper'; import {log} from "src/org/wanxp/utils/Logutil"; import GithubUtil from "./utils/GithubUtil"; import {DoubanPluginOnlineData} from "./douban/setting/model/DoubanPluginOnlineData"; +import SearcherV2 from "./douban/data/search/SearchV2"; +import {SearchPage} from "./douban/data/model/SearchPage"; export default class DoubanPlugin extends Plugin { public settings: DoubanPluginSetting; @@ -119,13 +126,13 @@ export default class DoubanPlugin extends Plugin { } } - async search(searchTerm: string, context: HandleContext) { + async search(searchTerm: string, searchType: SupportType, context: HandleContext) { try { this.showStatus(i18nHelper.getMessage('140201', searchTerm)); - const resultList:DoubanSearchResultSubject[] = await Searcher.search(searchTerm, this.settings, context.plugin.settingsManager); - this.showStatus(i18nHelper.getMessage('140202', resultList.length.toString())); - context.searchPage = new SearchPageInfo(21,-1,20); - new DoubanFuzzySuggester(this, context, searchTerm).showSearchList(resultList); + const result:SearchPage = await SearcherV2.search(searchTerm, searchType, 1, SEARCH_ITEM_PAGE_SIZE, this.settings, context.plugin.settingsManager); + this.showStatus(i18nHelper.getMessage('140202', result.list.toString())); + context.searchPage = result; + new DoubanFuzzySuggester(this, context, searchTerm).showSearchPage(result); } catch (e) { log.error(i18nHelper.getMessage('140206').replace('{0}', e.message), e); } finally { @@ -138,7 +145,7 @@ export default class DoubanPlugin extends Plugin { if (activeFile) { const searchTerm = activeFile.basename; if (searchTerm) { - await this.search(searchTerm, context); + await this.search(searchTerm, SupportType.ALL, context); } } } @@ -162,7 +169,7 @@ export default class DoubanPlugin extends Plugin { } this.addCommand({ - id: "search-douban-import-and-create-file", + id: "searcher-douban-import-and-create-file", name: i18nHelper.getMessage("110101"), callback: () => this.getDoubanTextForCreateNewNote({plugin: this, @@ -175,7 +182,7 @@ export default class DoubanPlugin extends Plugin { }); this.addCommand({ - id: "search-douban-and-input-current-file", + id: "searcher-douban-and-input-current-file", name: i18nHelper.getMessage("110002"), editorCallback: (editor: Editor) => this.getDoubanTextForSearchTerm({plugin: this, @@ -188,7 +195,7 @@ export default class DoubanPlugin extends Plugin { }); this.addCommand({ - id: "search-douban-by-current-file-name", + id: "searcher-douban-by-current-file-name", name: i18nHelper.getMessage("110001"), editorCallback: (editor: Editor) => this.getDoubanTextForActiveFile({plugin: this, diff --git a/src/org/wanxp/utils/HttpUtil.ts b/src/org/wanxp/utils/HttpUtil.ts index 0a9726f..11855b8 100644 --- a/src/org/wanxp/utils/HttpUtil.ts +++ b/src/org/wanxp/utils/HttpUtil.ts @@ -19,6 +19,7 @@ export default class HttpUtil { */ // Cookie: 'll="108296"; bid=xHRJLeWBrjQ; _pk_id.100001.8cb4=f8f83e81ec224a1a.1691572669.; __utmv=30149280.13103; __yadk_uid=ce95W7OsgT0iKFceWgbMSUdw1oOqxNTk; __gads=ID=62585f60f3f637d0-2234f63fc6e200a5:T=1691572672:RT=1691572672:S=ALNI_MaIqTxSWHsfpnX9nAmMHcPQEsaezg; __gpi=UID=00000c29a9f98e5b:T=1691572672:RT=1691572672:S=ALNI_MbLAq8XNoKrRPKNqGCMdgXSPZvidw; ap_v=0,6.0; __utma=30149280.135860784.1691572641.1691572641.1694509646.2; __utmc=30149280; __utmz=30149280.1694509646.2.2.utmcsr=baidu|utmccn=(organic)|utmcmd=organic; _pk_ref.100001.8cb4=%5B%22%22%2C%22%22%2C1694509648%2C%22https%3A%2F%2Fmovie.douban.com%2Ftv%2F%22%5D; _pk_ses.100001.8cb4=1; __utmt=1; dbcl2="131038721:LUssju34QFw"; ck=dCQj; push_noty_num=0; push_doumail_num=0; __utmb=30149280.3.10.1694509646' public static httpRequestGet(url: string, headers: any, settingsManager?: SettingsManager): Promise { + settingsManager.debug(`请求地址:${url}`); const {['Accept-Encoding']: acceptEncoding, ...headersInner} = headers; let options = { headers: headersInner @@ -48,6 +49,43 @@ export default class HttpUtil { }) } + /** + * get请求 + * @param url 请求地址 + * @param headers 请求参数 + * @param settingsManager 设置管理器 + */ + // Cookie: 'll="108296"; bid=xHRJLeWBrjQ; _pk_id.100001.8cb4=f8f83e81ec224a1a.1691572669.; __utmv=30149280.13103; __yadk_uid=ce95W7OsgT0iKFceWgbMSUdw1oOqxNTk; __gads=ID=62585f60f3f637d0-2234f63fc6e200a5:T=1691572672:RT=1691572672:S=ALNI_MaIqTxSWHsfpnX9nAmMHcPQEsaezg; __gpi=UID=00000c29a9f98e5b:T=1691572672:RT=1691572672:S=ALNI_MbLAq8XNoKrRPKNqGCMdgXSPZvidw; ap_v=0,6.0; __utma=30149280.135860784.1691572641.1691572641.1694509646.2; __utmc=30149280; __utmz=30149280.1694509646.2.2.utmcsr=baidu|utmccn=(organic)|utmcmd=organic; _pk_ref.100001.8cb4=%5B%22%22%2C%22%22%2C1694509648%2C%22https%3A%2F%2Fmovie.douban.com%2Ftv%2F%22%5D; _pk_ses.100001.8cb4=1; __utmt=1; dbcl2="131038721:LUssju34QFw"; ck=dCQj; push_noty_num=0; push_doumail_num=0; __utmb=30149280.3.10.1694509646' + public static httpRequestGetJson(url: string, headers: any, settingsManager?: SettingsManager): Promise { + const {['Accept-Encoding']: acceptEncoding, ...headersInner} = headers; + let options = { + headers: headersInner + } + settingsManager.debug(`Obsidian-Douban:从网络获取json开始:\nurl:${url}\nheaders:${JSON.stringify(headers)}`); + return new Promise((resolve, rejects) => { + https.get(url, { ...options }, function (response: any) { + let chunks: any = [], + size = 0; + if (response.status == 403) { + rejects(new Error(i18nHelper.getMessage('130106'))); + } + response.on("data", function (chunk: any) { + chunks.push(chunk) + size += chunk.length + }) + + response.on("end", function () { + let data = Buffer.concat(chunks, size) + let html = data.toString() + if (settingsManager) { + settingsManager.debug(`Obsidian-Douban:从网络获取网页完成:\nhtml:\n${html}`); + } + resolve(html) + }) + }) + }) + } + /** * get请求 * @param url 请求地址 diff --git a/styles.css b/styles.css index 9097e6b..eac4c72 100644 --- a/styles.css +++ b/styles.css @@ -34,6 +34,11 @@ } .obsidian_douban_search_input { + margin-left: 5px; + float: left; +} + +.obsidian_douban_search_input_content { margin-left: 5px; margin-right: 5px; width: 90%;