optimize code and settings

This commit is contained in:
wanxp 2022-11-03 21:33:55 +08:00
parent 8316dc319c
commit 16aacc680b
38 changed files with 1135 additions and 701 deletions

81
main.ts

@ -1,31 +1,38 @@
import { DEFAULT_SETTINGS, DoubanPluginSettings } from "./src/douban/Douban";
import {Editor, Plugin} from "obsidian";
import {DoubanFuzzySuggester} from "src/douban/data/search/DoubanSearchFuzzySuggestModal";
import {DoubanSearchChooseItemHandler} from "src/douban/data/handler/DoubanSearchChooseItemHandler";
import {DoubanSearchModal} from "src/douban/data/search/DoubanSearchModal";
import { DoubanSettingTab } from "src/douban/DoubanSettingTab";
import {DoubanSettingTab} from "@App/setting/DoubanSettingTab";
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";
import {BasicConst, SearchHandleMode} from "./src/constant/Constsant";
import FileHandler from "./src/file/FileHandler";
import HandleContext from "@App/data/model/HandleContext";
import HandleResult from "@App/data/model/HandleResult";
import {FileUtil} from "./src/utils/FileUtil";
import { DoubanPluginSetting } from "@App/setting/model/DoubanPluginSetting";
import {DEFAULT_SETTINGS} from "./src/constant/DefaultSettings";
export default class DoubanPlugin extends Plugin {
public settings: DoubanPluginSettings;
public settings: DoubanPluginSetting;
public doubanExtractHandler: DoubanSearchChooseItemHandler;
public doubanStatusBar: HTMLElement;
public fileHandler: FileHandler;
async putToEditor(editor:Editor, extract:DoubanSubject) {
async putToObsidian(context: HandleContext, extract: DoubanSubject) {
try {
if (!editor || !extract) {
if (!extract) {
log.warn(i18nHelper.getMessage('140101'));
return;
}
this.showStatus('140204', extract.title);
let content: string = this.doubanExtractHandler.parseText(extract, this.settings)
const content = await this.doubanExtractHandler.parseText(extract, context)
if (content) {
editor.replaceSelection(content);
this.putContentToObsidian(context, content);
}
this.showStatus('140205', extract.title);
} catch (e) {
@ -35,13 +42,32 @@ export default class DoubanPlugin extends Plugin {
}
}
async putContentToObsidian(context: HandleContext, content: HandleResult) {
const {mode} = context;
switch (mode) {
case SearchHandleMode.FOR_CREATE:
this.createFile(context, content);
break;
case SearchHandleMode.FOR_REPLACE:
this.putToEditor(context.editor, content.content);
break;
}
}
async search(searchTerm:string, editor: Editor) {
async putToEditor(editor: Editor, content: string) {
editor.replaceSelection(content);
}
async createFile(context: HandleContext, content: HandleResult) {
this.fileHandler.createNewNoteWithData(content.fileName,content.content);
}
async search(searchTerm: string, context: HandleContext) {
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);
new DoubanFuzzySuggester(this, context).showSearchList(resultList);
} catch (e) {
this.showStatus('140206', e.message);
} finally {
@ -49,18 +75,22 @@ export default class DoubanPlugin extends Plugin {
}
}
async getDoubanTextForActiveFile(editor: Editor) {
async getDoubanTextForActiveFile(context: HandleContext) {
const activeFile = await this.app.workspace.getActiveFile();
if (activeFile) {
const searchTerm = activeFile.basename;
if (searchTerm) {
await this.search(searchTerm, editor);
await this.search(searchTerm, context);
}
}
}
async getDoubanTextForSearchTerm(editor: Editor) {
new DoubanSearchModal(this.app, this, editor).open();
async getDoubanTextForCreateNewNote(context: HandleContext) {
new DoubanSearchModal(this.app, this, context).open();
}
async getDoubanTextForSearchTerm(context: HandleContext) {
new DoubanSearchModal(this.app, this, context).open();
}
async onload() {
@ -68,11 +98,18 @@ export default class DoubanPlugin extends Plugin {
this.doubanStatusBar = this.addStatusBarItem();
this.addCommand({
id: "search-douban-import-and-create-file",
name: i18nHelper.getMessage("110101"),
callback: () =>
this.getDoubanTextForCreateNewNote({mode: SearchHandleMode.FOR_CREATE, settings: this.settings}),
});
this.addCommand({
id: "search-douban-by-current-file-name",
name: i18nHelper.getMessage("110001"),
editorCallback: (editor: Editor) =>
this.getDoubanTextForActiveFile(editor),
this.getDoubanTextForActiveFile({mode: SearchHandleMode.FOR_REPLACE, settings: this.settings, editor: editor}),
});
@ -80,15 +117,8 @@ export default class DoubanPlugin extends Plugin {
id: "search-douban-and-input-current-file",
name: i18nHelper.getMessage("110002"),
editorCallback: (editor: Editor) =>
this.getDoubanTextForSearchTerm(editor),
this.getDoubanTextForSearchTerm({mode: SearchHandleMode.FOR_REPLACE, settings: this.settings, editor: editor}),
});
//TODO will support in future
// this.addCommand({
// id: "sync-douban-broadcast-by-user-id",
// name: i18nHelper.getMessage('110006'),
// editorCallback: (editor: Editor) =>
// this.geDoubanTextForSearchTerm(editor),
// });
this.addSettingTab(new DoubanSettingTab(this.app, this));
}
@ -96,12 +126,17 @@ export default class DoubanPlugin extends Plugin {
async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
this.doubanExtractHandler = new DoubanSearchChooseItemHandler(this.app, this);
this.fileHandler = new FileHandler(this.app);
}
async saveSettings() {
await this.saveData(this.settings);
}
showStatus(origin: string, message: string) {
this.doubanStatusBar.empty();

95
package-lock.json generated

@ -1,6 +1,6 @@
{
"name": "obsidian-sample-plugin",
"version": "1.0.1",
"name": "obsidian-douban-plugin",
"version": "v1.5.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -781,6 +781,11 @@
"mime2ext": "^1.0.1"
}
},
"@popperjs/core": {
"version": "2.11.6",
"resolved": "https://registry.npmmirror.com/@popperjs/core/-/core-2.11.6.tgz",
"integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw=="
},
"@sinclair/typebox": {
"version": "0.23.5",
"resolved": "https://registry.npmmirror.com/@sinclair/typebox/-/typebox-0.23.5.tgz",
@ -1096,20 +1101,6 @@
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
"dev": true
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"axios": {
"version": "0.27.2",
"resolved": "https://registry.npmmirror.com/axios/-/axios-0.27.2.tgz",
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
"requires": {
"follow-redirects": "^1.14.9",
"form-data": "^4.0.0"
}
},
"babel-jest": {
"version": "28.1.2",
"resolved": "https://registry.npmmirror.com/babel-jest/-/babel-jest-28.1.2.tgz",
@ -1371,14 +1362,6 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"requires": {
"delayed-stream": "~1.0.0"
}
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz",
@ -1422,11 +1405,6 @@
"resolved": "https://registry.npmmirror.com/css-what/-/css-what-6.1.0.tgz",
"integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw=="
},
"cuint": {
"version": "0.2.2",
"resolved": "https://registry.npmmirror.com/cuint/-/cuint-0.2.2.tgz",
"integrity": "sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw=="
},
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz",
@ -1448,11 +1426,6 @@
"integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
"dev": true
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
},
"detect-newline": {
"version": "3.1.0",
"resolved": "https://registry.npmmirror.com/detect-newline/-/detect-newline-3.1.0.tgz",
@ -1507,14 +1480,6 @@
"domhandler": "^5.0.1"
}
},
"douban-search-crack": {
"version": "1.0.6",
"resolved": "https://registry.npmmirror.com/douban-search-crack/-/douban-search-crack-1.0.6.tgz",
"integrity": "sha512-IchjtqsemiJH0x7xo/7/QjEVa0khKMfY0KMtA9GMXXSQRJFPtiedi5Z0htB/xq0Thpo6SsbLXYJIkdVX3n3Qng==",
"requires": {
"xxhashjs": "^0.2.2"
}
},
"electron-to-chromium": {
"version": "1.4.185",
"resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.185.tgz",
@ -1857,21 +1822,6 @@
"path-exists": "^4.0.0"
}
},
"follow-redirects": {
"version": "1.15.0",
"resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.0.tgz",
"integrity": "sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ=="
},
"form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -2722,19 +2672,6 @@
"picomatch": "^2.3.1"
}
},
"mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
},
"mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"requires": {
"mime-db": "1.52.0"
}
},
"mime2ext": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/mime2ext/-/mime2ext-1.0.1.tgz",
@ -2773,11 +2710,6 @@
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
"dev": true
},
"node-fetch": {
"version": "2.6.1",
"resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-2.6.1.tgz",
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
},
"node-int64": {
"version": "0.4.0",
"resolved": "https://registry.npmmirror.com/node-int64/-/node-int64-0.4.0.tgz",
@ -3261,11 +3193,6 @@
"integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==",
"dev": true
},
"tiny-network": {
"version": "0.0.6",
"resolved": "https://registry.npmmirror.com/tiny-network/-/tiny-network-0.0.6.tgz",
"integrity": "sha512-fYNn6nnbKZFch5nd1aWtwVwJG7zJc5dcyypKx1PgJvv1EFr/tUhQPSFx5Tw6lKTVqemxZystG8mkbQuu/P/R5g=="
},
"tmpl": {
"version": "1.0.5",
"resolved": "https://registry.npmmirror.com/tmpl/-/tmpl-1.0.5.tgz",
@ -3416,14 +3343,6 @@
"signal-exit": "^3.0.7"
}
},
"xxhashjs": {
"version": "0.2.2",
"resolved": "https://registry.npmmirror.com/xxhashjs/-/xxhashjs-0.2.2.tgz",
"integrity": "sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==",
"requires": {
"cuint": "^0.2.2"
}
},
"y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz",

