From ee2dead3937a029eb619f33a46b7e592f85768e8 Mon Sep 17 00:00:00 2001 From: wanxp <977741432@qq.com> Date: Thu, 16 Jun 2022 20:51:36 +0800 Subject: [PATCH] add book search --- douban/handler/DoubanAbstractLoadHandler.ts | 3 +- douban/handler/DoubanBookLoadHandler.ts | 68 +++++++++++++++++++ ...er.ts => DoubanSearchChooseItemHandler.ts} | 7 +- douban/model/DoubanBookSubject.ts | 10 +++ .../search/DoubanSearchFuzzySuggestModal.ts | 1 + douban/search/Search.ts | 2 +- main.ts | 16 +++-- utils/logutil.ts | 10 ++- 8 files changed, 101 insertions(+), 16 deletions(-) create mode 100644 douban/handler/DoubanBookLoadHandler.ts rename douban/handler/{DoubanExtractHandler.ts => DoubanSearchChooseItemHandler.ts} (90%) create mode 100644 douban/model/DoubanBookSubject.ts diff --git a/douban/handler/DoubanAbstractLoadHandler.ts b/douban/handler/DoubanAbstractLoadHandler.ts index b142e2d..b4d4db8 100644 --- a/douban/handler/DoubanAbstractLoadHandler.ts +++ b/douban/handler/DoubanAbstractLoadHandler.ts @@ -24,9 +24,10 @@ export default abstract class DoubanAbstractLoadHandler abstract support(extract: DoubanSubject): boolean; handle(url:string, editor:Editor):void { - Promise.resolve().then(() => get(url + "/", {headers: JSON.parse(this.doubanPlugin.settings.searchHeaders)})) + Promise.resolve().then(() => get(log.traceN("GET URL", url + "/"), log.traceN("GET HEAD", {headers: JSON.parse(this.doubanPlugin.settings.searchHeaders)}))) .then(readStream) .then(cheerio.load) + .then(log.trace) .then(this.parseSubjectFromHtml) .then(content => this.toEditor(editor, content)) // .then(content => content ? editor.replaceSelection(content) : content) diff --git a/douban/handler/DoubanBookLoadHandler.ts b/douban/handler/DoubanBookLoadHandler.ts new file mode 100644 index 0000000..f30beea --- /dev/null +++ b/douban/handler/DoubanBookLoadHandler.ts @@ -0,0 +1,68 @@ +import { Editor, moment, renderResults } from "obsidian"; +import cheerio, { CheerioAPI } from 'cheerio'; +import { get, readStream } from "tiny-network"; + +import DoubanAbstractLoadHandler from "./DoubanAbstractLoadHandler"; +import DoubanBookSubject from "douban/model/DoubanBookSubject"; +import DoubanPlugin from "main"; +import { DoubanPluginSettings } from "douban/Douban"; +import DoubanSubject from "douban/model/DoubanSubject"; +import SchemaOrg from "utils/SchemaOrg"; +import { log } from "utils/Logutil"; + +export default class DoubanBookLoadHandler extends DoubanAbstractLoadHandler { + + parseText(extract: DoubanBookSubject, settings:DoubanPluginSettings): string { + return settings.movieTemplate ? settings.movieTemplate.replaceAll("{{id}}", extract.id) + .replaceAll("{{type}}", extract.type ? extract.type : "") + .replaceAll("{{title}}", extract.title ? extract.title : "") + .replaceAll("{{desc}}", extract.desc ? extract.desc : "") + .replaceAll("{{image}}", extract.image ? extract.image : "") + // .replaceAll("{{director}}", extract.director ? extract.director.map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, settings)).filter(c => c).join(settings.arraySpilt) : "") + // .replaceAll("{{actor}}", extract.actor ? extract.actor.map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, settings)).filter(c => c).join(settings.arraySpilt) : "") + .replaceAll("{{author}}", extract.author ? extract.author.map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, settings)).filter(c => c).join(settings.arraySpilt) : "") + .replaceAll("{{datePublished}}", extract.datePublished ? moment(extract.datePublished).format(settings.dateFormat) : "") + .replaceAll("{{url}}", extract.url ? extract.url : "") + .replaceAll("{{score}}", extract.aggregateRating && extract.aggregateRating.ratingValue ? extract.aggregateRating.ratingValue + "" : "") + : undefined; } + support(extract: DoubanSubject): boolean { + return extract && extract.type && (extract.type.contains("书籍") || extract.type.contains("Book") || extract.type.contains("book")); + } + + + + + + constructor(doubanPlugin:DoubanPlugin) { + super(doubanPlugin); + } + + parseSubjectFromHtml(data: CheerioAPI): DoubanBookSubject { + return data('script') + .get() + .filter(scd => "application/ld+json" == data(scd).attr("type")) + .map(i => { + var item = data(i).text(); + item = super.html_decode(item); + var obj = JSON.parse(item.replace(/[\r\n\s+]/g, '')); + var idPattern = /(\d){5,10}/g; + var id = idPattern.exec(obj.url); + const result:DoubanBookSubject = { + id: id?id[0]:'', + type: 'Book', + title: obj.name, + desc: obj.description, + url: "https://book.douban.com" + obj.url, + author: obj.author, + aggregateRating: obj.aggregateRating, + datePublished: obj.datePublished ? new Date(obj.datePublished) : undefined, + image:obj.image + } + return result; + })[0]; +} + + +} + + diff --git a/douban/handler/DoubanExtractHandler.ts b/douban/handler/DoubanSearchChooseItemHandler.ts similarity index 90% rename from douban/handler/DoubanExtractHandler.ts rename to douban/handler/DoubanSearchChooseItemHandler.ts index 73fff2a..112dfb9 100644 --- a/douban/handler/DoubanExtractHandler.ts +++ b/douban/handler/DoubanSearchChooseItemHandler.ts @@ -7,7 +7,7 @@ import { DoubanPluginSettings } from "douban/Douban"; import DoubanSubject from "../model/DoubanSubject"; import DoubanSubjectLoadHandler from "./DoubanSubjectLoadHandler"; -export class DoubanEtractHandler { +export class DoubanSearchChooseItemHandler { private _app:App; private _doubanPlugin:DoubanPlugin; @@ -32,10 +32,7 @@ export class DoubanEtractHandler { var doubanSubjectHandlers:DoubanSubjectLoadHandler[] = this._doubanSubjectHandlers .filter(h => h.support(searchExtract)); if(doubanSubjectHandlers && doubanSubjectHandlers.length > 0) { - var result = doubanSubjectHandlers.map(h => h.handle(searchExtract.url, editor)) - if(result && result.length > 0) { - return result[0]; - } + doubanSubjectHandlers[0].handle(searchExtract.url, editor); }else { this._doubanSubjectHandlerDefault.handle(searchExtract.url, editor); } diff --git a/douban/model/DoubanBookSubject.ts b/douban/model/DoubanBookSubject.ts new file mode 100644 index 0000000..4d2afd5 --- /dev/null +++ b/douban/model/DoubanBookSubject.ts @@ -0,0 +1,10 @@ +import {AggregateRating, Person, WithContext} from 'schema-dts'; + +import DoubanSubject from "./DoubanSubject"; + +export default class DoubanMovieSubject extends DoubanSubject { + author:Person[]; + aggregateRating:AggregateRating; + datePublished:Date; + image:string +} diff --git a/douban/search/DoubanSearchFuzzySuggestModal.ts b/douban/search/DoubanSearchFuzzySuggestModal.ts index a86c71c..e00cc4c 100644 --- a/douban/search/DoubanSearchFuzzySuggestModal.ts +++ b/douban/search/DoubanSearchFuzzySuggestModal.ts @@ -33,6 +33,7 @@ class DoubanFuzzySuggester extends FuzzySuggestModal } onChooseItem(item: DoubanSearchResultSubject, evt: MouseEvent | KeyboardEvent): void { + log.trace(`you chosen : ${JSON.stringify(item)}`) this.plugin.doubanEtractHandler.handle(item, this.editor); } diff --git a/douban/search/Search.ts b/douban/search/Search.ts index d6e70fb..027cbc9 100644 --- a/douban/search/Search.ts +++ b/douban/search/Search.ts @@ -14,7 +14,7 @@ export default class Searcher { // return Promise.resolve(); return Promise .resolve() - .then(() => get(doubanSettings.searchUrl + searchItem, JSON.parse(doubanSettings.searchHeaders))) + .then(() => get(log.traceN("GET", doubanSettings.searchUrl + searchItem), JSON.parse(doubanSettings.searchHeaders))) .then(ensureStatusCode(200)) .then(readStream) .then(cheerio.load) diff --git a/main.ts b/main.ts index b9eeb8c..4c90aa9 100644 --- a/main.ts +++ b/main.ts @@ -1,9 +1,9 @@ import { DEFAULT_SETTINGS, DoubanPluginSettings } from "./douban/Douban"; import { Editor, Plugin } from "obsidian"; -import { DoubanEtractHandler } from "douban/handler/DoubanExtractHandler"; import { DoubanFuzzySuggester } from "douban/search/DoubanSearchFuzzySuggestModal"; import DoubanMovieSubject from "douban/model/DoubanMovieSubject"; +import { DoubanSearchChooseItemHandler } from "douban/handler/DoubanSearchChooseItemHandler"; import { DoubanSearchModal } from "douban/search/DoubanSearchModal"; import { DoubanSettingTab } from "douban/DoubanSettingTab"; import DoubanSubject from "douban/model/DoubanSubject"; @@ -13,12 +13,14 @@ import { log } from "utils/Logutil"; export default class DoubanPlugin extends Plugin { public settings: DoubanPluginSettings; - public doubanEtractHandler: DoubanEtractHandler; + public doubanEtractHandler: DoubanSearchChooseItemHandler; async putToEditor(editor:Editor, extract:DoubanSubject) { if(!editor || !extract) { + log.trace(`chosen item can not load data`); return; } + log.trace(`you choose item load data success: ${JSON.stringify(extract)}`); var content:string = this.doubanEtractHandler.parseText(extract, this.settings) if(content) { editor.replaceSelection(content); @@ -33,7 +35,7 @@ export default class DoubanPlugin extends Plugin { new DoubanFuzzySuggester(this, editor).showSearchList(resultList); } - async getDoubanMovieTextForActiveFile(editor: Editor) { + async getDoubanTextForActiveFile(editor: Editor) { const activeFile = await this.app.workspace.getActiveFile(); if (activeFile) { const searchTerm = activeFile.basename; @@ -43,7 +45,7 @@ export default class DoubanPlugin extends Plugin { } } - async geDoubanMovieTextForSearchTerm(editor: Editor) { + async geDoubanTextForSearchTerm(editor: Editor) { new DoubanSearchModal(this.app, this, editor).open(); } @@ -54,7 +56,7 @@ export default class DoubanPlugin extends Plugin { id: "search-douban-by-current-file-name", name: i18nHelper.getMessage("search douban by current file name"), editorCallback: (editor: Editor) => - this.getDoubanMovieTextForActiveFile(editor), + this.getDoubanTextForActiveFile(editor), }); @@ -62,7 +64,7 @@ export default class DoubanPlugin extends Plugin { id: "search-douban-and-input-current-file", name: i18nHelper.getMessage("search douban and import to current file"), editorCallback: (editor: Editor) => - this.geDoubanMovieTextForSearchTerm(editor), + this.geDoubanTextForSearchTerm(editor), }); this.addSettingTab(new DoubanSettingTab(this.app, this)); @@ -70,7 +72,7 @@ export default class DoubanPlugin extends Plugin { async loadSettings() { this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); - this.doubanEtractHandler = new DoubanEtractHandler(this.app, this); + this.doubanEtractHandler = new DoubanSearchChooseItemHandler(this.app, this); } async saveSettings() { diff --git a/utils/logutil.ts b/utils/logutil.ts index c972acf..001bf07 100644 --- a/utils/logutil.ts +++ b/utils/logutil.ts @@ -19,9 +19,15 @@ class Logger { } public trace(e:any):any { - return e; - // console.log(`Douban Plugin trace: ${typeof e == 'string' ? e : JSON.stringify(e)}`); // return e; + console.log(`Douban Plugin trace: ${typeof e == 'string' ? e : JSON.stringify(e)}`); + return e; + } + + public traceN(notion:string, e:any):any { + // return e; + console.log(`${notion} ${typeof e == 'string' ? e : JSON.stringify(e)}`); + return e; } }