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

163
main.ts

@ -1,112 +1,147 @@
import { DEFAULT_SETTINGS, DoubanPluginSettings } from "./src/douban/Douban"; import {Editor, Plugin} from "obsidian";
import { Editor, Plugin } from "obsidian";
import { DoubanFuzzySuggester } from "src/douban/data/search/DoubanSearchFuzzySuggestModal"; import {DoubanFuzzySuggester} from "src/douban/data/search/DoubanSearchFuzzySuggestModal";
import { DoubanSearchChooseItemHandler } from "src/douban/data/handler/DoubanSearchChooseItemHandler"; import {DoubanSearchChooseItemHandler} from "src/douban/data/handler/DoubanSearchChooseItemHandler";
import { DoubanSearchModal } from "src/douban/data/search/DoubanSearchModal"; 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 DoubanSubject from "src/douban/data/model/DoubanSubject";
import Searcher from "src/douban/data/search/Search"; import Searcher from "src/douban/data/search/Search";
import { i18nHelper } from './src/lang/helper'; import {i18nHelper} from './src/lang/helper';
import { log } from "src/utils/Logutil"; 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 { export default class DoubanPlugin extends Plugin {
public settings: DoubanPluginSettings; public settings: DoubanPluginSetting;
public doubanExtractHandler: DoubanSearchChooseItemHandler; public doubanExtractHandler: DoubanSearchChooseItemHandler;
public doubanStatusBar: HTMLElement; public doubanStatusBar: HTMLElement;
public fileHandler: FileHandler;
async putToEditor(editor:Editor, extract:DoubanSubject) {
async putToObsidian(context: HandleContext, extract: DoubanSubject) {
try { try {
if (!editor || !extract) { if (!extract) {
log.warn(i18nHelper.getMessage('140101')); log.warn(i18nHelper.getMessage('140101'));
return; return;
} }
this.showStatus('140204', extract.title); this.showStatus('140204', extract.title);
let content: string = this.doubanExtractHandler.parseText(extract, this.settings) const content = await this.doubanExtractHandler.parseText(extract, context)
if (content) { if (content) {
editor.replaceSelection(content); this.putContentToObsidian(context, content);
} }
this.showStatus('140205', extract.title); this.showStatus('140205', extract.title);
}catch (e) { } catch (e) {
this.showStatus('140206', e.message); this.showStatus('140206', e.message);
}finally { } finally {
setTimeout(() => this.doubanStatusBar.empty(), BasicConst.CLEAN_STATUS_BAR_DELAY) setTimeout(() => this.doubanStatusBar.empty(), BasicConst.CLEAN_STATUS_BAR_DELAY)
} }
} }
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 { try {
this.showStatus('140201', searchTerm); this.showStatus('140201', searchTerm);
const resultList = await Searcher.search(searchTerm, this.settings); const resultList = await Searcher.search(searchTerm, this.settings);
this.showStatus('140202', resultList.length.toString()); this.showStatus('140202', resultList.length.toString());
new DoubanFuzzySuggester(this, editor).showSearchList(resultList); new DoubanFuzzySuggester(this, context).showSearchList(resultList);
}catch (e) { } catch (e) {
this.showStatus('140206', e.message); this.showStatus('140206', e.message);
}finally { } finally {
setTimeout(() => this.doubanStatusBar.empty(), BasicConst.CLEAN_STATUS_BAR_DELAY) setTimeout(() => this.doubanStatusBar.empty(), BasicConst.CLEAN_STATUS_BAR_DELAY)
} }
} }
async getDoubanTextForActiveFile(editor: Editor) { async getDoubanTextForActiveFile(context: HandleContext) {
const activeFile = await this.app.workspace.getActiveFile(); const activeFile = await this.app.workspace.getActiveFile();
if (activeFile) { if (activeFile) {
const searchTerm = activeFile.basename; const searchTerm = activeFile.basename;
if (searchTerm) { 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() { async onload() {
await this.loadSettings(); await this.loadSettings();
this.doubanStatusBar = this.addStatusBarItem(); this.doubanStatusBar = this.addStatusBarItem();
this.addCommand({ this.addCommand({
id: "search-douban-by-current-file-name", id: "search-douban-import-and-create-file",
name: i18nHelper.getMessage("110001"), name: i18nHelper.getMessage("110101"),
editorCallback: (editor: Editor) => callback: () =>
this.getDoubanTextForActiveFile(editor), this.getDoubanTextForCreateNewNote({mode: SearchHandleMode.FOR_CREATE, settings: this.settings}),
}); });
this.addCommand({
this.addCommand({ id: "search-douban-by-current-file-name",
id: "search-douban-and-input-current-file", name: i18nHelper.getMessage("110001"),
name: i18nHelper.getMessage("110002"), editorCallback: (editor: Editor) =>
editorCallback: (editor: Editor) => this.getDoubanTextForActiveFile({mode: SearchHandleMode.FOR_REPLACE, settings: this.settings, editor: editor}),
this.getDoubanTextForSearchTerm(editor), });
});
//TODO will support in future
// this.addCommand({ this.addCommand({
// id: "sync-douban-broadcast-by-user-id", id: "search-douban-and-input-current-file",
// name: i18nHelper.getMessage('110006'), name: i18nHelper.getMessage("110002"),
// editorCallback: (editor: Editor) => editorCallback: (editor: Editor) =>
// this.geDoubanTextForSearchTerm(editor), this.getDoubanTextForSearchTerm({mode: SearchHandleMode.FOR_REPLACE, settings: this.settings, editor: editor}),
// }); });
this.addSettingTab(new DoubanSettingTab(this.app, this)); this.addSettingTab(new DoubanSettingTab(this.app, this));
}
async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
this.doubanExtractHandler = new DoubanSearchChooseItemHandler(this.app, this);
}
async saveSettings() {
await this.saveData(this.settings);
} }
showStatus(origin:string, message:string) { 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(); this.doubanStatusBar.empty();
// @ts-ignore // @ts-ignore
this.doubanStatusBar.setText(i18nHelper.getMessage(origin).replace('{0}', message)); this.doubanStatusBar.setText(i18nHelper.getMessage(origin).replace('{0}', message));
} }
} }

95
package-lock.json generated

@ -1,6 +1,6 @@
{ {
"name": "obsidian-sample-plugin", "name": "obsidian-douban-plugin",
"version": "1.0.1", "version": "v1.5.2",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -781,6 +781,11 @@
"mime2ext": "^1.0.1" "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": { "@sinclair/typebox": {
"version": "0.23.5", "version": "0.23.5",
"resolved": "https://registry.npmmirror.com/@sinclair/typebox/-/typebox-0.23.5.tgz", "resolved": "https://registry.npmmirror.com/@sinclair/typebox/-/typebox-0.23.5.tgz",
@ -1096,20 +1101,6 @@
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
"dev": true "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": { "babel-jest": {
"version": "28.1.2", "version": "28.1.2",
"resolved": "https://registry.npmmirror.com/babel-jest/-/babel-jest-28.1.2.tgz", "resolved": "https://registry.npmmirror.com/babel-jest/-/babel-jest-28.1.2.tgz",
@ -1371,14 +1362,6 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true "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": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz", "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", "resolved": "https://registry.npmmirror.com/css-what/-/css-what-6.1.0.tgz",
"integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==" "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": { "debug": {
"version": "4.3.4", "version": "4.3.4",
"resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz", "resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz",
@ -1448,11 +1426,6 @@
"integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
"dev": true "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": { "detect-newline": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmmirror.com/detect-newline/-/detect-newline-3.1.0.tgz", "resolved": "https://registry.npmmirror.com/detect-newline/-/detect-newline-3.1.0.tgz",
@ -1507,14 +1480,6 @@
"domhandler": "^5.0.1" "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": { "electron-to-chromium": {
"version": "1.4.185", "version": "1.4.185",
"resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.185.tgz", "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.185.tgz",
@ -1857,21 +1822,6 @@
"path-exists": "^4.0.0" "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": { "fs.realpath": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz", "resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -2722,19 +2672,6 @@
"picomatch": "^2.3.1" "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": { "mime2ext": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmmirror.com/mime2ext/-/mime2ext-1.0.1.tgz", "resolved": "https://registry.npmmirror.com/mime2ext/-/mime2ext-1.0.1.tgz",
@ -2773,11 +2710,6 @@
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
"dev": true "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": { "node-int64": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmmirror.com/node-int64/-/node-int64-0.4.0.tgz", "resolved": "https://registry.npmmirror.com/node-int64/-/node-int64-0.4.0.tgz",
@ -3261,11 +3193,6 @@
"integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==",
"dev": true "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": { "tmpl": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmmirror.com/tmpl/-/tmpl-1.0.5.tgz", "resolved": "https://registry.npmmirror.com/tmpl/-/tmpl-1.0.5.tgz",
@ -3416,14 +3343,6 @@
"signal-exit": "^3.0.7" "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": { "y18n": {
"version": "5.0.8", "version": "5.0.8",
"resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz", "resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz",

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

@ -16,6 +16,20 @@ export enum TemplateTextMode {
YAML, YAML,
} }
/**
*
*/
export enum SearchHandleMode {
/**
*
*/
FOR_REPLACE,
/**
*
*/
FOR_CREATE,
}
/** /**
* *
*/ */
@ -25,6 +39,19 @@ export enum PersonNameMode {
CH_EN_NAME = "CH_EN", 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 const DEFAULT_TEMPLATE_CONTENT = {
movieTemplateFileContent: `---
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:
`---
doubanId: {{id}} doubanId: {{id}}
title: {{title}} title: {{title}}
type: {{type}} type: {{type}}
@ -36,13 +12,13 @@ actor: {{actor}}
author: {{author}} author: {{author}}
tags: {{type}} tags: {{type}}
url: {{url}} url: {{url}}
dataTime: {{currentDate}} {{currentTime}}
desc: {{desc}} desc: {{desc}}
--- ---
![image]({{image}}) ![image]({{image}})
`, `,
bookTemplate: bookTemplateFileContent: `---
`---
doubanId: {{id}} doubanId: {{id}}
title: {{title}} title: {{title}}
subTitle: {{subTitle}} subTitle: {{subTitle}}
@ -60,6 +36,7 @@ totalPage: {{totalPage}}
price: {{price}} price: {{price}}
tags: Book tags: Book
binding: {{binding}} binding: {{binding}}
dataTime: {{currentDate}} {{currentTime}}
desc: {{desc}} desc: {{desc}}
--- ---
@ -67,8 +44,7 @@ desc: {{desc}}
{{menu}} {{menu}}
`, `,
musicTemplate: musicTemplateFileContent: `---
`---
doubanId: {{id}} doubanId: {{id}}
title: {{title}} title: {{title}}
type: {{type}} type: {{type}}
@ -83,13 +59,13 @@ barcode: {{barcode}}
url: {{url}} url: {{url}}
records: {{records}} records: {{records}}
tags: Music tags: Music
dataTime: {{currentDate}} {{currentTime}}
desc: {{desc}} desc: {{desc}}
--- ---
![image|150]({{image}}) ![image|150]({{image}})
`, `,
noteTemplate: noteTemplateFileContent: `---
`---
doubanId: {{id}} doubanId: {{id}}
title: {{title}} title: {{title}}
type: {{type}} type: {{type}}
@ -98,13 +74,13 @@ authorUrl: {{authorUrl}}
dateTimePublished: {{datePublished}} {{timePublished}} dateTimePublished: {{datePublished}} {{timePublished}}
url: {{url}} url: {{url}}
tags: Article tags: Article
dataTime: {{currentDate}} {{currentTime}}
desc: {{desc}} desc: {{desc}}
--- ---
{{content}} {{content}}
`, `,
gameTemplate: gameTemplateFileContent: `---
`---
doubanId: {{id}} doubanId: {{id}}
title: {{title}} title: {{title}}
aliases: {{aliases}} aliases: {{aliases}}
@ -117,19 +93,28 @@ developer: {{developer}}
platform: {{platform}} platform: {{platform}}
url: {{url}} url: {{url}}
tags: Game tags: Game
dataTime: {{currentDate}} {{currentTime}}
desc: {{desc}} desc: {{desc}}
--- ---
![image]({{image}}) ![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 DoubanNoteSubject from '../model/DoubanPageBroadcastSubject';
import DoubanPageBroadcastSubject from '../model/DoubanPageBroadcastSubject'; import DoubanPageBroadcastSubject from '../model/DoubanPageBroadcastSubject';
import DoubanPlugin from "main"; import DoubanPlugin from "main";
import {DoubanPluginSettings} from "src/douban/Douban";
import DoubanSubject from 'src/douban/data/model/DoubanSubject'; 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 //TODO will support in future version
export default class DoubanPageBroadcatLoadHandler extends DoubanAbstractLoadHandler<DoubanPageBroadcastSubject> { class DoubanPageBroadcatLoadHandler extends DoubanAbstractLoadHandler<DoubanPageBroadcastSubject> {
constructor(doubanPlugin: DoubanPlugin) { constructor(doubanPlugin: DoubanPlugin) {
super(doubanPlugin); super(doubanPlugin);
} }
getTemplate(settings: DoubanPluginSettings): string { getTemplateKey(context: HandleContext): TemplateKey {
return settings.bookTemplate; return null;
} }
parseText(beforeContent: string, extract: DoubanNoteSubject, settings: DoubanPluginSettings): string { parseText(beforeContent: string, extract: DoubanNoteSubject, context: HandleContext): string {
return settings.bookTemplate ? null : ""; return 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 : "")
} }
support(extract: DoubanSubject): boolean { support(extract: DoubanSubject): boolean {
@ -38,37 +27,6 @@ export default class DoubanPageBroadcatLoadHandler extends DoubanAbstractLoadHan
} }
parseSubjectFromHtml(html: CheerioAPI): DoubanPageBroadcastSubject { 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; return null;
} }

@ -1,14 +1,17 @@
import {DoubanPluginSettings} from "src/douban/Douban";
import DoubanPlugin from "main"; import DoubanPlugin from "main";
import DoubanSubject, {DoubanParameter} from '../model/DoubanSubject'; import DoubanSubject, {DoubanParameter} from '../model/DoubanSubject';
import DoubanSubjectLoadHandler from "./DoubanSubjectLoadHandler"; 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 {i18nHelper} from 'src/lang/helper';
import {log} from "src/utils/Logutil"; import {log} from "src/utils/Logutil";
import {CheerioAPI, load} from "cheerio"; import {CheerioAPI, load} from "cheerio";
import YamlUtil from "../../../utils/YamlUtil"; 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> { 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; this.doubanPlugin = doubanPlugin;
} }
parse(extract: T, settings: DoubanPluginSettings): string { async parse(extract: T, context: HandleContext): Promise<HandleResult> {
let template: string = this.getTemplate(settings); let template: string = await this.getTemplate(context);
let frontMatterStart: number = template.indexOf(BasicConst.YAML_FRONT_MATTER_SYMBOL, 0); let frontMatterStart: number = template.indexOf(BasicConst.YAML_FRONT_MATTER_SYMBOL, 0);
let frontMatterEnd: number = template.indexOf(BasicConst.YAML_FRONT_MATTER_SYMBOL, frontMatterStart + 1); let frontMatterEnd: number = template.indexOf(BasicConst.YAML_FRONT_MATTER_SYMBOL, frontMatterStart + 1);
let frontMatter: string = ''; let frontMatter: string = '';
let frontMatterBefore: string = ''; let frontMatterBefore: string = '';
let frontMatterAfter: string = ''; let frontMatterAfter: string = '';
let result:string = '';
if (frontMatterStart > -1 && frontMatterEnd > -1) { if (frontMatterStart > -1 && frontMatterEnd > -1) {
frontMatterBefore = template.substring(0, frontMatterStart); frontMatterBefore = template.substring(0, frontMatterStart);
frontMatter = template.substring(frontMatterStart, frontMatterEnd + 3); frontMatter = template.substring(frontMatterStart, frontMatterEnd + 3);
frontMatterAfter = template.substring(frontMatterEnd + 3); frontMatterAfter = template.substring(frontMatterEnd + 3);
if (frontMatterBefore.length > 0) { if (frontMatterBefore.length > 0) {
frontMatterBefore = this.parsePartText(frontMatterBefore, extract, settings); frontMatterBefore = this.parsePartText(frontMatterBefore, extract, context);
} }
if (frontMatterAfter.length > 0) { if (frontMatterAfter.length > 0) {
frontMatterAfter = this.parsePartText(frontMatterAfter, extract, settings); frontMatterAfter = this.parsePartText(frontMatterAfter, extract, context);
} }
if (frontMatter.length > 0) { 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 { } 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 settings
* @param textMode * @param textMode
*/ */
handleContentArray(array: any[], settings: DoubanPluginSettings, textMode: TemplateTextMode): string { handleContentArray(array: any[], context: HandleContext, textMode: TemplateTextMode): string {
let result; let result;
switch (textMode) { switch (textMode) {
case TemplateTextMode.YAML: case TemplateTextMode.YAML:
result = array.map(YamlUtil.handleText).join(', '); result = array.map(YamlUtil.handleText).join(', ');
break; break;
default: default:
result = array.join(settings.arraySpilt); result = array.join(context.settings.arraySpilt);
} }
return result; return result;
} }
@ -84,10 +94,10 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
* @param textMode * @param textMode
* @param settings * @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; let result;
if (value instanceof Array) { if (value instanceof Array) {
result = this.handleContentArray(value, settings, textMode); result = this.handleContentArray(value, context, textMode);
} else if (value instanceof Number) { } else if (value instanceof Number) {
result = value ? value.toString() : ''; result = value ? value.toString() : '';
} else { } else {
@ -96,13 +106,13 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
return result; 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; abstract support(extract: DoubanSubject): boolean;
handle(url: string, editor: Editor): void { handle(url: string, context: HandleContext): void {
const requestUrlParam: RequestUrlParam = { const requestUrlParam: RequestUrlParam = {
url: url, url: url,
method: "GET", method: "GET",
@ -112,7 +122,7 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
request(requestUrlParam) request(requestUrlParam)
.then(load) .then(load)
.then(this.parseSubjectFromHtml) .then(this.parseSubjectFromHtml)
.then(content => this.toEditor(editor, content)) .then(content => this.toEditor(context, content))
// .then(content => content ? editor.replaceSelection(content) : content) // .then(content => content ? editor.replaceSelection(content) : content)
.catch(e => log.error(i18nHelper.getMessage('130101'))) .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; abstract parseSubjectFromHtml(data: CheerioAPI): T | undefined;
toEditor(editor: Editor, extract: T): T { toEditor(context: HandleContext, extract: T): T {
this.doubanPlugin.putToEditor(editor, extract); this.doubanPlugin.putToObsidian(context, extract);
return extract; return extract;
} }
getPersonName(name: string, settings: DoubanPluginSettings): string { getPersonName(name: string, context: HandleContext): string {
const {settings} = context;
if (!name || !settings || !settings.personNameMode) { if (!name || !settings || !settings.personNameMode) {
return ""; return "";
} }
@ -173,7 +184,7 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
return s; 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 const resultContent = template
.replaceAll(DoubanParameter.ID, extract.id) .replaceAll(DoubanParameter.ID, extract.id)
.replaceAll(DoubanParameter.TITLE, this.handleSpecialContent(extract.title, textMode)) .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.URL, extract.url)
.replaceAll(DoubanParameter.DESC, this.handleSpecialContent(extract.desc, textMode)) .replaceAll(DoubanParameter.DESC, this.handleSpecialContent(extract.desc, textMode))
.replaceAll(DoubanParameter.PUBLISHER, extract.publisher) .replaceAll(DoubanParameter.PUBLISHER, extract.publisher)
.replaceAll(DoubanParameter.DATE_PUBLISHED, extract.datePublished ? moment(extract.datePublished).format(settings.dateFormat) : '') .replaceAll(DoubanParameter.DATE_PUBLISHED, extract.datePublished ? moment(extract.datePublished).format(context.settings.dateFormat) : '')
.replaceAll(DoubanParameter.TIME_PUBLISHED, extract.datePublished ? moment(extract.datePublished).format(settings.timeFormat) : '') .replaceAll(DoubanParameter.TIME_PUBLISHED, extract.datePublished ? moment(extract.datePublished).format(context.settings.timeFormat) : '')
.replaceAll(DoubanParameter.GENRE, this.handleSpecialContent(extract.genre, textMode, settings)) .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 DoubanAbstractLoadHandler from "./DoubanAbstractLoadHandler";
import DoubanBookSubject, {DoubanBookParameter} from "../model/DoubanBookSubject"; import DoubanBookSubject, {DoubanBookParameter} from "../model/DoubanBookSubject";
import DoubanPlugin from "main"; import DoubanPlugin from "main";
import {DEFAULT_SETTINGS, DoubanPluginSettings} from "src/douban/Douban";
import DoubanSubject from "../model/DoubanSubject"; import DoubanSubject from "../model/DoubanSubject";
import {TemplateTextMode} from "../../../constant/Constsant"; import {TemplateKey, TemplateTextMode} from "../../../constant/Constsant";
import StringUtil from "../../../utils/StringUtil"; import StringUtil from "../../../utils/StringUtil";
import HandleContext from "@App/data/model/HandleContext";
export default class DoubanBookLoadHandler extends DoubanAbstractLoadHandler<DoubanBookSubject> { export default class DoubanBookLoadHandler extends DoubanAbstractLoadHandler<DoubanBookSubject> {
@ -13,16 +13,16 @@ export default class DoubanBookLoadHandler extends DoubanAbstractLoadHandler<Dou
super(doubanPlugin); super(doubanPlugin);
} }
getTemplate(settings: DoubanPluginSettings): string { getTemplateKey(context: HandleContext): TemplateKey {
return StringUtil.defaultIfBlank(settings.bookTemplate, DEFAULT_SETTINGS.bookTemplate); 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 return beforeContent
.replaceAll(DoubanBookParameter.author, .replaceAll(DoubanBookParameter.author,
super.handleSpecialContent( super.handleSpecialContent(
extract.author.map(this.handleSpecialAuthorName), textMode, settings)) extract.author.map(this.handleSpecialAuthorName), textMode, context))
.replaceAll(DoubanBookParameter.translator, super.handleSpecialContent(extract.translator, textMode, settings)) .replaceAll(DoubanBookParameter.translator, super.handleSpecialContent(extract.translator, textMode, context))
.replaceAll(DoubanBookParameter.isbn, extract.isbn) .replaceAll(DoubanBookParameter.isbn, extract.isbn)
.replaceAll(DoubanBookParameter.originalTitle, super.handleSpecialContent(extract.originalTitle, textMode)) .replaceAll(DoubanBookParameter.originalTitle, super.handleSpecialContent(extract.originalTitle, textMode))
.replaceAll(DoubanBookParameter.subTitle, super.handleSpecialContent(extract.subTitle, textMode)) .replaceAll(DoubanBookParameter.subTitle, super.handleSpecialContent(extract.subTitle, textMode))

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

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

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

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

@ -1,4 +1,4 @@
import {App, Editor} from "obsidian"; import {App} from "obsidian";
import DoubanBookLoadHandler from "./DoubanBookLoadHandler"; import DoubanBookLoadHandler from "./DoubanBookLoadHandler";
import DoubanMovieLoadHandler from "./DoubanMovieLoadHandler"; import DoubanMovieLoadHandler from "./DoubanMovieLoadHandler";
@ -6,11 +6,12 @@ import DoubanMusicLoadHandler from "./DoubanMusicLoadHandler";
import DoubanNoteLoadHandler from "./DoubanNoteLoadHandler"; import DoubanNoteLoadHandler from "./DoubanNoteLoadHandler";
import DoubanOtherLoadHandler from "./DoubanOtherLoadHandler"; import DoubanOtherLoadHandler from "./DoubanOtherLoadHandler";
import DoubanPlugin from "main"; import DoubanPlugin from "main";
import {DoubanPluginSettings} from "src/douban/Douban";
import DoubanSubject from "../model/DoubanSubject"; import DoubanSubject from "../model/DoubanSubject";
import DoubanSubjectLoadHandler from "./DoubanSubjectLoadHandler"; import DoubanSubjectLoadHandler from "./DoubanSubjectLoadHandler";
import {DoubanTeleplayLoadHandler} from "./DoubanTeleplayLoadHandler"; import {DoubanTeleplayLoadHandler} from "./DoubanTeleplayLoadHandler";
import DoubanGameLoadHandler from "./DoubanGameLoadHandler"; import DoubanGameLoadHandler from "./DoubanGameLoadHandler";
import HandleContext from "@App/data/model/HandleContext";
import HandleResult from "@App/data/model/HandleResult";
export class DoubanSearchChooseItemHandler { export class DoubanSearchChooseItemHandler {
@ -33,34 +34,32 @@ export class DoubanSearchChooseItemHandler {
this._doubanSubjectHandlerDefault]; this._doubanSubjectHandlerDefault];
} }
public handle(searchExtract: DoubanSubject, editor: Editor): void { public handle(searchExtract: DoubanSubject, context: HandleContext): void {
if (!searchExtract) { if (!searchExtract) {
return; return;
} }
let doubanSubjectHandlers: DoubanSubjectLoadHandler<DoubanSubject>[] = this._doubanSubjectHandlers let doubanSubjectHandlers: DoubanSubjectLoadHandler<DoubanSubject>[] = this._doubanSubjectHandlers
.filter(h => h.support(searchExtract)); .filter(h => h.support(searchExtract));
if (doubanSubjectHandlers && doubanSubjectHandlers.length > 0) { if (doubanSubjectHandlers && doubanSubjectHandlers.length > 0) {
doubanSubjectHandlers[0].handle(searchExtract.url, editor); doubanSubjectHandlers[0].handle(searchExtract.url, context);
} else { } else {
this._doubanSubjectHandlerDefault.handle(searchExtract.url, editor); this._doubanSubjectHandlerDefault.handle(searchExtract.url, context);
} }
} }
public parseText(extract: DoubanSubject, settings: DoubanPluginSettings): string { public async parseText(extract: DoubanSubject, context: HandleContext): Promise<HandleResult> {
if (!settings) {
return "";
}
let doubanSubjectHandlers: DoubanSubjectLoadHandler<DoubanSubject>[] = this._doubanSubjectHandlers let doubanSubjectHandlers: DoubanSubjectLoadHandler<DoubanSubject>[] = this._doubanSubjectHandlers
.filter(h => h.support(extract)); .filter(h => h.support(extract));
let result:string='';
if (doubanSubjectHandlers && doubanSubjectHandlers.length > 0) { 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) { if (result && result.length > 0) {
return result[0]; return result[0];
} else { } else {
return ""; return {content: ''};
} }
} else { } 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 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> { export default interface DoubanSubjectLoadHandler<T extends DoubanSubject> {
parse(extract: T, settings: DoubanPluginSettings): string; parse(extract: T, context: HandleContext): Promise<HandleResult>;
support(extract: DoubanSubject): boolean; 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 {CheerioAPI} from "cheerio";
import DoubanAbstractLoadHandler from "./DoubanAbstractLoadHandler"; import DoubanAbstractLoadHandler from "./DoubanAbstractLoadHandler";
import DoubanPlugin from "main"; import DoubanPlugin from "main";
import {DEFAULT_SETTINGS, DoubanPluginSettings} from "src/douban/Douban";
import DoubanSubject from "../model/DoubanSubject"; import DoubanSubject from "../model/DoubanSubject";
import DoubanTeleplaySubject from "../model/DoubanTeleplaySubject"; import DoubanTeleplaySubject from "../model/DoubanTeleplaySubject";
import SchemaOrg from "src/utils/SchemaOrg"; import SchemaOrg from "src/utils/SchemaOrg";
import StringUtil from "../../../utils/StringUtil"; import HandleContext from "@App/data/model/HandleContext";
import {TemplateKey} from "../../../constant/Constsant";
/** /**
* teleplay * teleplay
@ -16,16 +16,17 @@ export class DoubanTeleplayLoadHandler extends DoubanAbstractLoadHandler<DoubanT
super(doubanPlugin); super(doubanPlugin);
} }
getTemplate(settings: DoubanPluginSettings): string { getTemplateKey(context: HandleContext): TemplateKey {
return StringUtil.defaultIfBlank(settings.movieTemplate, DEFAULT_SETTINGS.movieTemplate); return TemplateKey.teleplayTemplate
} }
parseText(beforeContent: string, extract: DoubanTeleplaySubject, settings: DoubanPluginSettings): string { parseText(beforeContent: string, extract: DoubanTeleplaySubject, context: HandleContext): string {
const {settings} = context;
return beforeContent return beforeContent
.replaceAll("{{originalTitle}}", extract.originalTitle ? extract.originalTitle : "") .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("{{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, settings)).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, settings)).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 { support(extract: DoubanSubject): boolean {

@ -27,4 +27,6 @@ export const DoubanParameter = {
DATE_PUBLISHED: '{{datePublished}}', DATE_PUBLISHED: '{{datePublished}}',
TIME_PUBLISHED: '{{timePublished}}', TIME_PUBLISHED: '{{timePublished}}',
GENRE: '{{genre}}', 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 DoubanPlugin from "main";
import DoubanSearchResultSubject from "../model/DoubanSearchResultSubject"; import DoubanSearchResultSubject from "../model/DoubanSearchResultSubject";
import {log} from "src/utils/Logutil"; import {log} from "src/utils/Logutil";
import {i18nHelper} from "../../../lang/helper"; import {i18nHelper} from "../../../lang/helper";
import HandleContext from "@App/data/model/HandleContext";
export {DoubanFuzzySuggester} export {DoubanFuzzySuggester}
class DoubanFuzzySuggester extends FuzzySuggestModal<DoubanSearchResultSubject> { class DoubanFuzzySuggester extends FuzzySuggestModal<DoubanSearchResultSubject> {
public editor: Editor;
private plugin: DoubanPlugin; private plugin: DoubanPlugin;
private doubanSearchResultExtract: DoubanSearchResultSubject[] private doubanSearchResultExtract: DoubanSearchResultSubject[];
private context: HandleContext;
constructor(plugin: DoubanPlugin, editor: Editor) { constructor(plugin: DoubanPlugin, context: HandleContext) {
super(app); super(app);
this.editor = editor;
this.plugin = plugin; this.plugin = plugin;
this.context = context;
this.setPlaceholder(i18nHelper.getMessage('150101')); this.setPlaceholder(i18nHelper.getMessage('150101'));
} }
@ -34,7 +34,7 @@ class DoubanFuzzySuggester extends FuzzySuggestModal<DoubanSearchResultSubject>
onChooseItem(item: DoubanSearchResultSubject, evt: MouseEvent | KeyboardEvent): void { onChooseItem(item: DoubanSearchResultSubject, evt: MouseEvent | KeyboardEvent): void {
this.plugin.showStatus('140204', item.title); this.plugin.showStatus('140204', item.title);
this.plugin.doubanExtractHandler.handle(item, this.editor); this.plugin.doubanExtractHandler.handle(item, this.context);
} }
public showSearchList(doubanSearchResultExtractList: DoubanSearchResultSubject[]) { 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 DoubanPlugin from "main";
import {i18nHelper} from "src/lang/helper"; import {i18nHelper} from "src/lang/helper";
import HandleContext from "@App/data/model/HandleContext";
export class DoubanSearchModal extends Modal { export class DoubanSearchModal extends Modal {
searchTerm: string; searchTerm: string;
plugin: DoubanPlugin; plugin: DoubanPlugin;
editor: Editor; context: HandleContext
constructor(app: App, plugin: DoubanPlugin, editor: Editor) { constructor(app: App, plugin: DoubanPlugin, context: HandleContext) {
super(app); super(app);
this.plugin = plugin; this.plugin = plugin;
this.editor = editor; this.context = context;
} }
onOpen() { onOpen() {
@ -55,7 +56,7 @@ export class DoubanSearchModal extends Modal {
let {contentEl} = this; let {contentEl} = this;
contentEl.empty(); contentEl.empty();
if (this.searchTerm) { 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 DoubanSearchResultSubject from '../model/DoubanSearchResultSubject';
import SearchParserHandler from './SearchParser'; import SearchParserHandler from './SearchParser';
@ -6,9 +5,10 @@ import {log} from 'src/utils/Logutil';
import {request, RequestUrlParam} from "obsidian"; import {request, RequestUrlParam} from "obsidian";
import {i18nHelper} from "../../../lang/helper"; import {i18nHelper} from "../../../lang/helper";
import {load} from 'cheerio'; import {load} from 'cheerio';
import {DoubanPluginSetting} from "@App/setting/model/DoubanPluginSetting";
export default class Searcher { export default class Searcher {
static search(searchItem: string, doubanSettings: DoubanPluginSettings): Promise<DoubanSearchResultSubject[]> { static search(searchItem: string, doubanSettings: DoubanPluginSetting): Promise<DoubanSearchResultSubject[]> {
let requestUrlParam: RequestUrlParam = { let requestUrlParam: RequestUrlParam = {
url: doubanSettings.searchUrl + searchItem, url: doubanSettings.searchUrl + searchItem,
method: "GET", 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`, '120131': `Create New File Name`,
'120201': `Book Content Template`, '120201': `Book Template File`,
'120202': `Set markdown Book template for extract to be inserted.`, '120202': `Set markdown Book template for extract to be inserted.`,
'120203': `Available Book template variables are :`, '120203': `Available Book template variables are :`,
'120204': `{{id}}, {{title}}, {{type}}, {{score}}, {{image}},`, '120204': `{{id}}, {{title}}, {{type}}, {{score}}, {{image}},`,
@ -41,7 +41,7 @@ export default {
'120207': `{{translator}}, {{isbn}}, {{price}}, {{totalPage}}`, '120207': `{{translator}}, {{isbn}}, {{price}}, {{totalPage}}`,
'120208': `{{series}}, {{binding}}, {{menu}}`, '120208': `{{series}}, {{binding}}, {{menu}}`,
'120301': `Music Content Template`, '120301': `Music Template File`,
'120302': `Set markdown Music template for extract to be inserted.`, '120302': `Set markdown Music template for extract to be inserted.`,
'120303': `Available Music template variables are :`, '120303': `Available Music template variables are :`,
'120304': `{{id}}, {{title}}, {{type}}, {{score}}, {{image}},`, '120304': `{{id}}, {{title}}, {{type}}, {{score}}, {{image}},`,
@ -49,7 +49,7 @@ export default {
'120306': `{{actor}}, {{medium}}, {{albumType}},`, '120306': `{{actor}}, {{medium}}, {{albumType}},`,
'120307': `{{barcode}}, {{records}}`, '120307': `{{barcode}}, {{records}}`,
'120401': `Article Content Template`, '120401': `Article Template File`,
'120402': `Set markdown Article template for extract to be inserted.`, '120402': `Set markdown Article template for extract to be inserted.`,
'120403': `Available Article template variables are :`, '120403': `Available Article template variables are :`,
'120404': `{{id}}, {{title}}, {{type}}, {{image}},`, '120404': `{{id}}, {{title}}, {{type}}, {{image}},`,
@ -57,7 +57,7 @@ export default {
'120406': `{{author}}, {{authorUrl}}, {{content}}`, '120406': `{{author}}, {{authorUrl}}, {{content}}`,
'120407': `{{timePublished}}`, '120407': `{{timePublished}}`,
'121301': `Game Content Template`, '121301': `Game Template File`,
'121302': `Set markdown Game template for extract to be inserted.`, '121302': `Set markdown Game template for extract to be inserted.`,
'121303': `Available Game template variables are :`, '121303': `Available Game template variables are :`,
'121304': `{{id}}, {{title}}, {{type}}, {{score}}, {{image}},`, '121304': `{{id}}, {{title}}, {{type}}, {{score}}, {{image}},`,
@ -88,8 +88,20 @@ export default {
'121207': `English Name`, '121207': `English Name`,
'121208': `Chinese And 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 //error
@ -110,4 +122,8 @@ export default {
//content //content
'200101': `. `, '200101': `. `,
'210101': `Default`,
'210201': `Search...`
} }

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