@ -27,6 +27,7 @@
},
"dependencies": {
"@notable/html2markdown": "^1.1.3",
"@popperjs/core": "^2.11.6",
"cheerio": "^1.0.0-rc.11",
"schema-dts": "^1.1.0"
}

@ -16,6 +16,20 @@ export enum TemplateTextMode {
YAML,
}
/**
*
*/
export enum SearchHandleMode {
/**
*
*/
FOR_REPLACE,
/**
*
*/
FOR_CREATE,
}
/**
*
*/
@ -25,6 +39,19 @@ export enum PersonNameMode {
CH_EN_NAME = "CH_EN",
}
/**
* key
*
*/
export enum TemplateKey {
movieTemplateFile= 'movieTemplateFile',
bookTemplateFile = 'bookTemplateFile',
musicTemplateFile = 'musicTemplateFile',
noteTemplateFile = 'noteTemplateFile',
gameTemplateFile = 'gameTemplateFile',
teleplayTemplateFile = 'teleplayTemplateFile',
}
/**
*
*/

@ -0,0 +1,20 @@
import {DoubanPluginSetting} from "@App/setting/model/DoubanPluginSetting";
import {PersonNameMode} from "./Constsant";
import {doubanHeaders} from "./Douban";
export const DEFAULT_SETTINGS: DoubanPluginSetting = {
movieTemplateFile: ``,
bookTemplateFile: ``,
musicTemplateFile: ``,
noteTemplateFile: ``,
gameTemplateFile: ``,
teleplayTemplateFile: ``,
searchUrl: 'https://www.douban.com/search?q=',
searchHeaders: JSON.stringify(doubanHeaders),
dateFormat: "yyyy-MM-DD",
timeFormat: "HH:mm:ss",
arraySpilt: ", ",
personNameMode: PersonNameMode.CH_NAME,
dataFilePath: "",
dataFileNamePath: "/{{type}}/{{title}}"
}

