From 06be454d0e33466d29cf705e336cac4e67c6b0c8 Mon Sep 17 00:00:00 2001 From: wanxp <977741432@qq.com> Date: Sun, 30 Oct 2022 21:59:28 +0800 Subject: [PATCH] Optimize code, fix bugs and add status bar --- esbuild.config.mjs | 2 +- main.ts | 51 ++++++-- src/constant/Constsant.ts | 36 ++++++ src/douban/Douban.ts | 56 ++++----- src/douban/DoubanSettingTab.ts | 55 +++++++-- .../data/handler/DoubanAbstractLoadHandler.ts | 111 +++++++++++++++--- .../data/handler/DoubanBookLoadHandler.ts | 93 +++++++++------ .../data/handler/DoubanGameLoadHandler.ts | 6 +- .../data/handler/DoubanMovieLoadHandler.ts | 1 - .../data/handler/DoubanMusicLoadHandler.ts | 1 - .../data/handler/DoubanNoteLoadHandler.ts | 1 - .../data/handler/DoubanOtherLoadHandler.ts | 2 - .../handler/DoubanSearchChooseItemHandler.ts | 1 - .../data/handler/DoubanTeleplayLoadHandler.ts | 3 +- src/douban/data/model/DoubanBookSubject.ts | 20 +++- src/douban/data/model/DoubanSubject.ts | 20 +++- .../data/model/PropertyExplainSubject.ts | 11 ++ .../search/DoubanSearchFuzzySuggestModal.ts | 10 +- src/douban/data/search/Search.ts | 2 +- src/douban/data/search/SearchParser.ts | 9 +- src/lang/locale/en.ts | 20 +++- src/lang/locale/zh-cn.ts | 44 ++++++- src/utils/YamlUtil.ts | 32 +++++ 23 files changed, 449 insertions(+), 138 deletions(-) create mode 100644 src/constant/Constsant.ts create mode 100644 src/douban/data/model/PropertyExplainSubject.ts create mode 100644 src/utils/YamlUtil.ts diff --git a/esbuild.config.mjs b/esbuild.config.mjs index 7097a14..21fcdd5 100644 --- a/esbuild.config.mjs +++ b/esbuild.config.mjs @@ -49,5 +49,5 @@ esbuild.build({ sourcemap: prod ? false : 'inline', treeShaking: true, outfile: 'main.js', - minify: true + // minify: true }).catch(() => process.exit(1)); diff --git a/main.ts b/main.ts index 4a9000c..6eccce5 100644 --- a/main.ts +++ b/main.ts @@ -9,29 +9,48 @@ import DoubanSubject from "src/douban/data/model/DoubanSubject"; import Searcher from "src/douban/data/search/Search"; import { i18nHelper } from './src/lang/helper'; import { log } from "src/utils/Logutil"; +import {BasicConst} from "./src/constant/Constsant"; export default class DoubanPlugin extends Plugin { public settings: DoubanPluginSettings; - public doubanEtractHandler: DoubanSearchChooseItemHandler; + public doubanExtractHandler: DoubanSearchChooseItemHandler; + public doubanStatusBar: HTMLElement; async putToEditor(editor:Editor, extract:DoubanSubject) { - if(!editor || !extract) { - log.warn(i18nHelper.getMessage('140101')); - return; - } - let content:string = this.doubanEtractHandler.parseText(extract, this.settings) - if(content) { - editor.replaceSelection(content); + try { + if (!editor || !extract) { + log.warn(i18nHelper.getMessage('140101')); + return; + } + this.showStatus('140204', extract.title); + let content: string = this.doubanExtractHandler.parseText(extract, this.settings) + if (content) { + editor.replaceSelection(content); + } + this.showStatus('140205', extract.title); + }catch (e) { + this.showStatus('140206', e.message); + }finally { + setTimeout(() => this.doubanStatusBar.empty(), BasicConst.CLEAN_STATUS_BAR_DELAY) } } async search(searchTerm:string, editor: Editor) { - const resultList = await Searcher.search(searchTerm, this.settings); - new DoubanFuzzySuggester(this, editor).showSearchList(resultList); + try { + this.showStatus('140201', searchTerm); + const resultList = await Searcher.search(searchTerm, this.settings); + this.showStatus('140202', resultList.length.toString()); + new DoubanFuzzySuggester(this, editor).showSearchList(resultList); + }catch (e) { + this.showStatus('140206', e.message); + }finally { + setTimeout(() => this.doubanStatusBar.empty(), BasicConst.CLEAN_STATUS_BAR_DELAY) + } } async getDoubanTextForActiveFile(editor: Editor) { + this.doubanStatusBar = this.addStatusBarItem(); const activeFile = await this.app.workspace.getActiveFile(); if (activeFile) { const searchTerm = activeFile.basename; @@ -41,7 +60,7 @@ export default class DoubanPlugin extends Plugin { } } - async geDoubanTextForSearchTerm(editor: Editor) { + async getDoubanTextForSearchTerm(editor: Editor) { new DoubanSearchModal(this.app, this, editor).open(); } @@ -60,7 +79,7 @@ export default class DoubanPlugin extends Plugin { id: "search-douban-and-input-current-file", name: i18nHelper.getMessage("110002"), editorCallback: (editor: Editor) => - this.geDoubanTextForSearchTerm(editor), + this.getDoubanTextForSearchTerm(editor), }); //TODO will support in future // this.addCommand({ @@ -75,11 +94,17 @@ export default class DoubanPlugin extends Plugin { async loadSettings() { this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); - this.doubanEtractHandler = new DoubanSearchChooseItemHandler(this.app, this); + this.doubanExtractHandler = new DoubanSearchChooseItemHandler(this.app, this); } async saveSettings() { await this.saveData(this.settings); } + + showStatus(origin:string, message:string) { + this.doubanStatusBar.empty(); + // @ts-ignore + this.doubanStatusBar.setText(i18nHelper.getMessage(origin).replace('{0}', message)); + } } diff --git a/src/constant/Constsant.ts b/src/constant/Constsant.ts new file mode 100644 index 0000000..5d3c97e --- /dev/null +++ b/src/constant/Constsant.ts @@ -0,0 +1,36 @@ +import {i18nHelper} from "../lang/helper"; + +/** + * 常量池 + */ +export const BasicConst = { + YAML_FRONT_MATTER_SYMBOL: '---', + CLEAN_STATUS_BAR_DELAY: 5000, +} + +/** + * 模板类型 + */ +export enum TemplateTextMode { + NORMAL, + YAML, +} + +/** + * 名称模式 + */ +export enum PersonNameMode { + CH_NAME = "CH", + EN_NAME = "EN", + CH_EN_NAME = "CH_EN", +} + +/** + * 名称模式选项 + */ +export const PersonNameModeRecords: {[key in PersonNameMode]: string} = { + [PersonNameMode.CH_NAME]: i18nHelper.getMessage('121206'), + [PersonNameMode.EN_NAME]: i18nHelper.getMessage('121207'), + [PersonNameMode.CH_EN_NAME]: i18nHelper.getMessage('121208'), +} + diff --git a/src/douban/Douban.ts b/src/douban/Douban.ts index 15ba5d9..bb222b6 100644 --- a/src/douban/Douban.ts +++ b/src/douban/Douban.ts @@ -1,5 +1,4 @@ -import { i18nHelper } from "src/lang/helper"; -import { type } from "os"; +import {PersonNameMode} from "../constant/Constsant"; export interface DoubanPluginSettings { movieTemplate:string, @@ -15,14 +14,10 @@ export interface DoubanPluginSettings { personNameMode:PersonNameMode, } -export enum PersonNameMode { - CH_NAME = "CH", - EN_NAME = "EN", - CH_EN_NAME = "CH_EN", -} -export const doubanHeadrs = { + +export const doubanHeaders = { "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "Accept-Language": "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7", "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.61 Safari/537.36", @@ -30,9 +25,7 @@ export const doubanHeadrs = { export const DEFAULT_SETTINGS:DoubanPluginSettings = { movieTemplate: -` -![image]({{image}}) - +`--- doubanId: {{id}} title: {{title}} type: {{type}} @@ -43,16 +36,20 @@ datePublished: {{datePublished}} director: {{director}} actor: {{actor}} author: {{author}} +tags: {{type}} url: {{url}} desc: {{desc}} +--- + +![image]({{image}}) `, bookTemplate: -`![image|150]({{image}}) - +`--- doubanId: {{id}} title: {{title}} subTitle: {{subTitle}} originalTitle: {{originalTitle}} +series: {{series}} type: {{type}} author: {{author}} score: {{score}} @@ -64,12 +61,16 @@ url: {{url}} totalPage: {{totalPage}} price: {{price}} tags: Book +binding: {{binding}} desc: {{desc}} -`, - musicTemplate: -` +--- + ![image|150]({{image}}) +{{menu}} +`, + musicTemplate: +`--- doubanId: {{id}} title: {{title}} type: {{type}} @@ -85,13 +86,17 @@ url: {{url}} numberOfRecords: {{numberOfRecords}} tags: Music desc: {{desc}} +--- + +![image|150]({{image}}) `, noteTemplate: `--- doubanId: {{id}} title: {{title}} type: {{type}} -author: [{{author}}]({{authorUrl}}) +author: {{author}} +authorUrl: {{authorUrl}} dateTimePublished: {{datePublished}} {{timePublished}} url: {{url}} tags: Article @@ -101,26 +106,28 @@ desc: {{desc}} {{content}} `, gameTemplate: -`![image]({{image}}) - +`--- doubanId: {{id}} title: {{title}} aliases: {{aliases}} type: {{type}} score: {{score}} -tags: Game dateTimePublished: {{datePublished}} publisher: {{publisher}} genre: {{genre}} developer: {{developer}} platform: {{platform}} url: {{url}} +tags: Game desc: {{desc}} +--- + +![image]({{image}}) `, // totalWord: {{totalWord}} searchUrl: 'https://www.douban.com/search?q=', - searchHeaders: JSON.stringify(doubanHeadrs), + searchHeaders: JSON.stringify(doubanHeaders), dateFormat: "yyyy-MM-DD", timeFormat: "HH:mm:ss", arraySpilt: ", ", @@ -128,10 +135,3 @@ desc: {{desc}} } -export const personNameModeRecords: {[key in PersonNameMode]: string} = { - [PersonNameMode.CH_NAME]: i18nHelper.getMessage('121206'), - [PersonNameMode.EN_NAME]: i18nHelper.getMessage('121207'), - [PersonNameMode.CH_EN_NAME]: i18nHelper.getMessage('121208'), - } - - diff --git a/src/douban/DoubanSettingTab.ts b/src/douban/DoubanSettingTab.ts index 778dd92..32f7111 100644 --- a/src/douban/DoubanSettingTab.ts +++ b/src/douban/DoubanSettingTab.ts @@ -1,8 +1,9 @@ import { App, PluginSettingTab, Setting } from "obsidian"; -import { DEFAULT_SETTINGS, PersonNameMode, personNameModeRecords } from "./Douban"; +import { DEFAULT_SETTINGS } from "./Douban"; import DoubanPlugin from "main"; import { i18nHelper } from "src/lang/helper"; +import {PersonNameMode, PersonNameModeRecords} from "../constant/Constsant"; export class DoubanSettingTab extends PluginSettingTab { plugin: DoubanPlugin; @@ -17,7 +18,7 @@ export class DoubanSettingTab extends PluginSettingTab { containerEl.empty(); - containerEl.createEl("h2", { text: i18nHelper.getMessage('1201') }); + containerEl.createEl("h2", { text: 'Obsidian Douban' }); new Setting(containerEl).setName(i18nHelper.getMessage('120001')) .then((setting) => { @@ -77,7 +78,7 @@ export class DoubanSettingTab extends PluginSettingTab { }) ); textarea.inputEl.addClass("obsidian_douban_settings_area"); - textarea.inputEl.setAttr("rows", 10); + textarea.inputEl.setAttr("rows", 20); textarea.setPlaceholder(DEFAULT_SETTINGS.movieTemplate) .setValue(this.plugin.settings.movieTemplate) .onChange(async (value) => { @@ -87,6 +88,36 @@ export class DoubanSettingTab extends PluginSettingTab { }); }); + // new Setting(containerEl) + // .setName(i18nHelper.getMessage('120101') + 111) + // .then((setting) => { + // setting.addTextArea((textarea) => { + // setting.descEl.appendChild( + // createEl('table', 'table', (table) => { + // table.createEl('thead', 'thread', (thead) => { + // thead.createEl('tr', 'tr',(tr) => { + // tr.createEl('th', { text: i18nHelper.getMessage('120108') }); + // tr.createEl('th', { text: i18nHelper.getMessage('120109') }); + // tr.createEl('th', { text: i18nHelper.getMessage('120110') }); + // }); + // }); + // table.createEl('tbody', 'tbody', (tbody) => { + // personNameModeRecords.forEach((record) => { + // tbody.createEl('tr', (tr) => { + // tr.createEl('td', { text: record.name }); + // tr.createEl('td', { text: record.key }); + // tr.createEl('td', { text: record.desc }); + // }); + // }); + // }); + // } + // + // ); + // })); + + + + new Setting(containerEl).setName(i18nHelper.getMessage('120201')).then((setting) => { setting.addTextArea((textarea) => { setting.descEl.appendChild( @@ -103,10 +134,12 @@ export class DoubanSettingTab extends PluginSettingTab { frag.createEl('br'); frag.appendText(i18nHelper.getMessage('120207')); frag.createEl('br'); + frag.appendText(i18nHelper.getMessage('120208')); + frag.createEl('br'); }) ); textarea.inputEl.addClass("obsidian_douban_settings_area"); - textarea.inputEl.setAttr("rows", 10); + textarea.inputEl.setAttr("rows", 20); textarea.setPlaceholder(DEFAULT_SETTINGS.bookTemplate) .setValue(this.plugin.settings.bookTemplate) .onChange(async (value) => { @@ -135,7 +168,7 @@ export class DoubanSettingTab extends PluginSettingTab { }) ); textarea.inputEl.addClass("obsidian_douban_settings_area"); - textarea.inputEl.setAttr("rows", 10); + textarea.inputEl.setAttr("rows", 20); textarea.setPlaceholder(DEFAULT_SETTINGS.musicTemplate) .setValue(this.plugin.settings.musicTemplate) .onChange(async (value) => { @@ -159,11 +192,13 @@ export class DoubanSettingTab extends PluginSettingTab { frag.createEl('br'); frag.appendText(i18nHelper.getMessage('120406')); frag.createEl('br'); + frag.appendText(i18nHelper.getMessage('120407')); + frag.createEl('br'); }) ); textarea.inputEl.addClass("obsidian_douban_settings_area"); - textarea.inputEl.setAttr("rows", 10); + textarea.inputEl.setAttr("rows", 20); textarea.setPlaceholder(DEFAULT_SETTINGS.noteTemplate) .setValue(this.plugin.settings.noteTemplate) .onChange(async (value) => { @@ -190,7 +225,7 @@ export class DoubanSettingTab extends PluginSettingTab { }) ); textarea.inputEl.addClass("obsidian_douban_settings_area"); - textarea.inputEl.setAttr("rows", 10); + textarea.inputEl.setAttr("rows", 20); textarea.setPlaceholder(DEFAULT_SETTINGS.gameTemplate) .setValue(this.plugin.settings.gameTemplate) .onChange(async (value) => { @@ -216,9 +251,9 @@ export class DoubanSettingTab extends PluginSettingTab { ); // dropdwon.inputEl.addClass("settings_area"); // dropdwon.inputEl.setAttr("rows", 10); - dropdwon.addOption(PersonNameMode.CH_NAME, personNameModeRecords.CH) - dropdwon.addOption(PersonNameMode.EN_NAME, personNameModeRecords.EN) - dropdwon.addOption(PersonNameMode.CH_EN_NAME, personNameModeRecords.CH_EN) + dropdwon.addOption(PersonNameMode.CH_NAME, PersonNameModeRecords.CH) + dropdwon.addOption(PersonNameMode.EN_NAME, PersonNameModeRecords.EN) + dropdwon.addOption(PersonNameMode.CH_EN_NAME, PersonNameModeRecords.CH_EN) dropdwon.setValue(this.plugin.settings.personNameMode) .onChange(async (value:string) => { this.plugin.settings.personNameMode = value as PersonNameMode; diff --git a/src/douban/data/handler/DoubanAbstractLoadHandler.ts b/src/douban/data/handler/DoubanAbstractLoadHandler.ts index 1f448aa..63a6a17 100644 --- a/src/douban/data/handler/DoubanAbstractLoadHandler.ts +++ b/src/douban/data/handler/DoubanAbstractLoadHandler.ts @@ -1,12 +1,14 @@ -import { DoubanPluginSettings, PersonNameMode } from "src/douban/Douban"; +import {DoubanPluginSettings} from "src/douban/Douban"; import DoubanPlugin from "main"; -import DoubanSubject from '../model/DoubanSubject'; +import DoubanSubject, {DoubanParameter} from '../model/DoubanSubject'; import DoubanSubjectLoadHandler from "./DoubanSubjectLoadHandler"; import {Editor, moment, request, requestUrl, RequestUrlParam, sanitizeHTMLToDom} from "obsidian"; import { i18nHelper } from 'src/lang/helper'; import { log } from "src/utils/Logutil"; import {CheerioAPI, load} from "cheerio"; +import YamlUtil from "../../../utils/YamlUtil"; +import {BasicConst, PersonNameMode, TemplateTextMode} from "../../../constant/Constsant"; export default abstract class DoubanAbstractLoadHandler implements DoubanSubjectLoadHandler { @@ -19,26 +21,101 @@ export default abstract class DoubanAbstractLoadHandler parse(extract: T, settings:DoubanPluginSettings): string { let template:string = this.getTemplate(settings); - let resultContent = template ? template - .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("{{url}}", extract.url ? extract.url : "") - .replaceAll("{{score}}", extract.score ? extract.score + "": "") - .replaceAll("{{publisher}}", extract.publisher ? extract.publisher : "") - .replaceAll("{{datePublished}}", extract.datePublished ? moment(extract.datePublished).format(settings.dateFormat) : "") - .replaceAll("{{timePublished}}", extract.datePublished ? moment(extract.datePublished).format(settings.timeFormat) : "") - .replaceAll("{{genre}}", extract.genre ? extract.genre.join(settings.arraySpilt) : "") - : "" + let frontMatterStart:number = template.indexOf(BasicConst.YAML_FRONT_MATTER_SYMBOL, 0); + let frontMatterEnd:number = template.indexOf(BasicConst.YAML_FRONT_MATTER_SYMBOL, frontMatterStart + 1); + let frontMatter:string = ''; + let frontMatterBefore:string = ''; + let frontMatterAfter:string = ''; + if(frontMatterStart > -1 && frontMatterEnd > -1) { + frontMatterBefore = template.substring(0, frontMatterStart); + frontMatter = template.substring(frontMatterStart, frontMatterEnd + 3); + frontMatterAfter = template.substring(frontMatterEnd + 3); + if (frontMatterBefore.length > 0) { + frontMatterBefore = this.parsePartText(frontMatterBefore, extract, settings); + } + if (frontMatterAfter.length > 0) { + frontMatterAfter = this.parsePartText(frontMatterAfter, extract, settings); + } + if (frontMatter.length > 0) { + frontMatter = this.parsePartText(frontMatter, extract, settings, TemplateTextMode.YAML); + } + return frontMatterBefore + frontMatter + frontMatterAfter; + }else { + return this.parsePartText(template, extract, settings); + } + } + + private parsePartText(template: string, extract: T, settings: DoubanPluginSettings, textMode:TemplateTextMode = TemplateTextMode.NORMAL): string { + let resultContent = template + .replaceAll(DoubanParameter.ID, extract.id) + .replaceAll(DoubanParameter.TITLE, this.handleSpecialContent(extract.title, textMode)) + .replaceAll(DoubanParameter.TYPE, extract.type) + .replaceAll(DoubanParameter.SCORE, this.handleSpecialContent(extract.score)) + .replaceAll(DoubanParameter.IMAGE, extract.image) + .replaceAll(DoubanParameter.URL, extract.url) + .replaceAll(DoubanParameter.DESC, this.handleSpecialContent(extract.desc, textMode)) + .replaceAll(DoubanParameter.PUBLISHER, extract.publisher) + .replaceAll(DoubanParameter.DATE_PUBLISHED, extract.datePublished ? moment(extract.datePublished).format(settings.dateFormat) : '') + .replaceAll(DoubanParameter.TIME_PUBLISHED, extract.datePublished ? moment(extract.datePublished).format(settings.timeFormat) : '') + .replaceAll(DoubanParameter.GENRE, this.handleSpecialContent(extract.genre, textMode, settings)) ; - return this.parseText(resultContent, extract, settings); + return this.parseText(resultContent, extract, settings, textMode); + } + + /** + * 处理特殊字符 + * @param text + * @param textMode + */ + handleSpecialText(text: string, textMode: TemplateTextMode):string { + let result = text; + switch (textMode) { + case TemplateTextMode.YAML: + result = YamlUtil.handleText(text); + break; + } + return result; + } + + /** + * 处理内容数组 + * @param array + * @param settings + * @param textMode + */ + handleContentArray(array: any[], settings: DoubanPluginSettings, textMode: TemplateTextMode):string { + let result = ''; + switch (textMode) { + case TemplateTextMode.YAML: + result = array.map(YamlUtil.handleText).join(', '); + break; + default: + result = array.join(settings.arraySpilt); + } + return result; + } + + /** + * 处理特殊内容 + * @param value + * @param textMode + * @param settings + */ + handleSpecialContent(value: any, textMode:TemplateTextMode = TemplateTextMode.NORMAL, settings: DoubanPluginSettings = null): string { + let result = ''; + if (value instanceof Array) { + result = this.handleContentArray(value, settings, textMode); + }else if (value instanceof Number) { + result = value ? value.toString() : ''; + }else { + result = this.handleSpecialText(value, textMode); + } + return result; } abstract getTemplate(settings:DoubanPluginSettings):string; - abstract parseText(beforeContent:string, extract: T, settings:DoubanPluginSettings): string; + abstract parseText(beforeContent:string, extract: T, settings:DoubanPluginSettings, textMode:TemplateTextMode): string; abstract support(extract: DoubanSubject): boolean; diff --git a/src/douban/data/handler/DoubanBookLoadHandler.ts b/src/douban/data/handler/DoubanBookLoadHandler.ts index caea3ab..b5cdab7 100644 --- a/src/douban/data/handler/DoubanBookLoadHandler.ts +++ b/src/douban/data/handler/DoubanBookLoadHandler.ts @@ -1,11 +1,12 @@ -import { Editor, moment, renderResults } from "obsidian"; +import {Editor, htmlToMarkdown, moment, renderResults} from "obsidian"; import { CheerioAPI } from 'cheerio'; import DoubanAbstractLoadHandler from "./DoubanAbstractLoadHandler"; -import DoubanBookSubject from "../model/DoubanBookSubject"; +import DoubanBookSubject, {DoubanBookParameter} from "../model/DoubanBookSubject"; import DoubanPlugin from "main"; -import { DoubanPluginSettings } from "src/douban/Douban"; +import {DoubanPluginSettings} from "src/douban/Douban"; import DoubanSubject from "../model/DoubanSubject"; +import {TemplateTextMode} from "../../../constant/Constsant"; export default class DoubanBookLoadHandler extends DoubanAbstractLoadHandler { @@ -13,23 +14,30 @@ export default class DoubanBookLoadHandler extends DoubanAbstractLoadHandler meta[property= 'og:title']").get(0)).attr("content"); let desc = html(html("head > meta[property= 'og:description']").get(0)).attr("content"); - let url = html(html("head > meta[property= 'og:url']").get(0)).attr("content"); let image = html(html("head > meta[property= 'og:image']").get(0)).attr("content"); - let type = html(html("head > meta[property= 'og:type']").get(0)).attr("content"); - let author = html(html("head > meta[property= 'book:author']").get(0)).attr("content"); - let isbn = html(html("head > meta[property= 'book:isbn']").get(0)).attr("content"); + let item = html(html("head > script[type='application/ld+json']").get(0)).text(); + item = super.html_decode(item); + let obj = JSON.parse(item.replace(/[\r\n\s+]/g, '')); + let title = obj.name; + let url = obj.url; + let author = obj.author.map((a:any) => a.name); + let isbn = obj.isbn; + + let score = html(html("#interest_sectl > div > div.rating_self.clearfix > strong[property= 'v:average']").get(0)).text(); let detailDom = html(html("#info").get(0)); let publish = detailDom.find("span.pl"); - let valueMap = new Map(); + let valueMap = new Map(); publish.map((index, info) => { let key = html(info).text().trim(); - let value = '' - if(key.indexOf('作者') >= 0 || key.indexOf('丛书') >= 0 || key.indexOf('译者') >= 0 || key.indexOf('出版社') >= 0){ + let value; + if(key.indexOf('译者') >= 0){ + value = []; + html(info.parent).find("a").map((index, a) => { + value.push(html(a).text().trim()); + }); + } else if(key.indexOf('作者') >= 0 || key.indexOf('丛书') >= 0 || key.indexOf('出版社') >= 0){ value = html(info.next.next).text().trim(); }else{ value = html(info.next).text().trim(); @@ -64,31 +81,32 @@ export default class DoubanBookLoadHandler extends DoubanAbstractLoadHandler row.trim()) : []; + menu.length > 0 ? menu.pop() : menu; + const result:DoubanBookSubject = { + author: author, + translator: valueMap.has('translator') ? valueMap.get('translator') : [], image: image, datePublished: valueMap.has('datePublished') ? new Date(valueMap.get('datePublished')) : undefined, - totalWord: valueMap.has('totalWord') ? Number(valueMap.get('totalWord')) : null, isbn: isbn, publisher: valueMap.has('publisher') ? valueMap.get('publisher') : "", score: Number(score), originalTitle: valueMap.has('originalTitle') ? valueMap.get('originalTitle') : "", - subTitle: "", - totalPage: valueMap.has('originalTitle') ? Number(valueMap.get('totalPage')) : null, - belong: "", - menu: [], + subTitle: valueMap.has('subTitle') ? valueMap.get('subTitle') : "", + totalPage: valueMap.has('totalPage') ? Number(valueMap.get('totalPage')) : null, + series: valueMap.has('series') ? valueMap.get('series') : "", + menu: menu, price: valueMap.has('price') ? Number(valueMap.get('price').replace('元', '')) : null, - labels: [], - id: id ? id[0] : "", + id: id, type: "Book", title: title, desc: desc, url: url, - genre: [] + genre: [], + binding: valueMap.has('binding') ? valueMap.get('binding') : "", }; return result; } @@ -105,8 +123,9 @@ const BookKeyValueMap:Map = new Map( ['页数:', 'totalPage'], ['定价:', 'price'], ['装帧:', 'binding'], - ['丛书:', 'bush'], + ['丛书:', 'series'], ['ISBN:', 'isbn'], ['译者', 'translator'], + ['副标题:', 'subTitle'], ] ); diff --git a/src/douban/data/handler/DoubanGameLoadHandler.ts b/src/douban/data/handler/DoubanGameLoadHandler.ts index 83e05ca..4589101 100644 --- a/src/douban/data/handler/DoubanGameLoadHandler.ts +++ b/src/douban/data/handler/DoubanGameLoadHandler.ts @@ -1,13 +1,9 @@ import { CheerioAPI } from 'cheerio'; import DoubanAbstractLoadHandler from "./DoubanAbstractLoadHandler"; import DoubanPlugin from "main"; -import {DoubanPluginSettings, PersonNameMode} from "src/douban/Douban"; -import SchemaOrg from "src/utils/SchemaOrg"; -import { moment } from "obsidian"; +import {DoubanPluginSettings} from "src/douban/Douban"; import DoubanSubject from '../model/DoubanSubject'; import DoubanGameSubject from '../model/DoubanGameSubject'; -import DoubanBookSubject from "@App/data/model/DoubanBookSubject"; -import { log } from 'src/utils/Logutil'; export default class DoubanGameLoadHandler extends DoubanAbstractLoadHandler { diff --git a/src/douban/data/handler/DoubanMovieLoadHandler.ts b/src/douban/data/handler/DoubanMovieLoadHandler.ts index d823585..0ca1320 100644 --- a/src/douban/data/handler/DoubanMovieLoadHandler.ts +++ b/src/douban/data/handler/DoubanMovieLoadHandler.ts @@ -3,7 +3,6 @@ import DoubanAbstractLoadHandler from "./DoubanAbstractLoadHandler"; import DoubanPlugin from "main"; import { DoubanPluginSettings } from "src/douban/Douban"; import SchemaOrg from "src/utils/SchemaOrg"; -import { moment } from "obsidian"; import DoubanSubject from '../model/DoubanSubject'; import DoubanMovieSubject from '../model/DoubanMovieSubject'; diff --git a/src/douban/data/handler/DoubanMusicLoadHandler.ts b/src/douban/data/handler/DoubanMusicLoadHandler.ts index cd19809..746e0fb 100644 --- a/src/douban/data/handler/DoubanMusicLoadHandler.ts +++ b/src/douban/data/handler/DoubanMusicLoadHandler.ts @@ -3,7 +3,6 @@ import DoubanAbstractLoadHandler from "./DoubanAbstractLoadHandler"; import DoubanMusicSubject from '../model/DoubanMusicSubject'; import DoubanPlugin from "main"; import { DoubanPluginSettings } from "src/douban/Douban"; -import { moment } from "obsidian"; import DoubanSubject from '../model/DoubanSubject'; export default class DoubanMusicLoadHandler extends DoubanAbstractLoadHandler { diff --git a/src/douban/data/handler/DoubanNoteLoadHandler.ts b/src/douban/data/handler/DoubanNoteLoadHandler.ts index 30f74bc..8240105 100644 --- a/src/douban/data/handler/DoubanNoteLoadHandler.ts +++ b/src/douban/data/handler/DoubanNoteLoadHandler.ts @@ -5,7 +5,6 @@ import DoubanPlugin from "main"; import { DoubanPluginSettings } from "src/douban/Douban"; import DoubanSubject from '../model/DoubanSubject'; import html2markdown from '@notable/html2markdown'; -import { moment } from "obsidian"; export default class DoubanNoteLoadHandler extends DoubanAbstractLoadHandler { diff --git a/src/douban/data/handler/DoubanOtherLoadHandler.ts b/src/douban/data/handler/DoubanOtherLoadHandler.ts index 14d6dbf..ec1bf86 100644 --- a/src/douban/data/handler/DoubanOtherLoadHandler.ts +++ b/src/douban/data/handler/DoubanOtherLoadHandler.ts @@ -1,5 +1,3 @@ -import { Editor, Notice } from "obsidian"; - import { CheerioAPI } from "cheerio"; import DoubanAbstractLoadHandler from "./DoubanAbstractLoadHandler"; import { DoubanPluginSettings } from "src/douban/Douban"; diff --git a/src/douban/data/handler/DoubanSearchChooseItemHandler.ts b/src/douban/data/handler/DoubanSearchChooseItemHandler.ts index 21186ec..18c4c92 100644 --- a/src/douban/data/handler/DoubanSearchChooseItemHandler.ts +++ b/src/douban/data/handler/DoubanSearchChooseItemHandler.ts @@ -32,7 +32,6 @@ export class DoubanSearchChooseItemHandler { new DoubanGameLoadHandler(doubanPlugin), this._doubanSubjectHandlerDefault]; - } public handle(searchExtract:DoubanSubject, editor: Editor):void{ diff --git a/src/douban/data/handler/DoubanTeleplayLoadHandler.ts b/src/douban/data/handler/DoubanTeleplayLoadHandler.ts index 9004410..e522e50 100644 --- a/src/douban/data/handler/DoubanTeleplayLoadHandler.ts +++ b/src/douban/data/handler/DoubanTeleplayLoadHandler.ts @@ -5,7 +5,6 @@ import { DoubanPluginSettings } from "src/douban/Douban"; import DoubanSubject from "../model/DoubanSubject"; import DoubanTeleplaySubject from "../model/DoubanTeleplaySubject"; import SchemaOrg from "src/utils/SchemaOrg"; -import { moment } from "obsidian"; /** * teleplay @@ -53,7 +52,7 @@ export class DoubanTeleplayLoadHandler extends DoubanAbstractLoadHandler = new Map([ + ['id', ''], +]); + +export const DoubanParameter = { + ID: '{{id}}', + TITLE: '{{title}}', + TYPE: '{{type}}', + SCORE: '{{score}}', + IMAGE: '{{image}}', + URL: '{{url}}', + DESC: '{{desc}}', + PUBLISHER: '{{publisher}}', + DATE_PUBLISHED: '{{datePublished}}', + TIME_PUBLISHED: '{{timePublished}}', + GENRE: '{{genre}}', +} diff --git a/src/douban/data/model/PropertyExplainSubject.ts b/src/douban/data/model/PropertyExplainSubject.ts new file mode 100644 index 0000000..7893dab --- /dev/null +++ b/src/douban/data/model/PropertyExplainSubject.ts @@ -0,0 +1,11 @@ +export default class PropertyExplainSubject { + name:string; + desc:string; + example:string; + + constructor(name:string, desc:string, example:string) { + this.name = name; + this.desc = desc; + this.example = example; + } +} diff --git a/src/douban/data/search/DoubanSearchFuzzySuggestModal.ts b/src/douban/data/search/DoubanSearchFuzzySuggestModal.ts index 8b5a773..15e9090 100644 --- a/src/douban/data/search/DoubanSearchFuzzySuggestModal.ts +++ b/src/douban/data/search/DoubanSearchFuzzySuggestModal.ts @@ -1,8 +1,9 @@ -import { App, Editor, FuzzySuggestModal } from "obsidian"; +import { Editor, FuzzySuggestModal } from "obsidian"; import DoubanPlugin from "main"; import DoubanSearchResultSubject from "../model/DoubanSearchResultSubject"; import { log } from "src/utils/Logutil"; +import {i18nHelper} from "../../../lang/helper"; export {DoubanFuzzySuggester} @@ -17,7 +18,7 @@ class DoubanFuzzySuggester extends FuzzySuggestModal super(app); this.editor = editor; this.plugin = plugin; - this.setPlaceholder("Choose an item..."); + this.setPlaceholder(i18nHelper.getMessage('150101')); } @@ -28,12 +29,13 @@ class DoubanFuzzySuggester extends FuzzySuggestModal } getItemText(item: DoubanSearchResultSubject): string { - let text:string = item.type + "/" + item.score + "/" + item.title + "/" + item.cast; + let text:string = item.type + "/" + (item.score ? item.score : '-') + "/" + item.title + "/" + item.cast; return text; } onChooseItem(item: DoubanSearchResultSubject, evt: MouseEvent | KeyboardEvent): void { - this.plugin.doubanEtractHandler.handle(item, this.editor); + this.plugin.showStatus('140204', item.title); + this.plugin.doubanExtractHandler.handle(item, this.editor); } public showSearchList(doubanSearchResultExtractList:DoubanSearchResultSubject[]) { diff --git a/src/douban/data/search/Search.ts b/src/douban/data/search/Search.ts index b159d24..7f818cf 100644 --- a/src/douban/data/search/Search.ts +++ b/src/douban/data/search/Search.ts @@ -1,4 +1,4 @@ -import { DoubanPluginSettings, doubanHeadrs } from 'src/douban/Douban'; +import { DoubanPluginSettings, doubanHeaders } from 'src/douban/Douban'; import DoubanSearchResultSubject from '../model/DoubanSearchResultSubject'; import SearchParserHandler from './SearchParser'; diff --git a/src/douban/data/search/SearchParser.ts b/src/douban/data/search/SearchParser.ts index bbcb887..0a6f045 100644 --- a/src/douban/data/search/SearchParser.ts +++ b/src/douban/data/search/SearchParser.ts @@ -14,13 +14,16 @@ export default class SearchParserHandler { let urlResult = urlPattern.exec(linkValue); let cast = item.find(".subject-cast").text(); let score = item.find(".rating_nums").text(); + let title = item.find("div.content > div > h3 > a").text(); + let type = item.find("div.content > div > h3 > span").text(); + let desc = item.find("div.content > p").text(); const result:DoubanSearchResultSubject = { id: ececResult ? ececResult[0] : '', - title: item.find("div.content > div > h3 > a").text(), + title: title ? title : '-', score: score ? Number(score) : null, cast: cast, - type: item.find("div.content > div > h3 > span").text(), - desc: item.find("div.content > p").text(), + type: type ? type : '-', + desc: desc ? desc : '-', url: urlResult ? decodeURIComponent(urlResult[0]) : 'https://www.douban.com', image: "", publisher: "", diff --git a/src/lang/locale/en.ts b/src/lang/locale/en.ts index 3d9d9fc..87bd18a 100644 --- a/src/lang/locale/en.ts +++ b/src/lang/locale/en.ts @@ -32,8 +32,9 @@ export default { '120205': `{{url}}, {{desc}}, {{datePublished}}, {{publisher}}`, '120206': `{{originalTitle}}, {{subTitle}}, {{author}},`, '120207': `{{translator}}, {{isbn}}, {{price}}, {{totalPage}}`, + '120208': `{{series}}, {{binding}}, {{menu}}`, - '120301': `Music Content Template`, + '120301': `Music Content Template`, '120302': `Set markdown Music template for extract to be inserted.`, '120303': `Available Music template variables are :`, '120304': `{{id}}, {{title}}, {{type}}, {{score}}, {{image}},`, @@ -47,6 +48,7 @@ export default { '120404': `{{id}}, {{title}}, {{type}}, {{image}},`, '120405': `{{url}}, {{desc}}, {{datePublished}}`, '120406': `{{author}}, {{authorUrl}}, {{content}}`, + '120407': `{{timePublished}}`, '121301': `Game Content Template`, '121302': `Set markdown Game template for extract to be inserted.`, @@ -65,8 +67,8 @@ export default { '120508': `format reference`, '120601': `Array Spilt String`, '120602': `string to join between array type, such as authors, actors. - example: '/' - the list of actor's name will be shown as: 'actor1/actor2/actor3'`, + example: ',' + the list of actor's name will be shown as: 'actor1,actor2,actor3'`, '120701': `Douban Request Headers`, '120801': `This type of import is not supported temporarily, please go to github to submit issues for help`, '120901': `Douban`, @@ -86,4 +88,16 @@ export default { '130301': `Obsidian Douban Plugin Warn: `, '140101': `Not support for current type. You can add Issues at Github:Wanxp/obsidian-douban`, + '140201': `[Obsidian Douban]: searching '{0}'...`, + '140202': `[Obsidian Douban]: result {0} rows`, + '140203': `[Obsidian Douban]: request '{0}'`, + '140204': `[Obsidian Douban]: replace '{0}'`, + '140205': `[Obsidian Douban]: complete '{0}'`, + '140206': `[Obsidian Douban]: occur error '{0}'`, + + '150101': `Choose an item...`, + + //content + '200101': `. `, + } diff --git a/src/lang/locale/zh-cn.ts b/src/lang/locale/zh-cn.ts index ebe6f00..e16d039 100644 --- a/src/lang/locale/zh-cn.ts +++ b/src/lang/locale/zh-cn.ts @@ -1,4 +1,7 @@ //简体中文 +import DoubanBookSubject from "@App/data/model/DoubanBookSubject"; +import {extract} from "jest-docblock"; + export default { //main.ts '110001': '用当前文档名搜索豆瓣并写入当前文档', @@ -32,8 +35,10 @@ export default { '120205': `{{url}}, {{desc}}, {{datePublished}}, {{publisher}}`, '120206': `{{originalTitle}}, {{subTitle}}, {{author}},`, '120207': `{{translator}}, {{isbn}}, {{price}}, {{totalPage}}`, + '120208': `{{series}}, {{binding}}, {{menu}}`, - '120301': `音乐文本模板`, + + '120301': `音乐文本模板`, '120302': `设置选择音乐后导入的文本内容模板,`, '120303': `支持以下参数名称 :`, '120304': `{{id}}, {{title}}, {{type}}, {{image}},`, @@ -47,6 +52,7 @@ export default { '120404': `{{id}}, {{title}}, {{type}}, {{image}},`, '120405': `{{url}}, {{desc}}, {{datePublished}}`, '120406': `{{author}}, {{authorUrl}}, {{content}}`, + '120407': `{{timePublished}}`, '121301': `游戏文本模板`, '121302': `设置选择游戏后导入的文本内容模板,`, @@ -65,8 +71,8 @@ export default { '120508': `格式参考`, '120601': `数组分割字符串`, '120602': `当模板中的变量存在数组, 则需要设定数组元素中的分割符号,比如演员列表等. - 举例: '/' - 则演员表将会显示为: '演员1/演员2/演员3'`, + 举例: ',' + 则演员表将会显示为: '演员1,演员2,演员3'`, '120701': `豆瓣HTTP请求头`, '120702': `如果豆瓣搜索或者获取数据失败,请尝试修改这个参数,\n 参数获取方式为:\n @@ -89,5 +95,37 @@ export default { '130103': `Obsidian Douban插件异常提示:`, '140101': `当前版本暂不支持该类型导入,请升级Obsidian Douban或至github提交issuess获取帮助`, + '140201': `[Obsidian Douban]: 开始搜索'{0}'...`, + '140202': `[Obsidian Douban]: 搜索条数{0}条`, + '140203': `[Obsidian Douban]: 请求豆瓣'{0}'...`, + '140204': `[Obsidian Douban]: 替换文本'{0}'...`, + '140205': `[Obsidian Douban]: 处理完成'{0}'`, + '140206': `[Obsidian Douban]: 出现错误'{0}'`, + '150101': `选择一项内容...`, + + + //content + '200101': `。`, + +//book example + 'book': { + id: {desc: `豆瓣ID`, example: `25982198`}, + title: {desc: `书名`, example: `社会心理学(第11版,精装彩印)`}, + type: {desc: `类型`, example: `Book`}, + score: {desc: `评分`, example: `9.4`}, + image: {desc: `图片URL`, example: `https://img1.doubanio.com/view/subject/l/public/s28261247.jpg`}, + url: {desc: `豆瓣URL`, example: `https://book.douban.com/subject/25982198/`}, + desc: {desc: `简述`, example: `戴维·迈尔斯的《社会心理学》是美国700 多所大专院校社会心理学教学所采用的教材,自出版以来深受广大师生和社会心理学爱好者的喜爱,并被翻译成多种语言,有着广泛的影响力。本书译自第11 版。全书共分四...`}, + publisher: {desc: `出版社`, example: `人民邮电出版社`}, + datePublished: {desc: `出版时间`, example: `2014-10-1`}, + genre: {desc: `类型`, example: `社会科学`}, + author: {desc: `作者`, example: `戴维·迈尔斯`}, + translator: {desc: `译者`, example: `侯玉波 / 乐国安 / 张志勇`}, + isbn: {desc: `ISBN`, example: `9787115369840`}, + originTitle: {desc: `原作名`, example: `Social Psychology (11th)`}, + subTitle: {desc: `副标题`, example: `社会心理学`}, + binding: {desc: `装帧`, example: `精装`}, + totalPages: {desc: `页数`, example: `707`}, + } } diff --git a/src/utils/YamlUtil.ts b/src/utils/YamlUtil.ts new file mode 100644 index 0000000..ea83528 --- /dev/null +++ b/src/utils/YamlUtil.ts @@ -0,0 +1,32 @@ +import {i18nHelper} from "../lang/helper"; + +export default class YamlUtil { + + + + public static hasSpecialChar(str:string):boolean { + return SPECIAL_CHAR_REG.test(str); + } + + + public static handleSpecialChar(text: string):string { + // return this.hasSpecialChar(text) ? text.replace(SPECIAL_CHAR_REG, (match, p1) => { + // return SPECIAL_CHAR_REG_REPLACE.get(p1) || p1; + // }) : text; + //temp solution + return '"' + text + '"'; + } + + public static handleText(text: string) { + return YamlUtil.hasSpecialChar(text) ? YamlUtil.handleSpecialChar(text) + .replace(/[\n]{1,}/, '。') + .replace('。。', '。') : text; + } + +} + +const SPECIAL_CHAR_REG = /[{}\[\]&*#?|\-<>=!%@:`,\n]/; +const SPECIAL_CHAR_REG_REPLACE:Map = new Map([ + ['{', '\\{'], +]); +