mirror of
https://github.com/Wanxp/obsidian-douban.git
synced 2026-04-04 08:38:41 +08:00
237 lines
8.5 KiB
TypeScript
237 lines
8.5 KiB
TypeScript
|
|
import DoubanPlugin from "main";
|
|
import DoubanSubject, {DoubanParameter} from '../model/DoubanSubject';
|
|
import DoubanSubjectLoadHandler from "./DoubanSubjectLoadHandler";
|
|
import {moment, request, RequestUrlParam, TFile} from "obsidian";
|
|
import {i18nHelper} from 'src/lang/helper';
|
|
import {log} from "src/utils/Logutil";
|
|
import {CheerioAPI, load} from "cheerio";
|
|
import YamlUtil from "../../../utils/YamlUtil";
|
|
import {BasicConst, PersonNameMode, SearchHandleMode, TemplateKey, TemplateTextMode} from "../../../constant/Constsant";
|
|
import HandleContext from "@App/data/model/HandleContext";
|
|
import HandleResult from "@App/data/model/HandleResult";
|
|
import {DEFAULT_TEMPLATE_CONTENT, getDefaultTemplateContent} from "../../../constant/DefaultTemplateContent";
|
|
import FileHandler from "../../../file/FileHandler";
|
|
import StringUtil from "../../../utils/StringUtil";
|
|
import {DEFAULT_SETTINGS} from "../../../constant/DefaultSettings";
|
|
|
|
export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject> implements DoubanSubjectLoadHandler<T> {
|
|
|
|
|
|
public doubanPlugin: DoubanPlugin;
|
|
|
|
constructor(doubanPlugin: DoubanPlugin) {
|
|
this.doubanPlugin = doubanPlugin;
|
|
}
|
|
|
|
async parse(extract: T, context: HandleContext): Promise<HandleResult> {
|
|
let template: string = await this.getTemplate(context);
|
|
let frontMatterStart: number = template.indexOf(BasicConst.YAML_FRONT_MATTER_SYMBOL, 0);
|
|
let frontMatterEnd: number = template.indexOf(BasicConst.YAML_FRONT_MATTER_SYMBOL, frontMatterStart + 1);
|
|
let frontMatter: string = '';
|
|
let frontMatterBefore: string = '';
|
|
let frontMatterAfter: string = '';
|
|
let result:string = '';
|
|
if (frontMatterStart > -1 && frontMatterEnd > -1) {
|
|
frontMatterBefore = template.substring(0, frontMatterStart);
|
|
frontMatter = template.substring(frontMatterStart, frontMatterEnd + 3);
|
|
frontMatterAfter = template.substring(frontMatterEnd + 3);
|
|
if (frontMatterBefore.length > 0) {
|
|
frontMatterBefore = this.parsePartText(frontMatterBefore, extract, context);
|
|
}
|
|
if (frontMatterAfter.length > 0) {
|
|
frontMatterAfter = this.parsePartText(frontMatterAfter, extract, context);
|
|
}
|
|
if (frontMatter.length > 0) {
|
|
frontMatter = this.parsePartText(frontMatter, extract, context, TemplateTextMode.YAML);
|
|
}
|
|
result = frontMatterBefore + frontMatter + frontMatterAfter;
|
|
} else {
|
|
result = this.parsePartText(template, extract, context);
|
|
}
|
|
let fileName:string = '';
|
|
if (SearchHandleMode.FOR_CREATE == context.mode) {
|
|
fileName = this.parsePartText(this.getFileName(context), extract, context);
|
|
}
|
|
|
|
return {content: result, fileName: fileName};
|
|
}
|
|
|
|
private getFileName(context:HandleContext): string {
|
|
const {dataFileNamePath} = context.settings;
|
|
return dataFileNamePath ? dataFileNamePath : DEFAULT_SETTINGS.dataFileNamePath;
|
|
}
|
|
|
|
/**
|
|
* 处理特殊字符
|
|
* @param text
|
|
* @param textMode
|
|
*/
|
|
handleSpecialText(text: string, textMode: TemplateTextMode): string {
|
|
let result = text;
|
|
switch (textMode) {
|
|
case TemplateTextMode.YAML:
|
|
result = YamlUtil.handleText(text);
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* 处理内容数组
|
|
* @param array
|
|
* @param settings
|
|
* @param textMode
|
|
*/
|
|
handleContentArray(array: any[], context: HandleContext, textMode: TemplateTextMode): string {
|
|
let result;
|
|
switch (textMode) {
|
|
case TemplateTextMode.YAML:
|
|
result = array.map(YamlUtil.handleText).join(', ');
|
|
break;
|
|
default:
|
|
result = array.join(context.settings.arraySpilt);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* 处理特殊内容
|
|
* @param value
|
|
* @param textMode
|
|
* @param settings
|
|
*/
|
|
handleSpecialContent(value: any, textMode: TemplateTextMode = TemplateTextMode.NORMAL, context: HandleContext = null): string {
|
|
let result;
|
|
if (!value) {
|
|
return i18nHelper.getMessage('410101');
|
|
}
|
|
if (value instanceof Array) {
|
|
result = this.handleContentArray(value, context, textMode);
|
|
} else if (value instanceof Number) {
|
|
result = value.toString();
|
|
} else {
|
|
result = this.handleSpecialText(value, textMode);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
abstract getTemplateKey(context: HandleContext): TemplateKey;
|
|
|
|
abstract parseText(beforeContent: string, extract: T, context: HandleContext, textMode: TemplateTextMode): string;
|
|
|
|
abstract support(extract: DoubanSubject): boolean;
|
|
|
|
handle(url: string, context: HandleContext): void {
|
|
const requestUrlParam: RequestUrlParam = {
|
|
url: url,
|
|
method: "GET",
|
|
headers: JSON.parse(this.doubanPlugin.settings.searchHeaders),
|
|
throw: true
|
|
};
|
|
request(requestUrlParam)
|
|
.then(load)
|
|
.then(this.parseSubjectFromHtml)
|
|
.then(content => this.toEditor(context, content))
|
|
// .then(content => content ? editor.replaceSelection(content) : content)
|
|
.catch(e => log.error(i18nHelper.getMessage('130101')))
|
|
;
|
|
|
|
}
|
|
|
|
abstract parseSubjectFromHtml(data: CheerioAPI): T | undefined;
|
|
|
|
toEditor(context: HandleContext, extract: T): T {
|
|
this.doubanPlugin.putToObsidian(context, extract);
|
|
return extract;
|
|
}
|
|
|
|
getPersonName(name: string, context: HandleContext): string {
|
|
return this.getPersonNameByMode(name, context.settings.personNameMode);
|
|
}
|
|
|
|
getPersonNameByMode(name: string, personNameMode: string): string {
|
|
if (!name || !personNameMode) {
|
|
return "";
|
|
}
|
|
let resultName: string;
|
|
let regValue: RegExpExecArray;
|
|
switch (personNameMode) {
|
|
case PersonNameMode.CH_NAME:
|
|
regValue = /[\u4e00-\u9fa50-9\. \:\u3002|\uff1f|\uff01|\uff0c|\u3001|\uff1b|\uff1a|\u201c|\u201d|\u2018|\u2019|\uff08|\uff09|\u300a|\u300b|\u3008|\u3009|\u3010|\u3011|\u300e|\u300f|\u300c|\u300d|\ufe43|\ufe44|\u3014|\u3015|\u2026|\u2014|\uff5e|\ufe4f|\uffe5]{2,20}/g.exec(name);
|
|
resultName = regValue ? regValue[0] : name;
|
|
break;
|
|
case PersonNameMode.EN_NAME:
|
|
regValue = /[0-9a-zA-Z.\s-]{2,50}/g.exec(name);
|
|
resultName = regValue ? regValue[0] : name;
|
|
break;
|
|
default:
|
|
resultName = name;
|
|
}
|
|
return resultName;
|
|
}
|
|
|
|
// html_encode(str: string): string {
|
|
// let s = "";
|
|
// if (str.length == 0) return "";
|
|
// s = str.replace(/&/g, "&");
|
|
// s = s.replace(/</g, "<");
|
|
// s = s.replace(/>/g, ">");
|
|
// s = s.replace(/ /g, " ");
|
|
// s = s.replace(/\'/g, "'");
|
|
// s = s.replace(/\"/g, """);
|
|
// s = s.replace(/\n/g, "<br/>");
|
|
// return s;
|
|
// }
|
|
|
|
html_decode(str: string): string {
|
|
let s = "";
|
|
if (str.length == 0) return "";
|
|
s = str.replace(/&/g, "&");
|
|
s = s.replace(/</g, "<");
|
|
s = s.replace(/>/g, ">");
|
|
s = s.replace(/ /g, " ");
|
|
s = s.replace(/'/g, "\'");
|
|
s = s.replace(/"/g, "\"");
|
|
s = s.replace(/<br\/>/g, "\n");
|
|
return s;
|
|
}
|
|
|
|
private parsePartText(template: string, extract: T, context: HandleContext, textMode: TemplateTextMode = TemplateTextMode.NORMAL): string {
|
|
const resultContent = template
|
|
.replaceAll(DoubanParameter.ID, extract.id)
|
|
.replaceAll(DoubanParameter.TITLE, this.handleSpecialContent(this.getPersonName(extract.title, context), textMode))
|
|
.replaceAll(DoubanParameter.TYPE, extract.type)
|
|
.replaceAll(DoubanParameter.SCORE, this.handleSpecialContent(extract.score))
|
|
.replaceAll(DoubanParameter.IMAGE, extract.image)
|
|
.replaceAll(DoubanParameter.URL, extract.url)
|
|
.replaceAll(DoubanParameter.DESC, this.handleSpecialContent(extract.desc, textMode))
|
|
.replaceAll(DoubanParameter.PUBLISHER, extract.publisher)
|
|
.replaceAll(DoubanParameter.DATE_PUBLISHED, extract.datePublished ? moment(extract.datePublished).format(context.settings.dateFormat) : '')
|
|
.replaceAll(DoubanParameter.TIME_PUBLISHED, extract.datePublished ? moment(extract.datePublished).format(context.settings.timeFormat) : '')
|
|
.replaceAll(DoubanParameter.CURRENT_DATE, moment(new Date()).format(context.settings.dateFormat))
|
|
.replaceAll(DoubanParameter.CURRENT_TIME, moment(new Date()).format(context.settings.timeFormat))
|
|
.replaceAll(DoubanParameter.GENRE, this.handleSpecialContent(extract.genre, textMode, context))
|
|
;
|
|
return this.parseText(resultContent, extract, context, textMode);
|
|
}
|
|
|
|
private async getTemplate(context: HandleContext):Promise<string> {
|
|
const tempKey:TemplateKey = this.getTemplateKey(context);
|
|
const templatePath:string = context.settings[tempKey];
|
|
|
|
// @ts-ignore
|
|
if (!templatePath || StringUtil.isBlank(templatePath)) {
|
|
return getDefaultTemplateContent(tempKey);
|
|
}
|
|
const defaultContent = getDefaultTemplateContent(tempKey);
|
|
let firstLinkpathDest:TFile = this.doubanPlugin.app.metadataCache.getFirstLinkpathDest(templatePath, '');
|
|
if (!firstLinkpathDest) {
|
|
return defaultContent;
|
|
}else {
|
|
const val = await this.doubanPlugin.fileHandler.getFileContent(firstLinkpathDest.path);
|
|
return val?val:defaultContent;
|
|
}
|
|
}
|
|
}
|