@ -1,29 +1,5 @@
import {PersonNameMode} from "../constant/Constsant";
export interface DoubanPluginSettings {
movieTemplate: string,
bookTemplate: string,
musicTemplate: string,
noteTemplate: string,
gameTemplate: string,
dateFormat: string,
timeFormat: string,
searchUrl: string,
arraySpilt: string,
searchHeaders?: string,
personNameMode: PersonNameMode,
}
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",
};
export const DEFAULT_SETTINGS: DoubanPluginSettings = {
movieTemplate:
`---
export const DEFAULT_TEMPLATE_CONTENT = {
movieTemplateFileContent: `---
doubanId: {{id}}
title: {{title}}
type: {{type}}
@ -36,13 +12,13 @@ actor: {{actor}}
author: {{author}}
tags: {{type}}
url: {{url}}
dataTime: {{currentDate}} {{currentTime}}
desc: {{desc}}
---
![image]({{image}})
`,
bookTemplate:
`---
bookTemplateFileContent: `---
doubanId: {{id}}
title: {{title}}
subTitle: {{subTitle}}
@ -60,6 +36,7 @@ totalPage: {{totalPage}}
price: {{price}}
tags: Book
binding: {{binding}}
dataTime: {{currentDate}} {{currentTime}}
desc: {{desc}}
---
@ -67,8 +44,7 @@ desc: {{desc}}
{{menu}}
`,
musicTemplate:
`---
musicTemplateFileContent: `---
doubanId: {{id}}
title: {{title}}
type: {{type}}
@ -83,13 +59,13 @@ barcode: {{barcode}}
url: {{url}}
records: {{records}}
tags: Music
dataTime: {{currentDate}} {{currentTime}}
desc: {{desc}}
---
![image|150]({{image}})
`,
noteTemplate:
`---
noteTemplateFileContent: `---
doubanId: {{id}}
title: {{title}}
type: {{type}}
@ -98,13 +74,13 @@ authorUrl: {{authorUrl}}
dateTimePublished: {{datePublished}} {{timePublished}}
url: {{url}}
tags: Article
dataTime: {{currentDate}} {{currentTime}}
desc: {{desc}}
---
{{content}}
`,
gameTemplate:
`---
gameTemplateFileContent: `---
doubanId: {{id}}
title: {{title}}
aliases: {{aliases}}
@ -117,19 +93,28 @@ developer: {{developer}}
platform: {{platform}}
url: {{url}}
tags: Game
dataTime: {{currentDate}} {{currentTime}}
desc: {{desc}}
---
![image]({{image}})
`,teleplayTemplateFileContent: `---
doubanId: {{id}}
title: {{title}}
type: {{type}}
score: {{score}}
originalTitle: {{originalTitle}}
genre: {{genre}}
datePublished: {{datePublished}}
director: {{director}}
actor: {{actor}}
author: {{author}}
tags: {{type}}
url: {{url}}
dataTime: {{currentDate}} {{currentTime}}
desc: {{desc}}
---
![image]({{image}})
`,
// totalWord: {{totalWord}}
searchUrl: 'https://www.douban.com/search?q=',
searchHeaders: JSON.stringify(doubanHeaders),
dateFormat: "yyyy-MM-DD",
timeFormat: "HH:mm:ss",
arraySpilt: ", ",
personNameMode: PersonNameMode.CH_NAME
}

12
src/constant/Douban.ts Normal file

@ -0,0 +1,12 @@
import {PersonNameMode} from "./Constsant";
import {DoubanPluginSetting} from "@App/setting/model/DoubanPluginSetting";
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",
};

@ -1,350 +0,0 @@
import {App, PluginSettingTab, Setting} from "obsidian";
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;
constructor(app: App, plugin: DoubanPlugin) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
const {containerEl} = this;
containerEl.empty();
containerEl.createEl("h2", {text: 'Obsidian Douban'});
new Setting(containerEl).setName(i18nHelper.getMessage('120001'))
.then((setting) => {
setting.addText((textField) => {
setting.descEl.appendChild(
createFragment((frag) => {
frag.appendText(i18nHelper.getMessage('120002'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120003'));
frag.createEl(
'a',
{
text: i18nHelper.getMessage('120901'),
href: 'https://www.douban.com',
},
(a) => {
a.setAttr('target', '_blank');
}
);
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120004'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120005'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120006'));
frag.createEl('br');
})
);
textField.inputEl.addClass("obsidian_douban_settings_textField");
textField
.setPlaceholder(DEFAULT_SETTINGS.searchUrl)
.setValue(this.plugin.settings.searchUrl)
.onChange(async (value) => {
this.plugin.settings.searchUrl = value;
await this.plugin.saveSettings();
});
});
});
new Setting(containerEl).setName(i18nHelper.getMessage('120501')).then((setting) => {
setting.addMomentFormat((mf) => {
setting.descEl.appendChild(
createFragment((frag) => {
frag.appendText(
i18nHelper.getMessage('120503')
);
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120506') + ' ');
frag.createEl(
'a',
{
text: i18nHelper.getMessage('120508'),
href: 'https://momentjs.com/docs/#/displaying/format/',
},
(a) => {
a.setAttr('target', '_blank');
}
);
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120507') + ': ');
mf.setSampleEl(frag.createEl('b', {cls: 'u-pop'}));
frag.createEl('br');
})
);
mf.setPlaceholder(DEFAULT_SETTINGS.dateFormat);
mf.setValue(this.plugin.settings.dateFormat)
mf.onChange(async (value) => {
this.plugin.settings.dateFormat = value;
await this.plugin.saveSettings();
});
});
});
new Setting(containerEl).setName(i18nHelper.getMessage('120502')).then((setting) => {
setting.addMomentFormat((mf) => {
setting.descEl.appendChild(
createFragment((frag) => {
frag.appendText(
i18nHelper.getMessage('120504')
);
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120506') + ' ');
frag.createEl(
'a',
{
text: i18nHelper.getMessage('120508'),
href: 'https://momentjs.com/docs/#/displaying/format/',
},
(a) => {
a.setAttr('target', '_blank');
}
);
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120507') + ': ');
mf.setSampleEl(frag.createEl('b', {cls: 'u-pop'}));
frag.createEl('br');
})
);
mf.setPlaceholder(DEFAULT_SETTINGS.timeFormat);
mf.setValue(this.plugin.settings.timeFormat)
mf.onChange(async (value) => {
this.plugin.settings.timeFormat = value;
await this.plugin.saveSettings();
});
});
});
new Setting(containerEl)
.setName(i18nHelper.getMessage('120601'))
.setDesc(i18nHelper.getMessage('120602'))
.addText((textField) => {
textField.setPlaceholder(DEFAULT_SETTINGS.arraySpilt)
.setValue(this.plugin.settings.arraySpilt)
.onChange(async (value) => {
this.plugin.settings.arraySpilt = value;
await this.plugin.saveSettings();
});
});
new Setting(containerEl).setName(i18nHelper.getMessage('121201')).then((setting) => {
setting.addDropdown((dropdwon) => {
setting.descEl.appendChild(
createFragment((frag) => {
frag.appendText(i18nHelper.getMessage('121202'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('121203'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('121204'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('121205'));
frag.createEl('br');
})
);
// 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.setValue(this.plugin.settings.personNameMode)
.onChange(async (value: string) => {
this.plugin.settings.personNameMode = value as PersonNameMode;
await this.plugin.saveSettings();
});
});
});
new Setting(containerEl).setName(i18nHelper.getMessage('120101')).then((setting) => {
setting.addTextArea((textarea) => {
setting.descEl.appendChild(
createFragment((frag) => {
frag.appendText(i18nHelper.getMessage('120102'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120103'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120104'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120105'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120106'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120107'));
frag.createEl('br');
})
);
textarea.inputEl.addClass("obsidian_douban_settings_area");
textarea.inputEl.setAttr("rows", 20);
textarea.setPlaceholder(DEFAULT_SETTINGS.movieTemplate)
.setValue(this.plugin.settings.movieTemplate)
.onChange(async (value) => {
this.plugin.settings.movieTemplate = value;
await this.plugin.saveSettings();
});
});
});
// 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(
createFragment((frag) => {
frag.appendText(i18nHelper.getMessage('120202'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120203'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120204'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120205'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120206'));
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", 20);
textarea.setPlaceholder(DEFAULT_SETTINGS.bookTemplate)
.setValue(this.plugin.settings.bookTemplate)
.onChange(async (value) => {
this.plugin.settings.bookTemplate = value;
await this.plugin.saveSettings();
});
});
});
new Setting(containerEl).setName(i18nHelper.getMessage('120301')).then((setting) => {
setting.addTextArea((textarea) => {
setting.descEl.appendChild(
createFragment((frag) => {
frag.appendText(i18nHelper.getMessage('120302'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120303'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120304'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120305'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120306'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120307'));
frag.createEl('br');
})
);
textarea.inputEl.addClass("obsidian_douban_settings_area");
textarea.inputEl.setAttr("rows", 20);
textarea.setPlaceholder(DEFAULT_SETTINGS.musicTemplate)
.setValue(this.plugin.settings.musicTemplate)
.onChange(async (value) => {
this.plugin.settings.musicTemplate = value;
await this.plugin.saveSettings();
});
});
});
new Setting(containerEl).setName(i18nHelper.getMessage("120401")).then((setting) => {
setting.addTextArea((textarea) => {
setting.descEl.appendChild(
createFragment((frag) => {
frag.appendText(i18nHelper.getMessage('120402'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120403'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120404'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120405'));
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", 20);
textarea.setPlaceholder(DEFAULT_SETTINGS.noteTemplate)
.setValue(this.plugin.settings.noteTemplate)
.onChange(async (value) => {
this.plugin.settings.noteTemplate = value;
await this.plugin.saveSettings();
});
});
});
new Setting(containerEl).setName(i18nHelper.getMessage('121301')).then((setting) => {
setting.addTextArea((textarea) => {
setting.descEl.appendChild(
createFragment((frag) => {
frag.appendText(i18nHelper.getMessage('121302'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('121303'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('121304'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('121305'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('121306'));
frag.createEl('br');
})
);
textarea.inputEl.addClass("obsidian_douban_settings_area");
textarea.inputEl.setAttr("rows", 20);
textarea.setPlaceholder(DEFAULT_SETTINGS.gameTemplate)
.setValue(this.plugin.settings.gameTemplate)
.onChange(async (value) => {
this.plugin.settings.gameTemplate = value;
await this.plugin.saveSettings();
});
});
})
}
}

@ -3,34 +3,23 @@ import DoubanAbstractLoadHandler from 'src/douban/data/handler/DoubanAbstractLoa
import DoubanNoteSubject from '../model/DoubanPageBroadcastSubject';
import DoubanPageBroadcastSubject from '../model/DoubanPageBroadcastSubject';
import DoubanPlugin from "main";
import {DoubanPluginSettings} from "src/douban/Douban";
import DoubanSubject from 'src/douban/data/model/DoubanSubject';
import HandleContext from "@App/data/model/HandleContext";
import {TemplateKey} from "../../../constant/Constsant";
//TODO will support in future version
export default class DoubanPageBroadcatLoadHandler extends DoubanAbstractLoadHandler<DoubanPageBroadcastSubject> {
class DoubanPageBroadcatLoadHandler extends DoubanAbstractLoadHandler<DoubanPageBroadcastSubject> {
constructor(doubanPlugin: DoubanPlugin) {
super(doubanPlugin);
}
getTemplate(settings: DoubanPluginSettings): string {
return settings.bookTemplate;
getTemplateKey(context: HandleContext): TemplateKey {
return null;
}
parseText(beforeContent: string, extract: DoubanNoteSubject, settings: DoubanPluginSettings): string {
return settings.bookTemplate ? null : "";
// settings.noteTemplate
// .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("{{timePublished}}", extract.timePublished ? moment(extract.timePublished).format(settings.dateTimeFormat) : "")
// .replaceAll("{{url}}", extract.url ? extract.url : "")
// .replaceAll("{{content}}", extract.content ? extract.content : "")
// .replaceAll("{{url}}", extract.url ? extract.url : "")
// .replaceAll("{{authorUrl}}", extract.authorUrl ? extract.authorUrl : "")
// .replaceAll("{{author}}", extract.author ? extract.author : "")
parseText(beforeContent: string, extract: DoubanNoteSubject, context: HandleContext): string {
return null;
}
support(extract: DoubanSubject): boolean {
@ -38,37 +27,6 @@ export default class DoubanPageBroadcatLoadHandler extends DoubanAbstractLoadHan
}
parseSubjectFromHtml(html: CheerioAPI): DoubanPageBroadcastSubject {
// return html('.new-status .status-wrapper')
// .get()
// .map(i -> {
// let div = html(i);
// div.find('')
// });
let title = html(html("head > 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 authorA = html(html("a.note-author").get(0));
let timePublished = html(html(".pub-date").get(0)).text();
let content = html(html(".note").get(1));
let idPattern = /(\d){5,10}/g;
let id = idPattern.exec(url);
// const result:DoubanNoteSubject = {
// image: image,
// timePublished: timePublished ? new Date(timePublished) : null,
// content: content ? html2markdown(content.toString()): "",
// id: id ? id[0] : "",
// type: "Article",
// title: title,
// desc: desc,
// url: url,
// author: authorA ? authorA.text() : null,
// authorUrl: authorA ? authorA.attr("href") : null,
// };
// return result;
return null;
}

@ -1,14 +1,17 @@
import {DoubanPluginSettings} from "src/douban/Douban";
import DoubanPlugin from "main";
import DoubanSubject, {DoubanParameter} from '../model/DoubanSubject';
import DoubanSubjectLoadHandler from "./DoubanSubjectLoadHandler";
import {Editor, moment, request, RequestUrlParam} from "obsidian";
import {moment, request, RequestUrlParam, TFile} 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";
import {BasicConst, PersonNameMode, SearchHandleMode, TemplateKey, TemplateTextMode} from "../../../constant/Constsant";
import HandleContext from "@App/data/model/HandleContext";
import HandleResult from "@App/data/model/HandleResult";
import {DEFAULT_TEMPLATE_CONTENT} from "../../../constant/DefaultTemplateContent";
import FileHandler from "../../../file/FileHandler";
export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject> implements DoubanSubjectLoadHandler<T> {
@ -19,30 +22,37 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
this.doubanPlugin = doubanPlugin;
}
parse(extract: T, settings: DoubanPluginSettings): string {
let template: string = this.getTemplate(settings);
async parse(extract: T, context: HandleContext): Promise<HandleResult> {
let template: string = await this.getTemplate(context);
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 = '';
let result: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);
frontMatterBefore = this.parsePartText(frontMatterBefore, extract, context);
}
if (frontMatterAfter.length > 0) {
frontMatterAfter = this.parsePartText(frontMatterAfter, extract, settings);
frontMatterAfter = this.parsePartText(frontMatterAfter, extract, context);
}
if (frontMatter.length > 0) {
frontMatter = this.parsePartText(frontMatter, extract, settings, TemplateTextMode.YAML);
frontMatter = this.parsePartText(frontMatter, extract, context, TemplateTextMode.YAML);
}
return frontMatterBefore + frontMatter + frontMatterAfter;
result = frontMatterBefore + frontMatter + frontMatterAfter;
} else {
return this.parsePartText(template, extract, settings);
result = this.parsePartText(template, extract, context);
}
let fileName:string = '';
if (SearchHandleMode.FOR_CREATE == context.mode) {
fileName = this.parsePartText(template, extract, context);
}
return {content: result, fileName: fileName};
}
/**
@ -66,14 +76,14 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
* @param settings
* @param textMode
*/
handleContentArray(array: any[], settings: DoubanPluginSettings, textMode: TemplateTextMode): string {
handleContentArray(array: any[], context: HandleContext, textMode: TemplateTextMode): string {
let result;
switch (textMode) {
case TemplateTextMode.YAML:
result = array.map(YamlUtil.handleText).join(', ');
break;
default:
result = array.join(settings.arraySpilt);
result = array.join(context.settings.arraySpilt);
}
return result;
}
@ -84,10 +94,10 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
* @param textMode
* @param settings
*/
handleSpecialContent(value: any, textMode: TemplateTextMode = TemplateTextMode.NORMAL, settings: DoubanPluginSettings = null): string {
handleSpecialContent(value: any, textMode: TemplateTextMode = TemplateTextMode.NORMAL, context: HandleContext = null): string {
let result;
if (value instanceof Array) {
result = this.handleContentArray(value, settings, textMode);
result = this.handleContentArray(value, context, textMode);
} else if (value instanceof Number) {
result = value ? value.toString() : '';
} else {
@ -96,13 +106,13 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
return result;
}
abstract getTemplate(settings: DoubanPluginSettings): string;
abstract getTemplateKey(context: HandleContext): TemplateKey;
abstract parseText(beforeContent: string, extract: T, settings: DoubanPluginSettings, textMode: TemplateTextMode): string;
abstract parseText(beforeContent: string, extract: T, context: HandleContext, textMode: TemplateTextMode): string;
abstract support(extract: DoubanSubject): boolean;
handle(url: string, editor: Editor): void {
handle(url: string, context: HandleContext): void {
const requestUrlParam: RequestUrlParam = {
url: url,
method: "GET",
@ -112,7 +122,7 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
request(requestUrlParam)
.then(load)
.then(this.parseSubjectFromHtml)
.then(content => this.toEditor(editor, content))
.then(content => this.toEditor(context, content))
// .then(content => content ? editor.replaceSelection(content) : content)
.catch(e => log.error(i18nHelper.getMessage('130101')))
;
@ -121,12 +131,13 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
abstract parseSubjectFromHtml(data: CheerioAPI): T | undefined;
toEditor(editor: Editor, extract: T): T {
this.doubanPlugin.putToEditor(editor, extract);
toEditor(context: HandleContext, extract: T): T {
this.doubanPlugin.putToObsidian(context, extract);
return extract;
}
getPersonName(name: string, settings: DoubanPluginSettings): string {
getPersonName(name: string, context: HandleContext): string {
const {settings} = context;
if (!name || !settings || !settings.personNameMode) {
return "";
}
@ -173,7 +184,7 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
return s;
}
private parsePartText(template: string, extract: T, settings: DoubanPluginSettings, textMode: TemplateTextMode = TemplateTextMode.NORMAL): string {
private parsePartText(template: string, extract: T, context: HandleContext, textMode: TemplateTextMode = TemplateTextMode.NORMAL): string {
const resultContent = template
.replaceAll(DoubanParameter.ID, extract.id)
.replaceAll(DoubanParameter.TITLE, this.handleSpecialContent(extract.title, textMode))
@ -183,11 +194,29 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
.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))
.replaceAll(DoubanParameter.DATE_PUBLISHED, extract.datePublished ? moment(extract.datePublished).format(context.settings.dateFormat) : '')
.replaceAll(DoubanParameter.TIME_PUBLISHED, extract.datePublished ? moment(extract.datePublished).format(context.settings.timeFormat) : '')
.replaceAll(DoubanParameter.CURRENT_DATE, moment(new Date()).format(context.settings.dateFormat))
.replaceAll(DoubanParameter.CURRENT_TIME, moment(new Date()).format(context.settings.timeFormat))
.replaceAll(DoubanParameter.GENRE, this.handleSpecialContent(extract.genre, textMode, context))
;
return this.parseText(resultContent, extract, settings, textMode);
return this.parseText(resultContent, extract, context, textMode);
}
private async getTemplate(context: HandleContext):Promise<string> {
const tempKey:TemplateKey = this.getTemplateKey(context);
const templatePath:string = context.settings[tempKey];
let firstLinkpathDest:TFile = this.doubanPlugin.app.metadataCache.getFirstLinkpathDest(templatePath, '');
// @ts-ignore
const defaultContent = DEFAULT_TEMPLATE_CONTENT[tempKey + 'Content'];
if (!firstLinkpathDest) {
return defaultContent;
}else {
// return firstLinkpathDest.
const val = await new FileHandler(this.doubanPlugin.app).getFileContent(firstLinkpathDest.path);
return val?val:defaultContent;
}
}
}

@ -2,10 +2,10 @@ import {CheerioAPI} from 'cheerio';
import DoubanAbstractLoadHandler from "./DoubanAbstractLoadHandler";
import DoubanBookSubject, {DoubanBookParameter} from "../model/DoubanBookSubject";
import DoubanPlugin from "main";
import {DEFAULT_SETTINGS, DoubanPluginSettings} from "src/douban/Douban";
import DoubanSubject from "../model/DoubanSubject";
import {TemplateTextMode} from "../../../constant/Constsant";
import {TemplateKey, TemplateTextMode} from "../../../constant/Constsant";
import StringUtil from "../../../utils/StringUtil";
import HandleContext from "@App/data/model/HandleContext";
export default class DoubanBookLoadHandler extends DoubanAbstractLoadHandler<DoubanBookSubject> {
@ -13,16 +13,16 @@ export default class DoubanBookLoadHandler extends DoubanAbstractLoadHandler<Dou
super(doubanPlugin);
}
getTemplate(settings: DoubanPluginSettings): string {
return StringUtil.defaultIfBlank(settings.bookTemplate, DEFAULT_SETTINGS.bookTemplate);
getTemplateKey(context: HandleContext): TemplateKey {
return TemplateKey.bookTemplate;
}
parseText(beforeContent: string, extract: DoubanBookSubject, settings: DoubanPluginSettings, textMode: TemplateTextMode): string {
parseText(beforeContent: string, extract: DoubanBookSubject, context: HandleContext, textMode: TemplateTextMode): string {
return beforeContent
.replaceAll(DoubanBookParameter.author,
super.handleSpecialContent(
extract.author.map(this.handleSpecialAuthorName), textMode, settings))
.replaceAll(DoubanBookParameter.translator, super.handleSpecialContent(extract.translator, textMode, settings))
extract.author.map(this.handleSpecialAuthorName), textMode, context))
.replaceAll(DoubanBookParameter.translator, super.handleSpecialContent(extract.translator, textMode, context))
.replaceAll(DoubanBookParameter.isbn, extract.isbn)
.replaceAll(DoubanBookParameter.originalTitle, super.handleSpecialContent(extract.originalTitle, textMode))
.replaceAll(DoubanBookParameter.subTitle, super.handleSpecialContent(extract.subTitle, textMode))

@ -1,10 +1,11 @@
import {CheerioAPI} from 'cheerio';
import DoubanAbstractLoadHandler from "./DoubanAbstractLoadHandler";
import DoubanPlugin from "main";
import {DEFAULT_SETTINGS, DoubanPluginSettings} from "src/douban/Douban";
import DoubanSubject from '../model/DoubanSubject';
import DoubanGameSubject from '../model/DoubanGameSubject';
import StringUtil from "../../../utils/StringUtil";
import HandleContext from "@App/data/model/HandleContext";
import {TemplateKey} from "../../../constant/Constsant";
export default class DoubanGameLoadHandler extends DoubanAbstractLoadHandler<DoubanGameSubject> {
@ -12,16 +13,12 @@ export default class DoubanGameLoadHandler extends DoubanAbstractLoadHandler<Dou
super(doubanPlugin);
}
// parse(extract: DoubanGameSubject, settings: DoubanPluginSettings): string {
// extract.title = this.handleI18nName(extract.title, settings);
// return super.parse(extract, settings);
// }
getTemplate(settings: DoubanPluginSettings): string {
return StringUtil.defaultIfBlank(settings.gameTemplate, DEFAULT_SETTINGS.gameTemplate);
getTemplateKey(context: HandleContext): TemplateKey {
return TemplateKey.gameTemplate;
}
parseText(beforeContent: string, extract: DoubanGameSubject, settings: DoubanPluginSettings): string {
parseText(beforeContent: string, extract: DoubanGameSubject, context: HandleContext): string {
const {settings} = context;
return beforeContent
.replaceAll("{{platform}}", extract.platform ? extract.platform.join(settings.arraySpilt) : "")
.replaceAll("{{aliases}}", extract.aliases ? extract.aliases.join(settings.arraySpilt) : "")

@ -1,11 +1,12 @@
import {CheerioAPI} from 'cheerio';
import DoubanAbstractLoadHandler from "./DoubanAbstractLoadHandler";
import DoubanPlugin from "main";
import {DEFAULT_SETTINGS, DoubanPluginSettings} from "src/douban/Douban";
import SchemaOrg from "src/utils/SchemaOrg";
import DoubanSubject from '../model/DoubanSubject';
import DoubanMovieSubject from '../model/DoubanMovieSubject';
import StringUtil from "../../../utils/StringUtil";
import HandleContext from "@App/data/model/HandleContext";
import {TemplateKey} from "../../../constant/Constsant";
export default class DoubanMovieLoadHandler extends DoubanAbstractLoadHandler<DoubanMovieSubject> {
@ -13,16 +14,17 @@ export default class DoubanMovieLoadHandler extends DoubanAbstractLoadHandler<Do
super(doubanPlugin);
}
getTemplate(settings: DoubanPluginSettings): string {
return StringUtil.defaultIfBlank(settings.movieTemplate, DEFAULT_SETTINGS.movieTemplate);
getTemplateKey(context: HandleContext): TemplateKey {
return TemplateKey.movieTemplate;
}
parseText(beforeContent: string, extract: DoubanMovieSubject, settings: DoubanPluginSettings): string {
parseText(beforeContent: string, extract: DoubanMovieSubject, context: HandleContext): string {
const {settings} = context;
return beforeContent
.replaceAll("{{originalTitle}}", extract.originalTitle ? extract.originalTitle : "")
.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("{{director}}", extract.director ? extract.director.map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, context)).filter(c => c).join(settings.arraySpilt) : "")
.replaceAll("{{actor}}", extract.actor ? extract.actor.map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, context)).filter(c => c).join(settings.arraySpilt) : "")
.replaceAll("{{author}}", extract.author ? extract.author.map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, context)).filter(c => c).join(settings.arraySpilt) : "")
;
}

@ -2,9 +2,9 @@ import {CheerioAPI} from 'cheerio';
import DoubanAbstractLoadHandler from "./DoubanAbstractLoadHandler";
import DoubanMusicSubject from '../model/DoubanMusicSubject';
import DoubanPlugin from "main";
import {DEFAULT_SETTINGS, DoubanPluginSettings} from "src/douban/Douban";
import DoubanSubject from '../model/DoubanSubject';
import StringUtil from "../../../utils/StringUtil";
import HandleContext from "@App/data/model/HandleContext";
import {TemplateKey} from "../../../constant/Constsant";
export default class DoubanMusicLoadHandler extends DoubanAbstractLoadHandler<DoubanMusicSubject> {
@ -12,11 +12,12 @@ export default class DoubanMusicLoadHandler extends DoubanAbstractLoadHandler<Do
super(doubanPlugin);
}
getTemplate(settings: DoubanPluginSettings): string {
return StringUtil.defaultIfBlank(settings.musicTemplate, DEFAULT_SETTINGS.musicTemplate);
getTemplateKey(context: HandleContext): TemplateKey {
return TemplateKey.musicTemplate;
}
parseText(beforeContent: string, extract: DoubanMusicSubject, settings: DoubanPluginSettings): string {
parseText(beforeContent: string, extract: DoubanMusicSubject, context: HandleContext): string {
const {settings} = context;
return beforeContent
.replaceAll("{{actor}}", extract.actor ? extract.actor.join(settings.arraySpilt) : "")
.replaceAll("{{barcode}}", extract.barcode ? extract.barcode : "")
@ -43,7 +44,7 @@ export default class DoubanMusicLoadHandler extends DoubanAbstractLoadHandler<Do
publish.map((index, info) => {
let key = html(info).text().trim();
let value = ''
let value = '';
if (key.indexOf('表演者') >= 0) {
// value = html(info.next.next).text().trim();
let vas: string[] = key.split("\n \n ");

@ -2,10 +2,10 @@ import {CheerioAPI} from 'cheerio';
import DoubanAbstractLoadHandler from "./DoubanAbstractLoadHandler";
import DoubanNoteSubject from '../model/DoubanNoteSubject';
import DoubanPlugin from "main";
import {DEFAULT_SETTINGS, DoubanPluginSettings} from "src/douban/Douban";
import DoubanSubject from '../model/DoubanSubject';
import html2markdown from '@notable/html2markdown';
import StringUtil from "../../../utils/StringUtil";
import HandleContext from "@App/data/model/HandleContext";
import {TemplateKey} from "../../../constant/Constsant";
export default class DoubanNoteLoadHandler extends DoubanAbstractLoadHandler<DoubanNoteSubject> {
@ -13,11 +13,11 @@ export default class DoubanNoteLoadHandler extends DoubanAbstractLoadHandler<Dou
super(doubanPlugin);
}
getTemplate(settings: DoubanPluginSettings): string {
return StringUtil.defaultIfBlank(settings.noteTemplate, DEFAULT_SETTINGS.noteTemplate);
getTemplateKey(context: HandleContext): TemplateKey {
return TemplateKey.noteTemplate;
}
parseText(beforeContent: string, extract: DoubanNoteSubject, settings: DoubanPluginSettings): string {
parseText(beforeContent: string, extract: DoubanNoteSubject, context: HandleContext): string {
return beforeContent
.replaceAll("{{authorUrl}}", extract.authorUrl ? extract.authorUrl : "")
.replaceAll("{{content}}", extract.content ? extract.content : "")

@ -1,19 +1,20 @@
import {CheerioAPI} from "cheerio";
import DoubanAbstractLoadHandler from "./DoubanAbstractLoadHandler";
import {DoubanPluginSettings} from "src/douban/Douban";
import DoubanSubject from "../model/DoubanSubject";
import {i18nHelper} from "src/lang/helper";
import {log} from "src/utils/Logutil";
import HandleContext from "@App/data/model/HandleContext";
import {TemplateKey} from "../../../constant/Constsant";
/**
*
*/
export default class DoubanOtherLoadHandler extends DoubanAbstractLoadHandler<DoubanSubject> {
getTemplate(settings: DoubanPluginSettings): string {
return "";
getTemplateKey(context: HandleContext): TemplateKey {
return TemplateKey.bookTemplate
}
parseText(beforeContent: string, extract: DoubanSubject, settings: DoubanPluginSettings): string {
parseText(beforeContent: string, extract: DoubanSubject, context: HandleContext): string {
log.warn(i18nHelper.getMessage('140101'));
return "";
}

@ -1,4 +1,4 @@
import {App, Editor} from "obsidian";
import {App} from "obsidian";
import DoubanBookLoadHandler from "./DoubanBookLoadHandler";
import DoubanMovieLoadHandler from "./DoubanMovieLoadHandler";
@ -6,11 +6,12 @@ import DoubanMusicLoadHandler from "./DoubanMusicLoadHandler";
import DoubanNoteLoadHandler from "./DoubanNoteLoadHandler";
import DoubanOtherLoadHandler from "./DoubanOtherLoadHandler";
import DoubanPlugin from "main";
import {DoubanPluginSettings} from "src/douban/Douban";
import DoubanSubject from "../model/DoubanSubject";
import DoubanSubjectLoadHandler from "./DoubanSubjectLoadHandler";
import {DoubanTeleplayLoadHandler} from "./DoubanTeleplayLoadHandler";
import DoubanGameLoadHandler from "./DoubanGameLoadHandler";
import HandleContext from "@App/data/model/HandleContext";
import HandleResult from "@App/data/model/HandleResult";
export class DoubanSearchChooseItemHandler {
@ -33,34 +34,32 @@ export class DoubanSearchChooseItemHandler {
this._doubanSubjectHandlerDefault];
}
public handle(searchExtract: DoubanSubject, editor: Editor): void {
public handle(searchExtract: DoubanSubject, context: HandleContext): void {
if (!searchExtract) {
return;
}
let doubanSubjectHandlers: DoubanSubjectLoadHandler<DoubanSubject>[] = this._doubanSubjectHandlers
.filter(h => h.support(searchExtract));
if (doubanSubjectHandlers && doubanSubjectHandlers.length > 0) {
doubanSubjectHandlers[0].handle(searchExtract.url, editor);
doubanSubjectHandlers[0].handle(searchExtract.url, context);
} else {
this._doubanSubjectHandlerDefault.handle(searchExtract.url, editor);
this._doubanSubjectHandlerDefault.handle(searchExtract.url, context);
}
}
public parseText(extract: DoubanSubject, settings: DoubanPluginSettings): string {
if (!settings) {
return "";
}
public async parseText(extract: DoubanSubject, context: HandleContext): Promise<HandleResult> {
let doubanSubjectHandlers: DoubanSubjectLoadHandler<DoubanSubject>[] = this._doubanSubjectHandlers
.filter(h => h.support(extract));
let result:string='';
if (doubanSubjectHandlers && doubanSubjectHandlers.length > 0) {
let result = doubanSubjectHandlers.map(h => h.parse(extract, settings));
let result = await doubanSubjectHandlers.map(h => h.parse(extract, context));
if (result && result.length > 0) {
return result[0];
} else {
return "";
return {content: ''};
}
} else {
return this._doubanSubjectHandlerDefault.parse(extract, settings);
return this._doubanSubjectHandlerDefault.parse(extract, context);
}
}

@ -1,14 +1,14 @@
import {DoubanPluginSettings} from "src/douban/Douban";
import DoubanSubject from "../model/DoubanSubject";
import {Editor} from "obsidian";
import HandleContext from "@App/data/model/HandleContext";
import HandleResult from "@App/data/model/HandleResult";
export default interface DoubanSubjectLoadHandler<T extends DoubanSubject> {
parse(extract: T, settings: DoubanPluginSettings): string;
parse(extract: T, context: HandleContext): Promise<HandleResult>;
support(extract: DoubanSubject): boolean;
handle(url: string, editor: Editor): void;
handle(url: string, context: HandleContext): void;
}

@ -1,11 +1,11 @@
import {CheerioAPI} from "cheerio";
import DoubanAbstractLoadHandler from "./DoubanAbstractLoadHandler";
import DoubanPlugin from "main";
import {DEFAULT_SETTINGS, DoubanPluginSettings} from "src/douban/Douban";
import DoubanSubject from "../model/DoubanSubject";
import DoubanTeleplaySubject from "../model/DoubanTeleplaySubject";
import SchemaOrg from "src/utils/SchemaOrg";
import StringUtil from "../../../utils/StringUtil";
import HandleContext from "@App/data/model/HandleContext";
import {TemplateKey} from "../../../constant/Constsant";
/**
* teleplay
@ -16,16 +16,17 @@ export class DoubanTeleplayLoadHandler extends DoubanAbstractLoadHandler<DoubanT
super(doubanPlugin);
}
getTemplate(settings: DoubanPluginSettings): string {
return StringUtil.defaultIfBlank(settings.movieTemplate, DEFAULT_SETTINGS.movieTemplate);
getTemplateKey(context: HandleContext): TemplateKey {
return TemplateKey.teleplayTemplate
}
parseText(beforeContent: string, extract: DoubanTeleplaySubject, settings: DoubanPluginSettings): string {
parseText(beforeContent: string, extract: DoubanTeleplaySubject, context: HandleContext): string {
const {settings} = context;
return beforeContent
.replaceAll("{{originalTitle}}", extract.originalTitle ? extract.originalTitle : "")
.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("{{director}}", extract.director ? extract.director.map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, context)).filter(c => c).join(settings.arraySpilt) : "")
.replaceAll("{{actor}}", extract.actor ? extract.actor.map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, context)).filter(c => c).join(settings.arraySpilt) : "")
.replaceAll("{{author}}", extract.author ? extract.author.map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, context)).filter(c => c).join(settings.arraySpilt) : "")
}
support(extract: DoubanSubject): boolean {

@ -27,4 +27,6 @@ export const DoubanParameter = {
DATE_PUBLISHED: '{{datePublished}}',
TIME_PUBLISHED: '{{timePublished}}',
GENRE: '{{genre}}',
CURRENT_DATE: '{{currentDate}}',
CURRENT_TIME: '{{currentTime}}',
}

@ -0,0 +1,9 @@
import {SearchHandleMode} from "../../../constant/Constsant";
import {Editor} from "obsidian";
import { DoubanPluginSetting } from "@App/setting/model/DoubanPluginSetting";
export default interface HandleContext {
mode:SearchHandleMode;
settings: DoubanPluginSetting;
editor?:Editor;
}

@ -0,0 +1,4 @@
export default interface HandleResult {
content:string
fileName?:string
}

@ -1,25 +1,25 @@
import {Editor, FuzzySuggestModal} from "obsidian";
import {FuzzySuggestModal} from "obsidian";
import DoubanPlugin from "main";
import DoubanSearchResultSubject from "../model/DoubanSearchResultSubject";
import {log} from "src/utils/Logutil";
import {i18nHelper} from "../../../lang/helper";
import HandleContext from "@App/data/model/HandleContext";
export {DoubanFuzzySuggester}
class DoubanFuzzySuggester extends FuzzySuggestModal<DoubanSearchResultSubject> {
public editor: Editor;
private plugin: DoubanPlugin;
private doubanSearchResultExtract: DoubanSearchResultSubject[]
private doubanSearchResultExtract: DoubanSearchResultSubject[];
private context: HandleContext;
constructor(plugin: DoubanPlugin, editor: Editor) {
constructor(plugin: DoubanPlugin, context: HandleContext) {
super(app);
this.editor = editor;
this.plugin = plugin;
this.context = context;
this.setPlaceholder(i18nHelper.getMessage('150101'));
}
@ -34,7 +34,7 @@ class DoubanFuzzySuggester extends FuzzySuggestModal<DoubanSearchResultSubject>
onChooseItem(item: DoubanSearchResultSubject, evt: MouseEvent | KeyboardEvent): void {
this.plugin.showStatus('140204', item.title);
this.plugin.doubanExtractHandler.handle(item, this.editor);
this.plugin.doubanExtractHandler.handle(item, this.context);
}
public showSearchList(doubanSearchResultExtractList: DoubanSearchResultSubject[]) {

@ -1,17 +1,18 @@
import {App, Editor, Modal, TextComponent} from "obsidian";
import {App, Modal, TextComponent} from "obsidian";
import DoubanPlugin from "main";
import {i18nHelper} from "src/lang/helper";
import HandleContext from "@App/data/model/HandleContext";
export class DoubanSearchModal extends Modal {
searchTerm: string;
plugin: DoubanPlugin;
editor: Editor;
context: HandleContext
constructor(app: App, plugin: DoubanPlugin, editor: Editor) {
constructor(app: App, plugin: DoubanPlugin, context: HandleContext) {
super(app);
this.plugin = plugin;
this.editor = editor;
this.context = context;
}
onOpen() {
@ -55,7 +56,7 @@ export class DoubanSearchModal extends Modal {
let {contentEl} = this;
contentEl.empty();
if (this.searchTerm) {
await this.plugin.search(this.searchTerm, this.editor);
await this.plugin.search(this.searchTerm, this.context);
}
}

@ -1,4 +1,3 @@
import {DoubanPluginSettings} from 'src/douban/Douban';
import DoubanSearchResultSubject from '../model/DoubanSearchResultSubject';
import SearchParserHandler from './SearchParser';
@ -6,9 +5,10 @@ import {log} from 'src/utils/Logutil';
import {request, RequestUrlParam} from "obsidian";
import {i18nHelper} from "../../../lang/helper";
import {load} from 'cheerio';
import {DoubanPluginSetting} from "@App/setting/model/DoubanPluginSetting";
export default class Searcher {
static search(searchItem: string, doubanSettings: DoubanPluginSettings): Promise<DoubanSearchResultSubject[]> {
static search(searchItem: string, doubanSettings: DoubanPluginSetting): Promise<DoubanSearchResultSubject[]> {
let requestUrlParam: RequestUrlParam = {
url: doubanSettings.searchUrl + searchItem,
method: "GET",

@ -0,0 +1,186 @@
import {App, PluginSettingTab, SearchComponent, Setting} from "obsidian";
import DoubanPlugin from "main";
import {i18nHelper} from "src/lang/helper";
import {PersonNameMode, PersonNameModeRecords} from "../../constant/Constsant";
import SettingsManager from "@App/setting/SettingsManager";
import {FolderSuggest} from "@App/setting/model/FolderSuggest";
import { DEFAULT_SETTINGS } from "src/constant/DefaultSettings";
/**
*
* obsidian-kanban
*/
export class DoubanSettingTab extends PluginSettingTab {
plugin: DoubanPlugin;
settingsManager: SettingsManager;
constructor(app: App, plugin: DoubanPlugin) {
super(app, plugin);
this.plugin = plugin;
this.settingsManager = new SettingsManager(app, plugin);
}
display(): void {
const {containerEl} = this;
containerEl.empty();
containerEl.createEl("h2", {text: 'Obsidian Douban'});
new Setting(containerEl).setName(i18nHelper.getMessage('120001'))
.then((setting) => {
setting.addText((textField) => {
setting.descEl.appendChild(
createFragment((frag) => {
frag.appendText(i18nHelper.getMessage('120002'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120003'));
frag.createEl(
'a',
{
text: i18nHelper.getMessage('120901'),
href: 'https://www.douban.com',
},
(a) => {
a.setAttr('target', '_blank');
}
);
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120004'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120005'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120006'));
frag.createEl('br');
})
);
textField.inputEl.addClass("obsidian_douban_settings_textField");
textField
.setPlaceholder(DEFAULT_SETTINGS.searchUrl)
.setValue(this.plugin.settings.searchUrl)
.onChange(async (value) => {
this.plugin.settings.searchUrl = value;
await this.plugin.saveSettings();
});
});
});
new Setting(containerEl).setName(i18nHelper.getMessage('120501')).then((setting) => {
setting.addMomentFormat((mf) => {
setting.descEl.appendChild(
createFragment((frag) => {
frag.appendText(
i18nHelper.getMessage('120503')
);
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120506') + ' ');
frag.createEl(
'a',
{
text: i18nHelper.getMessage('120508'),
href: 'https://momentjs.com/docs/#/displaying/format/',
},
(a) => {
a.setAttr('target', '_blank');
}
);
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120507') + ': ');
mf.setSampleEl(frag.createEl('b', {cls: 'u-pop'}));
frag.createEl('br');
})
);
mf.setPlaceholder(DEFAULT_SETTINGS.dateFormat);
mf.setValue(this.plugin.settings.dateFormat)
mf.onChange(async (value) => {
this.plugin.settings.dateFormat = value;
await this.plugin.saveSettings();
});
});
});
new Setting(containerEl).setName(i18nHelper.getMessage('120502')).then((setting) => {
setting.addMomentFormat((mf) => {
setting.descEl.appendChild(
createFragment((frag) => {
frag.appendText(
i18nHelper.getMessage('120504')
);
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120506') + ' ');
frag.createEl(
'a',
{
text: i18nHelper.getMessage('120508'),
href: 'https://momentjs.com/docs/#/displaying/format/',
},
(a) => {
a.setAttr('target', '_blank');
}
);
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('120507') + ': ');
mf.setSampleEl(frag.createEl('b', {cls: 'u-pop'}));
frag.createEl('br');
})
);
mf.setPlaceholder(DEFAULT_SETTINGS.timeFormat);
mf.setValue(this.plugin.settings.timeFormat)
mf.onChange(async (value) => {
this.plugin.settings.timeFormat = value;
await this.plugin.saveSettings();
});
});
});
new Setting(containerEl)
.setName(i18nHelper.getMessage('120601'))
.setDesc(i18nHelper.getMessage('120602'))
.addText((textField) => {
textField.setPlaceholder(DEFAULT_SETTINGS.arraySpilt)
.setValue(this.plugin.settings.arraySpilt)
.onChange(async (value) => {
this.plugin.settings.arraySpilt = value;
await this.plugin.saveSettings();
});
});
this.settingsManager.constructUI(containerEl);
new Setting(containerEl).setName(i18nHelper.getMessage('121201')).then((setting) => {
setting.addDropdown((dropdwon) => {
setting.descEl.appendChild(
createFragment((frag) => {
frag.appendText(i18nHelper.getMessage('121202'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('121203'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('121204'));
frag.createEl('br');
frag.appendText(i18nHelper.getMessage('121205'));
frag.createEl('br');
})
);
// 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.setValue(this.plugin.settings.personNameMode)
.onChange(async (value: string) => {
this.plugin.settings.personNameMode = value as PersonNameMode;
await this.plugin.saveSettings();
});
});
});
}
}

@ -0,0 +1,61 @@
import {i18nHelper} from "../../lang/helper";
import {CreateTemplateSelectParams} from "@App/setting/model/CreateTemplateSelectParams";
import { FileSuggest } from "./model/FileSuggest";
import {SearchComponent, Setting} from "obsidian";
export function createFileSelectionSetting({
name, desc, placeholder, key, manager,
}: CreateTemplateSelectParams) {
return (setting: Setting) => {
// @ts-ignore
setting.setName( i18nHelper.getMessage(name));
// @ts-ignore
setting.setDesc( i18nHelper.getMessage(desc));
setting.addSearch(async (search: SearchComponent) => {
const [oldValue, defaultVal] = manager.getSetting(key);
let v = defaultVal;
if (oldValue) {
v = oldValue;
}
new FileSuggest(manager.app, search.inputEl);
search.setValue(v);
// @ts-ignore
search.setPlaceholder(i18nHelper.getMessage());
search.onChange(async (value: string) => {
manager.updateSetting(key, value);
});
});
};
}
export function createFolderSelectionSetting({
name, desc, placeholder, key, manager,
}: CreateTemplateSelectParams) {
return (setting: Setting) => {
// @ts-ignore
setting.setName( i18nHelper.getMessage(name));
// @ts-ignore
setting.setDesc( i18nHelper.getMessage(desc));
setting.addSearch(async (search: SearchComponent) => {
const [oldValue, defaultVal] = manager.getSetting(key);
let v = defaultVal;
if (oldValue) {
v = oldValue;
}
new FileSuggest(manager.app, search.inputEl);
search
.setValue(v)
// @ts-ignore
.setPlaceholder(i18nHelper.getMessage(placeholder))
.onChange(async (value: string) => {
manager.updateSetting(key, value);
});
});
};
}

@ -0,0 +1,40 @@
import {App, Setting} from "obsidian";
import { DEFAULT_SETTINGS } from "src/constant/DefaultSettings";
import DoubanPlugin from "../../../main";
import { DoubanPluginSetting } from "./model/DoubanPluginSetting";
import {createFileSelectionSetting, createFolderSelectionSetting} from "@App/setting/SettingHelper";
export default class SettingsManager {
app: App;
plugin: DoubanPlugin;
settings: DoubanPluginSetting;
cleanupFns: Array<() => void> = [];
constructor(app: App, plugin: DoubanPlugin) {
this.app = app;
this.plugin = plugin;
this.settings = plugin.settings;
}
getSetting(key: keyof DoubanPluginSetting) {
return [this.settings[key], DEFAULT_SETTINGS[key]];
}
async updateSetting(key: keyof DoubanPluginSetting, value:any) {
this.settings[key] = value;
await this.plugin.saveSettings();
}
constructUI(contenterEl: HTMLElement) {
new Setting(contenterEl).then(createFileSelectionSetting({name: '120101', desc: '120102', placeholder: '121701', key: 'movieTemplateFile', manager: this}));
new Setting(contenterEl).then(createFileSelectionSetting({name: '120201', desc: '120202', placeholder: '121701', key: 'bookTemplateFile', manager: this}));
new Setting(contenterEl).then(createFileSelectionSetting({name: '120301', desc: '120302', placeholder: '121701', key: 'musicTemplateFile', manager: this}));
new Setting(contenterEl).then(createFileSelectionSetting({name: '120401', desc: '120402', placeholder: '121701', key: 'noteTemplateFile', manager: this}));
new Setting(contenterEl).then(createFileSelectionSetting({name: '121301', desc: '121302', placeholder: '121701', key: 'gameTemplateFile', manager: this}));
new Setting(contenterEl).then(createFileSelectionSetting({name: '121301', desc: '121302', placeholder: '121701', key: 'teleplayTemplateFile', manager: this}));
new Setting(contenterEl).then(createFolderSelectionSetting({name: '121301', desc: '121302', placeholder: '121701', key: 'dataFilePath', manager: this}));
}
}

@ -0,0 +1,11 @@
import SettingsManager from "@App/setting/SettingsManager";
import { DoubanPluginSetting } from "./DoubanPluginSetting";
export interface CreateTemplateSelectParams {
// @ts-ignore
name:string,
desc:string,
placeholder:string,
key: keyof DoubanPluginSetting;
manager: SettingsManager;
}

@ -0,0 +1,18 @@
export interface DoubanPluginSetting {
movieTemplateFile: string,
bookTemplateFile: string,
musicTemplateFile: string,
noteTemplateFile: string,
gameTemplateFile: string,
teleplayTemplateFile: string,
dateFormat: string,
timeFormat: string,
searchUrl: string,
arraySpilt: string,
searchHeaders?: string,
personNameMode: string,
dataFilePath: string,
dataFileNamePath: string,
}

@ -0,0 +1,33 @@
import {TAbstractFile, TFile, TFolder} from "obsidian";
import {TextInputSuggest} from "@App/setting/model/TextInputSuggest";
// Credits go to Liam's Periodic Notes Plugin: https://github.com/liamcain/obsidian-periodic-notes
export class FileSuggest extends TextInputSuggest<TFile> {
getSuggestions(inputStr: string): TFile[] {
const abstractFiles = this.app.vault.getAllLoadedFiles();
const files: TFile[] = [];
const lowerCaseInputStr = inputStr.toLowerCase();
abstractFiles.forEach((file: TAbstractFile) => {
if (
file instanceof TFile &&
file.extension === "md" &&
file.path.toLowerCase().contains(lowerCaseInputStr)
) {
files.push(file);
}
});
return files;
}
renderSuggestion(file: TFile, el: HTMLElement): void {
el.setText(file.path);
}
selectSuggestion(file: TFile): void {
this.inputEl.value = file.path;
this.inputEl.trigger("input");
this.close();
}
}

@ -0,0 +1,32 @@
import { TAbstractFile, TFolder } from "obsidian";
import {TextInputSuggest} from "@App/setting/model/TextInputSuggest";
// Credits go to Liam's Periodic Notes Plugin: https://github.com/liamcain/obsidian-periodic-notes
export class FolderSuggest extends TextInputSuggest<TFolder> {
getSuggestions(inputStr: string): TFolder[] {
const abstractFiles = this.app.vault.getAllLoadedFiles();
const folders: TFolder[] = [];
const lowerCaseInputStr = inputStr.toLowerCase();
abstractFiles.forEach((folder: TAbstractFile) => {
if (
folder instanceof TFolder &&
folder.path.toLowerCase().contains(lowerCaseInputStr)
) {
folders.push(folder);
}
});
return folders;
}
renderSuggestion(file: TFolder, el: HTMLElement): void {
el.setText(file.path);
}
selectSuggestion(file: TFolder): void {
this.inputEl.value = file.path;
this.inputEl.trigger("input");
this.close();
}
}

@ -0,0 +1,98 @@
import { App, ISuggestOwner, Scope } from "obsidian";
import { createPopper, Instance as PopperInstance } from "@popperjs/core";
const wrapAround = (value: number, size: number): number => {
return ((value % size) + size) % size;
};
export default class Suggest<T> {
private owner: ISuggestOwner<T>;
private values: T[];
private suggestions: HTMLDivElement[];
private selectedItem: number;
private containerEl: HTMLElement;
constructor(owner: ISuggestOwner<T>, containerEl: HTMLElement, scope: Scope) {
this.owner = owner;
this.containerEl = containerEl;
containerEl.on("click", ".suggestion-item", this.onSuggestionClick.bind(this));
containerEl.on(
"mousemove",
".suggestion-item",
this.onSuggestionMouseover.bind(this)
);
scope.register([], "ArrowUp", (event) => {
if (!event.isComposing) {
this.setSelectedItem(this.selectedItem - 1, true);
return false;
}
});
scope.register([], "ArrowDown", (event) => {
if (!event.isComposing) {
this.setSelectedItem(this.selectedItem + 1, true);
return false;
}
});
scope.register([], "Enter", (event) => {
if (!event.isComposing) {
this.useSelectedItem(event);
return false;
}
});
}
onSuggestionClick(event: MouseEvent, el: HTMLDivElement): void {
event.preventDefault();
const item = this.suggestions.indexOf(el);
this.setSelectedItem(item, false);
this.useSelectedItem(event);
}
onSuggestionMouseover(_event: MouseEvent, el: HTMLDivElement): void {
const item = this.suggestions.indexOf(el);
this.setSelectedItem(item, false);
}
setSuggestions(values: T[]) {
this.containerEl.empty();
const suggestionEls: HTMLDivElement[] = [];
values.forEach((value) => {
const suggestionEl = this.containerEl.createDiv("suggestion-item");
this.owner.renderSuggestion(value, suggestionEl);
suggestionEls.push(suggestionEl);
});
this.values = values;
this.suggestions = suggestionEls;
this.setSelectedItem(0, false);
}
useSelectedItem(event: MouseEvent | KeyboardEvent) {
const currentValue = this.values[this.selectedItem];
if (currentValue) {
this.owner.selectSuggestion(currentValue, event);
}
}
setSelectedItem(selectedIndex: number, scrollIntoView: boolean) {
const normalizedIndex = wrapAround(selectedIndex, this.suggestions.length);
const prevSelectedSuggestion = this.suggestions[this.selectedItem];
const selectedSuggestion = this.suggestions[normalizedIndex];
prevSelectedSuggestion?.removeClass("is-selected");
selectedSuggestion?.addClass("is-selected");
this.selectedItem = normalizedIndex;
if (scrollIntoView) {
selectedSuggestion.scrollIntoView(false);
}
}
}

@ -0,0 +1,89 @@
import {App, ISuggestOwner, Scope} from "obsidian";
import Suggest from "./Suggest";
import { createPopper, type Instance as PopperInstance } from "@popperjs/core";
// Credits go to Liam's Periodic Notes Plugin: https://github.com/liamcain/obsidian-periodic-notes
export abstract class TextInputSuggest<T> implements ISuggestOwner<T> {
protected app: App;
protected inputEl: HTMLInputElement;
private popper: PopperInstance;
private scope: Scope;
private suggestEl: HTMLElement;
private suggest: Suggest<T>;
constructor(app: App, inputEl: HTMLInputElement) {
this.app = app;
this.inputEl = inputEl;
this.scope = new Scope();
this.suggestEl = createDiv("suggestion-container");
const suggestion = this.suggestEl.createDiv("suggestion");
this.suggest = new Suggest(this, suggestion, this.scope);
this.scope.register([], "Escape", this.close.bind(this));
this.inputEl.addEventListener("input", this.onInputChanged.bind(this));
this.inputEl.addEventListener("focus", this.onInputChanged.bind(this));
this.inputEl.addEventListener("blur", this.close.bind(this));
this.suggestEl.on("mousedown", ".suggestion-container", (event: MouseEvent) => {
event.preventDefault();
});
}
onInputChanged(): void {
const inputStr = this.inputEl.value;
const suggestions = this.getSuggestions(inputStr);
if (suggestions.length > 0) {
this.suggest.setSuggestions(suggestions);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this.open((<any>this.app).dom.appContainerEl, this.inputEl);
}
}
open(container: HTMLElement, inputEl: HTMLElement): void {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(<any>this.app).keymap.pushScope(this.scope);
container.appendChild(this.suggestEl);
this.popper = createPopper(inputEl, this.suggestEl, {
placement: "bottom-start",
modifiers: [
{
name: "sameWidth",
enabled: true,
fn: ({ state, instance }) => {
// Note: positioning needs to be calculated twice -
// first pass - positioning it according to the width of the popper
// second pass - position it with the width bound to the reference element
// we need to early exit to avoid an infinite loop
const targetWidth = `${state.rects.reference.width}px`;
if (state.styles.popper.width === targetWidth) {
return;
}
state.styles.popper.width = targetWidth;
instance.update();
},
phase: "beforeWrite",
requires: ["computeStyles"],
},
],
});
}
close(): void {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(<any>this.app).keymap.popScope(this.scope);
this.suggest.setSuggestions([]);
this.popper.destroy();
this.suggestEl.detach();
}
abstract getSuggestions(inputStr: string): T[];
abstract renderSuggestion(item: T, el: HTMLElement): void;
abstract selectSuggestion(item: T): void;
}

133
src/file/FileHandler.ts Normal file

@ -0,0 +1,133 @@
import { DoubanPluginSetting } from "@App/setting/model/DoubanPluginSetting";
import {App, normalizePath, Platform} from "obsidian";
import { log } from "src/utils/Logutil";
import DoubanPlugin from "../../main";
import {FileUtil} from "../utils/FileUtil";
/**
*
* obsidian-advanced-new-file插件
* @auther: wanxuping
* @date: 2022/11/01 23:32
*/
export default class FileHandler {
private _app: App;
constructor(app:App) {
this._app = app;
}
/**
*
*/
/**
* Creates a directory (recursive) if it does not already exist.
* This is a helper function that includes a workaround for a bug in the
* Obsidian mobile app.
*/
private async createDirectory(dir: string): Promise<void> {
const {vault} = this._app;
const {adapter} = vault;
const root = vault.getRoot().path;
const directoryPath = FileUtil.join(dir);
const directoryExists = await adapter.exists(directoryPath);
// ===============================================================
// -> Desktop App
// ===============================================================
if (!Platform.isIosApp) {
if (!directoryExists) {
return adapter.mkdir(normalizePath(directoryPath));
}
}
// ===============================================================
// -> Mobile App (IOS)
// ===============================================================
// This is a workaround for a bug in the mobile app:
// To get the file explorer view to update correctly, we have to create
// each directory in the path one at time.
// Split the path into an array of sub paths
// Note: `normalizePath` converts path separators to '/' on all platforms
// @example '/one/two/three/' ==> ['one', 'one/two', 'one/two/three']
// @example 'one\two\three' ==> ['one', 'one/two', 'one/two/three']
const subPaths: string[] = normalizePath(directoryPath)
.split('/')
.filter((part) => part.trim() !== '')
.map((_, index, arr) => arr.slice(0, index + 1).join('/'));
// Create each directory if it does not exist
for (const subPath of subPaths) {
const directoryExists = await adapter.exists(FileUtil.join(root, subPath));
if (!directoryExists) {
await adapter.mkdir(FileUtil.join(root, subPath));
}
}
}
/**
* Handles creating the new note
* A new markdown file will be created at the given file path (`input`)
* in the specified parent folder (`this.folder`)
*/
async createNewNote(originalFilePath: string): Promise<void> {
this.createNewNoteWithData(originalFilePath, '');
}
/**
* Handles creating the new note
* A new markdown file will be created at the given file path (`input`)
* in the specified parent folder (`this.folder`)
*/
async createNewNoteWithData(originalFilePath: string, data:string): Promise<void> {
const {vault} = this._app;
const {adapter} = vault;
const prependDirInput = FileUtil.join("", originalFilePath);
const {dir, name} = FileUtil.parse(prependDirInput);
const filePath = FileUtil.join(dir, `${name}.md`);
try {
const fileExists = await adapter.exists(filePath);
if (fileExists) {
// If the file already exists, respond with error
throw new Error(`${filePath} already exists`);
}
if (dir !== '') {
// If `input` includes a directory part, create it
await this.createDirectory(dir);
}
const File = await vault.create(filePath, data);
// Create the file and open it in the active leaf
const leaf = this._app.workspace.splitLeafOrActive();
await leaf.openFile(File);
} catch (error) {
log.error(error.toString());
}
}
async getFileContent(filePath: string | undefined): Promise<string> {
const { metadataCache, vault } = this._app;
const normalizedTemplatePath = normalizePath(filePath ?? "");
if (filePath === "/") {
return Promise.resolve("");
}
try {
const file = metadataCache.getFirstLinkpathDest(normalizedTemplatePath, "");
return file ? vault.cachedRead(file) : "";
} catch (err) {
console.error(
`Failed to read the daily note template '${normalizedTemplatePath}'`,
err
);
//TODO i18n
log.error('Failed to read the template')
return "";
}
}
}

@ -32,7 +32,7 @@ export default {
'120131': `Create New File Name`,
'120201': `Book Content Template`,
'120201': `Book Template File`,
'120202': `Set markdown Book template for extract to be inserted.`,
'120203': `Available Book template variables are :`,
'120204': `{{id}}, {{title}}, {{type}}, {{score}}, {{image}},`,
@ -41,7 +41,7 @@ export default {
'120207': `{{translator}}, {{isbn}}, {{price}}, {{totalPage}}`,
'120208': `{{series}}, {{binding}}, {{menu}}`,
'120301': `Music Content Template`,
'120301': `Music Template File`,
'120302': `Set markdown Music template for extract to be inserted.`,
'120303': `Available Music template variables are :`,
'120304': `{{id}}, {{title}}, {{type}}, {{score}}, {{image}},`,
@ -49,7 +49,7 @@ export default {
'120306': `{{actor}}, {{medium}}, {{albumType}},`,
'120307': `{{barcode}}, {{records}}`,
'120401': `Article Content Template`,
'120401': `Article Template File`,
'120402': `Set markdown Article template for extract to be inserted.`,
'120403': `Available Article template variables are :`,
'120404': `{{id}}, {{title}}, {{type}}, {{image}},`,
@ -57,7 +57,7 @@ export default {
'120406': `{{author}}, {{authorUrl}}, {{content}}`,
'120407': `{{timePublished}}`,
'121301': `Game Content Template`,
'121301': `Game Template File`,
'121302': `Set markdown Game template for extract to be inserted.`,
'121303': `Available Game template variables are :`,
'121304': `{{id}}, {{title}}, {{type}}, {{score}}, {{image}},`,
@ -88,8 +88,20 @@ export default {
'121207': `English Name`,
'121208': `Chinese And English Name`,
'121401': `Status Bar`,
'121402': `Display status bar when import data ?`,
'121501': `Note folder`,
'121502': `Nodes created from Obsidian-Douban will be placed in this folder, If blank, they will be placed in the default location for this vault. `,
'121503': `Default Folder`,
'121601': `Note Name`,
'121602': `Nodes created from Obsidian-Douban will use this fileName(also support filePath), If blank, they will be created by default name. `,
'121701': `Input And Search Template`,
'121702': `Movie created from Obsidian-Douban will be placed in this folder, If blank, they will be placed in the default location for this vault. `,
'121703': `Default`,
//error
@ -110,4 +122,8 @@ export default {
//content
'200101': `. `,
'210101': `Default`,
'210201': `Search...`
}

@ -90,6 +90,15 @@ export default {
'121207': `英文名`,
'121208': `中文名和英文名`,
'121401': `状态栏`,
'121402': `当在导入数据时, 是否需要在状态栏显示处理状态? `,
'121501': `笔记存放位置`,
'121502': `从Obsidian-Douban创建的笔记将会存放导该文件夹中. 如果为空,笔记将会存放到Obsidian的默认文件存放位置`,
'121601': `笔记名称`,
'121602': `从Obsidian-Douban创建的笔记将会使用次名称,支持所有通用的参数作为名称(如:{{type}},{{title}}等等). 如果为空, 笔记将会使用默认名称`,
'130101': `获取数据失败,您如有需要请至Github提交Issues`,
'130102': `Obsidian Douban插件错误提示:`,
'130103': `Obsidian Douban插件异常提示:`,

55
src/utils/FileUtil.ts Normal file

@ -0,0 +1,55 @@
import {normalizePath} from "obsidian";
interface ParsedPath {
/**
* The full directory path such as '/home/user/dir' or 'folder/sub'
* */
dir: string;
/**
* The file name without extension
* */
name: string;
/**
* The file extension without the dot.
*/
extension:string;
}
export const FileUtil = {
/**
* Parses the file path into a directory and file name.
* If the path string does not include a file name, it will default to
* 'Untitled'.
*
* @example
* parse('/one/two/file name')
* // ==> { dir: '/one/two', name: 'file name' }
*
* parse('\\one\\two\\file name')
* // ==> { dir: '/one/two', name: 'file name' }
*
* parse('')
* // ==> { dir: '', name: 'Untitled' }
*
* parse('/one/two/')
* // ==> { dir: '/one/two/', name: 'Untitled' }
*/
parse(pathString: string): ParsedPath {
const regex = /(?<dir>([^/\\]+[/\\])*)(?<name>[^/\\]*$)/;
const match = String(pathString).match(regex);
const { dir, name } = match && match.groups;
return { dir, name: name || 'Untitled', extension: 'md'};
},
/**
* Joins multiple strings into a path using Obsidian's preferred format.
* The resulting path is normalized with Obsidian's `normalizePath` func.
* - Converts path separators to '/' on all platforms
* - Removes duplicate separators
* - Removes trailing slash
*/
join(...strings: string[]): string {
const parts = strings.map((s) => String(s).trim()).filter((s) => s != null);
return normalizePath(parts.join('/'));
},
};