optimize and fix bug

This commit is contained in:
wanxp 2022-11-26 13:54:29 +08:00
parent c0d7cf5972
commit 86345cdf85
30 changed files with 587 additions and 146 deletions

@ -48,36 +48,36 @@ Import _Movie, Book, Music, Teleplay, Note, Game_ even _Your Personal Movie/Book
## Support Field/支持的字段
(若有缺少想导入的字段, 欢迎提issues反馈)
| 字段 | 电影 | 电视剧 | 书籍 | 音乐 | 日记 | 游戏 | 广播 |
| ---------------- | -------------------- | -------------------- | -------------------- | ------------------- | ------------------ | ------------------- | ---- |
| id | 豆瓣ID | 豆瓣ID | 豆瓣ID | 豆瓣ID | 豆瓣ID | 豆瓣ID | - |
| title | 电影名称 | 电视剧名称 | 书名 | 音乐名 | 日记标题 | 游戏名称 | - |
| type | 类型 | 类型 | 类型 | 类型 | 类型 | 类型 | - |
| score | 评分 | 评分 | 评分 | 评分 | 评分 | 评分 | - |
| image | 封面 | 封面 | 封面 | 封面 | 图片 | 封面 | - |
| url | 豆瓣网址 | 豆瓣网址 | 豆瓣网址 | 豆瓣网址 | 豆瓣网址 | 豆瓣网址 | - |
| desc | 简介 | 简介 | 内容简介 | 简介 | 简介 | 简介 | - |
| publisher | - | - | 出版社 | 出版者 | 发布者 | 发行商 | - |
| datePublished | 上映日期 | 上映日期 | 出版年 | 发行时间 | 发布时间 | 发行日期 | - |
| genre | 类型 | 类型 | - | 流派 | - | 类型 | - |
| currentDate | 今日日期 | 今日日期 | 今日日期 | 今日日期 | 今日日期 | 今日日期 | |
| currentTime | 当前时间 | 当前时间 | 当前时间 | 当前时间 | 当前时间 | 当前时间 | |
| myTags | 我标记的标签 | 我标记的标签 | 我标记的标签 | 我标记的标签 | - | 我标记的标签 | |
| myRating | 我的评分 | 我的评分 | 我的评分 | 我的评分 | - | 我的评分 |
| myState | 状态:想看/在看/看过 | 状态:想看/在看/看过 | 状态:想看/在看/看过 | 状态:想听/在听/听过 | - | 状态:想玩/在玩/玩过 | |
| myComment | 我的评语 | 我的评语 | 我的评语 | 我的评语 | - | 我的评语 | |
| myCollectionDate | 我标记的时间 | 我标记的时间 | 我标记的时间 | 我标记的时间 | - | 我标记的时间 | |
| 扩展1 | director:导演 | director:导演 | author:原作者 | actor: 表演者 | author:作者 | aliases:别名 | |
| 扩展2 | author:编剧 | author:编剧 | translator:译者 | albumType:专辑类型 | authorUrl:作者网址 | developer:开发商 | |
| 扩展3 | actor:主演 | actor:主演 | isbn:isbn | medium:介质 | content:日记内容 | platform:平台 | |
| 字段 | 电影 | 电视剧 | 书籍 | 音乐 | 日记 | 游戏 | 广播 |
| ---------------- |-------------------|------------------| -------------------- | ------------------- | ------------------ | ------------------- | ---- |
| id | 豆瓣ID | 豆瓣ID | 豆瓣ID | 豆瓣ID | 豆瓣ID | 豆瓣ID | - |
| title | 电影名称 | 电视剧名称 | 书名 | 音乐名 | 日记标题 | 游戏名称 | - |
| type | 类型 | 类型 | 类型 | 类型 | 类型 | 类型 | - |
| score | 评分 | 评分 | 评分 | 评分 | 评分 | 评分 | - |
| image | 封面 | 封面 | 封面 | 封面 | 图片 | 封面 | - |
| url | 豆瓣网址 | 豆瓣网址 | 豆瓣网址 | 豆瓣网址 | 豆瓣网址 | 豆瓣网址 | - |
| desc | 简介 | 简介 | 内容简介 | 简介 | 简介 | 简介 | - |
| publisher | - | - | 出版社 | 出版者 | 发布者 | 发行商 | - |
| datePublished | 上映日期 | 上映日期 | 出版年 | 发行时间 | 发布时间 | 发行日期 | - |
| genre | 类型 | 类型 | - | 流派 | - | 类型 | - |
| currentDate | 今日日期 | 今日日期 | 今日日期 | 今日日期 | 今日日期 | 今日日期 | |
| currentTime | 当前时间 | 当前时间 | 当前时间 | 当前时间 | 当前时间 | 当前时间 | |
| myTags | 我标记的标签 | 我标记的标签 | 我标记的标签 | 我标记的标签 | - | 我标记的标签 | |
| myRating | 我的评分 | 我的评分 | 我的评分 | 我的评分 | - | 我的评分 |
| myState | 状态:想看/在看/看过 | 状态:想看/在看/看过 | 状态:想看/在看/看过 | 状态:想听/在听/听过 | - | 状态:想玩/在玩/玩过 | |
| myComment | 我的评语 | 我的评语 | 我的评语 | 我的评语 | - | 我的评语 | |
| myCollectionDate | 我标记的时间 | 我标记的时间 | 我标记的时间 | 我标记的时间 | - | 我标记的时间 | |
| 扩展1 | director:导演 | director:导演 | author:原作者 | actor: 表演者 | author:作者 | aliases:别名 | |
| 扩展2 | author:编剧 | author:编剧 | translator:译者 | albumType:专辑类型 | authorUrl:作者网址 | developer:开发商 | |
| 扩展3 | actor:主演 | actor:主演 | isbn:isbn | medium:介质 | content:日记内容 | platform:平台 | |
| 扩展4 | originalTitle:原作名 | originalTitle:原作名 | originalTitle:原作名 | records:唱片数 | | | |
| 扩展5 | | | subTitle:副标题 | barcode:条形码 | | | |
| 扩展6 | | | totalPage:页数 | | | | |
| 扩展7 | | | series:丛书 | | | | |
| 扩展8 | | | menu:目录 | | | | |
| 扩展9 | | | price:定价 | | | | |
| 扩展7 | | | binding:装帧 | | | | |
| 扩展8 | | | producer: 出品方 | | | | |
| 扩展5 | country:国家 | country:国家 | subTitle:副标题 | barcode:条形码 | | | |
| 扩展6 | language:语言 | language:语言 | totalPage:页数 | | | | |
| 扩展7 | time:片长 | time:片长 | series:丛书 | | | | |
| 扩展8 | aliases:又名 | aliases:又名 | menu:目录 | | | | |
| 扩展9 | IMDb | IMDb | price:定价 | | | | |
| 扩展7 | | episode:集数 | binding:装帧 | | | | |
| 扩展8 | | | producer: 出品方 | | | | |
- 注: myTags, myRating, myState, myComment, myCollectionDate 参数均为在插件中登录后可用

@ -1,7 +1,7 @@
{
"id": "obsidian-douban-plugin",
"name": "Douban",
"version": "v1.7.3",
"version": "1.7.4",
"minAppVersion": "0.12.0",
"description": "This is a plugin that can import movies/books/musics/notes/games info data from Douban for Obsidian .",
"author": "Wanxp",

@ -1,6 +1,6 @@
{
"name": "obsidian-douban-plugin",
"version": "v1.7.3",
"version": "1.7.4",
"description": "This is a plugin for Obsidian (https://obsidian.md) that can import data from Douban (https://www.douban.com/).",
"main": "main.js",
"scripts": {

@ -14,6 +14,11 @@ actor: {{actor}}
author: {{author}}
tags: {{type}}
url: {{url}}
aliases: {{aliases}}
country: {{country}}
language: {{language}}
IMDb: {{IMDb}}
time: {{time}}
createTime: {{currentDate}} {{currentTime}}
desc: {{desc}}
---
@ -114,6 +119,12 @@ actor: {{actor}}
author: {{author}}
tags: {{type}}
url: {{url}}
aliases: {{aliases}}
country: {{country}}
language: {{language}}
IMDb: {{IMDb}}
time: {{time}}
episode: {{episode}}
createTime: {{currentDate}} {{currentTime}}
desc: {{desc}}
---
@ -138,6 +149,11 @@ author: {{author}}
tags: {{type}}, {{myTags}}
state: {{myState}}
url: {{url}}
aliases: {{aliases}}
country: {{country}}
language: {{language}}
IMDb: {{IMDb}}
time: {{time}}
createTime: {{currentDate}} {{currentTime}}
collectionDate: {{myCollectionDate}}
desc: {{desc}}
@ -206,6 +222,11 @@ desc: {{desc}}
---
![image|150]({{image}})
Comment:
---
{{myComment}}
`,
noteTemplateFileContent: `---
doubanId: {{id}}
@ -262,6 +283,12 @@ author: {{author}}
tags: {{type}}, {{myTags}}
state: {{myState}}
url: {{url}}
aliases: {{aliases}}
country: {{country}}
language: {{language}}
IMDb: {{IMDb}}
time: {{time}}
episode: {{episode}}
createTime: {{currentDate}} {{currentTime}}
collectionDate: {{myCollectionDate}}
desc: {{desc}}

@ -17,6 +17,9 @@ import {SyncConfig} from "../sync/model/SyncConfig";
import {clearInterval} from "timers";
import {FolderSuggest} from "../setting/model/FolderSuggest";
import {DEFAULT_SETTINGS} from "../../constant/DefaultSettings";
import {createFileSelectionSetting} from "../setting/TemplateSettingHelper";
import {FileSuggest} from "../setting/model/FileSuggest";
import {getDefaultTemplateContent} from "../../constant/DefaultTemplateContent";
export class DoubanSyncModal extends Modal {
plugin: DoubanPlugin;
@ -54,31 +57,32 @@ export class DoubanSyncModal extends Modal {
sliderDiv.addClass('obsidian_douban_sync_slider');
const controls = contentEl.createDiv("controls");
const syncButton = new ButtonComponent(controls)
const stopButton = new ButtonComponent(controls)
.setButtonText(i18nHelper.getMessage('110009'))
.onClick(async () => {
this.close();
await this.plugin.statusHolder.stopSync();
})
const cancelButton = new ButtonComponent(controls)
const backgroundButton = new ButtonComponent(controls)
.setButtonText(i18nHelper.getMessage('110010'))
.onClick(() => {
this.close();
});
this.showProgress(sliderDiv, syncButton);
this.showProgress(sliderDiv, backgroundButton, stopButton);
this.timer = setInterval(() => {
this.showProgress(sliderDiv,syncButton);
this.showProgress(sliderDiv,backgroundButton, stopButton);
}, 1000);
syncButton.setClass("obsidian_douban_status_button");
cancelButton.setClass("obsidian_douban_status_button");
backgroundButton.setClass("obsidian_douban_status_button");
stopButton.setClass("obsidian_douban_status_button");
}
private showProgress(sliderDiv: HTMLDivElement, button:ButtonComponent) {
private showProgress(sliderDiv: HTMLDivElement, backgroundButton:ButtonComponent, stopButton:ButtonComponent) {
sliderDiv.empty();
new Setting(sliderDiv);
let progress = sliderDiv.createDiv('progress');
@ -88,7 +92,8 @@ export class DoubanSyncModal extends Modal {
<label for="file">${i18nHelper.getMessage('110033')}</label>
<progress class="obsidian_douban_sync_slider" max="${syncStatus.getTotal()}" value="${syncStatus.getHandle()}"> </progress> <span> ${syncStatus.getHandle()}/${syncStatus.getTotal()}:${i18nHelper.getMessage('110036')} </span>
</p>`
button.setDisabled(true);
backgroundButton.setDisabled(true);
stopButton.setButtonText(i18nHelper.getMessage('110036'))
return;
}
progress.innerHTML = `<p>
@ -108,6 +113,7 @@ export class DoubanSyncModal extends Modal {
dataFileNamePath: (settings.dataFileNamePath == '' || settings.dataFileNamePath == null) ? DEFAULT_SETTINGS.dataFileNamePath : settings.dataFileNamePath,
cacheImage: ( settings.cacheImage == null) ? DEFAULT_SETTINGS.cacheImage : settings.cacheImage,
attachmentPath: (settings.attachmentPath == '' || settings.attachmentPath == null) ? DEFAULT_SETTINGS.attachmentPath : settings.attachmentPath,
templateFile: (settings.movieTemplateFile == '' || settings.movieTemplateFile == null) ? DEFAULT_SETTINGS.movieTemplateFile : settings.movieTemplateFile,
};
this.showConfigPan(contentEl.createDiv('config'), syncConfig, false);
const controls = contentEl.createDiv("controls");
@ -145,6 +151,7 @@ export class DoubanSyncModal extends Modal {
private showConfigPan(contentEl: HTMLElement, config:SyncConfig, disable:boolean) {
new Setting(contentEl);
this.showTypeDropdown(contentEl, config, disable);
this.showOutputFolderSelections(contentEl, config, disable);
this.showOutiFleName(contentEl, config, disable);
this.showAttachmentsFileConfig(contentEl, config, disable);
@ -182,6 +189,7 @@ export class DoubanSyncModal extends Modal {
private showTypeDropdown(containerEl:HTMLElement, config: SyncConfig, disable:boolean) {
const settings = new Setting(containerEl);
const scopeSelections = containerEl.createDiv("scope-selection");
const templateFile:HTMLDivElement = containerEl.createDiv('template-file-path-selection');
settings
.setName(i18nHelper.getMessage('110030'))
.addDropdown((dropdown) => {
@ -190,9 +198,11 @@ export class DoubanSyncModal extends Modal {
.onChange((value) => {
config.syncType = value;
this.openScopeDropdown(scopeSelections, config, disable);
this.showTemplateFileSelectionSetting(templateFile, config, disable);
});
}).setDisabled(disable);
this.openScopeDropdown(scopeSelections, config, disable);
this.showTemplateFileSelectionSetting(templateFile, config, disable);
}
private showScopeDropdown(containerEl:HTMLDivElement, scopeSelections: Record<string, string>, config: SyncConfig, disable:boolean) {
@ -251,6 +261,52 @@ export class DoubanSyncModal extends Modal {
.setDisabled(disable);
}
showTemplateFileSelectionSetting(containerEl: HTMLElement, config: SyncConfig, disable:boolean) {
containerEl.empty();
const key:string = this.getKey(config.syncType);
// @ts-ignore
const placeHolder:string = this.plugin.settings[key] ? this.plugin.settings[key] : DEFAULT_SETTINGS[key];
let setting = new Setting(containerEl)
.setName(i18nHelper.getMessage('121101'))
.setDesc(i18nHelper.getMessage('121102'))
.addSearch(async (search: SearchComponent) => {
new FileSuggest(this.app, search.inputEl);
// @ts-ignore
search.setValue(config.templateFile)
// @ts-ignore
.setPlaceholder(placeHolder)
.onChange(async (value: string) => {
config.templateFile = value;
});
})
.setDisabled(disable);
setting.addExtraButton((button) => {
button
.setIcon('copy')
.setTooltip(i18nHelper.getMessage('121903'))
.onClick(async () => {
// @ts-ignore
navigator.clipboard.writeText(getDefaultTemplateContent(key));
});
});
setting.addExtraButton((button) => {
button
.setIcon('document')
.setTooltip(i18nHelper.getMessage('121901'))
.onClick(async () => {
// @ts-ignore
navigator.clipboard.writeText(getDefaultTemplateContent(key, false))
});
});
}
private getKey(supportType: string) {
return supportType + 'TemplateFile';
}
showForceUpdateConfig(containerEl: HTMLElement, config: SyncConfig, disable:boolean) {
new Setting(containerEl)

@ -136,7 +136,7 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
abstract support(extract: DoubanSubject): boolean;
handle(url: string, context: HandleContext): void {
async handle(url: string, context: HandleContext): Promise<void> {
let headers = JSON.parse(context.settings.searchHeaders);
headers.Cookie = context.settings.loginCookiesContent;
const requestUrlParam: RequestUrlParam = {
@ -145,12 +145,13 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
headers: headers,
throw: true
};
request(requestUrlParam)
await request(requestUrlParam)
.then(s => this.humanCheck(s, url))
.then(response => log.debug(response))
.then(load)
.then(data => this.analysisUserState(data, context))
.then(({data, userState}) => {
let sub = this.parseSubjectFromHtml(data);
let sub = this.parseSubjectFromHtml(data, context);
sub.userState = userState;
return sub;
})
@ -171,10 +172,10 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
}
abstract parseSubjectFromHtml(data: CheerioAPI): T | undefined;
abstract parseSubjectFromHtml(data: CheerioAPI, context: HandleContext): T | undefined;
toEditor(context: HandleContext, extract: T): T {
this.doubanPlugin.putToObsidian(context, extract);
async toEditor(context: HandleContext, extract: T): Promise<T> {
await this.doubanPlugin.putToObsidian(context, extract);
return extract;
}
@ -203,6 +204,24 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
return resultName;
}
getTitleNameByMode(name: string, personNameMode: string, context: HandleContext): string {
if (!name || !personNameMode) {
return "";
}
if (context.listItem) {
const newName = context.listItem.title.trim().replaceAll(' ', '');
switch (personNameMode) {
case PersonNameMode.CH_NAME:
return newName;
break;
case PersonNameMode.EN_NAME:
return name.trim().replaceAll(' ', '').replaceAll(newName, '');
break;
}
}
return this.getPersonNameByMode(name, personNameMode);
}
// html_encode(str: string): string {
// let s = "";
// if (str.length == 0) return "";
@ -232,7 +251,7 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
private parsePartText(template: string, extract: T, context: HandleContext, textMode: TemplateTextMode = TemplateTextMode.NORMAL): string {
let resultContent = this.handleCustomVariable(template, context);
resultContent = resultContent.replaceAll(DoubanParameter.ID, extract.id)
.replaceAll(DoubanParameter.TITLE, this.handleSpecialContent(this.getPersonName(extract.title, context), textMode))
.replaceAll(DoubanParameter.TITLE, this.handleSpecialContent(extract.title, textMode))
.replaceAll(DoubanParameter.TYPE, extract.type)
.replaceAll(DoubanParameter.SCORE, this.handleSpecialContent(extract.score))
.replaceAll(DoubanParameter.IMAGE, extract.image)
@ -266,7 +285,7 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
.replaceAll(DoubanUserParameter.MY_RATING, this.handleSpecialContent(userState.rate, textMode))
.replaceAll(DoubanUserParameter.MY_STATE, this.getUserStateName(userState.state))
.replaceAll(DoubanUserParameter.MY_COMMENT, this.handleSpecialContent(userState.comment, textMode))
.replaceAll(DoubanUserParameter.MY_COLLECTION_DATE, moment(userState.collectionDate).format(context.settings.dateFormat))
.replaceAll(DoubanUserParameter.MY_COLLECTION_DATE, userState.collectionDate?moment(userState.collectionDate).format(context.settings.dateFormat): '')
}
/**
@ -319,6 +338,13 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
}
private async getTemplate(extract: T, context: HandleContext): Promise<string> {
const {syncConfig} = context;
if (syncConfig && syncConfig.templateFile) {
const val = await this.doubanPlugin.fileHandler.getFileContent(syncConfig.templateFile);
if (val) {
return val;
}
}
const tempKey: TemplateKey = this.getTemplateKey();
const templatePath: string = context.settings[tempKey];
let useUserState:boolean = context.userComponent.isLogin() &&
@ -349,25 +375,11 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
if(!html('.nav-user-account')) {
return {data: html, userState: null};
}
let rate = html(html('input#n_rating').get(0)).val();
let tagsStr = html(html('div#interest_sect_level > div.a_stars > span.color_gray').get(0)).text().trim();
let tags = tagsStr.replace('标签:', '').split(' ');
let stateWord = html(html('div#interest_sect_level > div.a_stars > span.mr10').get(0)).text().trim();
let collectionDateStr = html(html('div#interest_sect_level > div.a_stars > span.mr10 > span.collection_date').get(0)).text().trim();
let userState1 = DoubanAbstractLoadHandler.getUserState(stateWord);
let component = html(html('div#interest_sect_level > div.a_stars > span.color_gray').get(0)).next().next().text().trim();
const userState: UserStateSubject = {
tags: tags,
rate: rate?Number(rate):null,
state: userState1,
collectionDate: collectionDateStr?moment(collectionDateStr, 'YYYY-MM-DD').toDate():null,
comment: component
}
return {data: html, userState: userState};
return this. analysisUser(html, context);
}
abstract analysisUser(html: CheerioAPI, context: HandleContext): {data:CheerioAPI , userState: UserStateSubject};
public static getUserState(stateWord:string):DoubanSubjectState {
let state:DoubanSubjectState;

@ -6,6 +6,8 @@ import DoubanSubject from "../model/DoubanSubject";
import {SupportType, TemplateTextMode} from "../../../constant/Constsant";
import HandleContext from "../model/HandleContext";
import StringUtil from "../../../utils/StringUtil";
import {UserStateSubject} from "../model/UserStateSubject";
import {moment} from "obsidian";
export default class DoubanBookLoadHandler extends DoubanAbstractLoadHandler<DoubanBookSubject> {
@ -44,7 +46,28 @@ export default class DoubanBookLoadHandler extends DoubanAbstractLoadHandler<Dou
.replace(']', '/');
}
parseSubjectFromHtml(html: CheerioAPI): DoubanBookSubject {
analysisUser(html: CheerioAPI, context: HandleContext): {data:CheerioAPI , userState: UserStateSubject} {
let rate = html('input#n_rating').val();
let tagsStr = html('span#rating').next().text().trim();
let tags = tagsStr ? tagsStr.replace('标签:', '').trim().split(' ') : null;
let stateWord = html('div#interest_sect_level > div.a_stars > span.mr10').text().trim();
let collectionDateStr = html('div#interest_sect_level > div.a_stars > span.mr10').next().text().trim();
let userState1 = DoubanAbstractLoadHandler.getUserState(stateWord);
let component = html('span#rating').next().next().next().text().trim();
const userState: UserStateSubject = {
tags: tags,
rate: rate?Number(rate):null,
state: userState1,
collectionDate: collectionDateStr?moment(collectionDateStr, 'YYYY-MM-DD').toDate():null,
comment: component
}
return {data: html, userState: userState};
}
parseSubjectFromHtml(html: CheerioAPI, context: HandleContext): DoubanBookSubject {
let desc = html(html("head > meta[property= 'og:description']").get(0)).attr("content");
let image = html(html("head > meta[property= 'og:image']").get(0)).attr("content");
let item = html(html("head > script[type='application/ld+json']").get(0)).text();

@ -5,7 +5,9 @@ import DoubanSubject from '../model/DoubanSubject';
import DoubanGameSubject from '../model/DoubanGameSubject';
import StringUtil from "../../../utils/StringUtil";
import HandleContext from "../model/HandleContext";
import {SupportType, TemplateKey} from "../../../constant/Constsant";
import {PersonNameMode, SupportType, TemplateKey} from "../../../constant/Constsant";
import {UserStateSubject} from "../model/UserStateSubject";
import {moment} from "obsidian";
export default class DoubanGameLoadHandler extends DoubanAbstractLoadHandler<DoubanGameSubject> {
@ -29,8 +31,30 @@ export default class DoubanGameLoadHandler extends DoubanAbstractLoadHandler<Dou
return extract && extract.type && (extract.type.contains("游戏") || extract.type.contains("Game") || extract.type.contains("game"));
}
parseSubjectFromHtml(html: CheerioAPI): DoubanGameSubject {
analysisUser(html: CheerioAPI, context: HandleContext): {data:CheerioAPI , userState: UserStateSubject} {
let rate = html('input#n_rating').val();
const rating = html('span#rating');
const tagsStr = rating.parent().next().text().trim();
const tags = tagsStr ? tagsStr.replace('标签:', '').trim().split(' ') : null;
const collected = html('div.collection-section > div.collection-rating-stars > div.collection-collected');
const stateWord = collected.find('span.collection-result').text().trim();
const collectionDateStr = collected.find('span.color_gray').text().trim();
const userState1 = DoubanAbstractLoadHandler.getUserState(stateWord);
const component = rating.parent().next().next().text().trim();
const userState: UserStateSubject = {
tags: tags,
rate: rate?Number(rate):null,
state: userState1,
collectionDate: collectionDateStr?moment(collectionDateStr, 'YYYY-MM-DD').toDate():null,
comment: component
}
return {data: html, userState: userState};
}
parseSubjectFromHtml(html: CheerioAPI, context: HandleContext): DoubanGameSubject {
let title = html(html("#content > h1").get(0)).text();
title = this.getPersonNameByMode(title, PersonNameMode.CH_NAME);
let idContent = html(html("head > meta[name= 'mobile-agent']").get(0)).attr("content");
let idPattern = /(\d){5,10}/g;
let idP = idPattern.exec(idContent);

@ -7,6 +7,8 @@ import DoubanMovieSubject from '../model/DoubanMovieSubject';
import StringUtil from "../../../utils/StringUtil";
import HandleContext from "../model/HandleContext";
import {PersonNameMode, SupportType, TemplateKey} from "../../../constant/Constsant";
import {UserStateSubject} from "../model/UserStateSubject";
import {moment} from "obsidian";
export default class DoubanMovieLoadHandler extends DoubanAbstractLoadHandler<DoubanMovieSubject> {
@ -25,6 +27,11 @@ export default class DoubanMovieLoadHandler extends DoubanAbstractLoadHandler<Do
.replaceAll("{{director}}", extract.director ? extract.director.map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, context)).filter(c => c).join(settings.arraySpilt) : "")
.replaceAll("{{actor}}", extract.actor ? extract.actor.map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, context)).filter(c => c).join(settings.arraySpilt) : "")
.replaceAll("{{author}}", extract.author ? extract.author.map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, context)).filter(c => c).join(settings.arraySpilt) : "")
.replaceAll("{{aliases}}", extract.aliases ? extract.aliases.join(settings.arraySpilt) : "")
.replaceAll("{{country}}", extract.country ? extract.country.join(settings.arraySpilt) : "")
.replaceAll("{{language}}", extract.language ? extract.language.join(settings.arraySpilt) : "")
.replaceAll("{{IMDb}}", extract.IMDb ? extract.IMDb : "")
.replaceAll("{{time}}", extract.time ? extract.time : "")
;
}
@ -32,19 +39,40 @@ export default class DoubanMovieLoadHandler extends DoubanAbstractLoadHandler<Do
return extract && extract.type && (extract.type.contains("电影") || extract.type.contains("Movie") || extract.type.contains("movie"));
}
parseSubjectFromHtml(data: CheerioAPI): DoubanMovieSubject {
return data('script')
analysisUser(html: CheerioAPI, context: HandleContext): {data:CheerioAPI , userState: UserStateSubject} {
let rate = html('input#n_rating').val();
let tagsStr = html('div#interest_sect_level > div.a_stars > span.color_gray').text().trim();
let tags = tagsStr ? tagsStr.replace('标签:', '').trim().split(' ') : null;
let stateWord = html('div#interest_sect_level > div.a_stars > span.mr10').text().trim();
let collectionDateStr = html('div#interest_sect_level > div.a_stars > span.mr10 > span.collection_date').text().trim();
let userState1 = DoubanAbstractLoadHandler.getUserState(stateWord);
let component = html('div#interest_sect_level > div.a_stars > span.color_gray').next().next().text().trim();
const userState: UserStateSubject = {
tags: tags,
rate: rate?Number(rate):null,
state: userState1,
collectionDate: collectionDateStr?moment(collectionDateStr, 'YYYY-MM-DD').toDate():null,
comment: component
}
return {data: html, userState: userState};
}
parseSubjectFromHtml(html: CheerioAPI, context: HandleContext): DoubanMovieSubject {
const movie:DoubanMovieSubject = html('script')
.get()
.filter(scd => "application/ld+json" == data(scd).attr("type"))
.filter(scd => "application/ld+json" == html(scd).attr("type"))
.map(i => {
let item = data(i).text();
let item = html(i).text();
item = super.html_decode(item);
let obj = JSON.parse(item.replace(/[\r\n\s+]/g, ''));
let idPattern = /(\d){5,10}/g;
let id = idPattern.exec(obj.url);
let name = obj.name;
let title = super.getPersonNameByMode(name, PersonNameMode.CH_NAME)??name;
let originalTitle = super.getPersonNameByMode(name, PersonNameMode.EN_NAME) ?? name;
let title = super.getTitleNameByMode(name, PersonNameMode.CH_NAME, context)??name;
let originalTitle = super.getTitleNameByMode(name, PersonNameMode.EN_NAME, context) ?? name;
const result: DoubanMovieSubject = {
id: id ? id[0] : '',
@ -61,12 +89,50 @@ export default class DoubanMovieLoadHandler extends DoubanAbstractLoadHandler<Do
datePublished: obj.datePublished ? new Date(obj.datePublished) : undefined,
image: obj.image,
genre: obj.genre,
publisher: ''
publisher: '',
aliases: [""],
language: [""],
country: [],
time: null,
IMDb: null,
}
return result;
})[0];
let detailDom = html(html("#info").get(0));
let publish = detailDom.find("span.pl");
let valueMap = new Map<string, any>();
publish.map((index, info) => {
let key = html(info).text().trim();
let value;
if (key.indexOf('又名') >= 0 || key.indexOf('语言') >= 0 || key.indexOf('制片国家') >= 0) {
// value = html(info.next.next).text().trim();
let vas = html(info.next).text().trim();
value = vas.split("/").map((v) => v.trim());
} else if(key.indexOf('片长') >= 0) {
value = html(info.next.next).text().trim()
} else {
value = html(info.next).text().trim();
}
valueMap.set(MovieKeyValueMap.get(key), value);
})
movie.country = valueMap.has('country') ? valueMap.get('country') : [];
movie.language = valueMap.has('language') ? valueMap.get('language') : [];
movie.time = valueMap.has('time') ? valueMap.get('time') : "";
movie.aliases = valueMap.has('aliases') ? valueMap.get('aliases') : [];
movie.IMDb = valueMap.has('IMDb') ? valueMap.get('IMDb') : "";
return movie;
}
}
const MovieKeyValueMap: Map<string, string> = new Map(
[['制片国家/地区:', 'country'],
['语言:', 'language'],
['片长:', 'time'],
['又名:', 'aliases'],
['IMDb:', 'IMDb']
]
);

@ -5,6 +5,8 @@ import DoubanPlugin from "../../../main";
import DoubanSubject from '../model/DoubanSubject';
import HandleContext from "../model/HandleContext";
import {SupportType, TemplateKey} from "../../../constant/Constsant";
import {UserStateSubject} from "../model/UserStateSubject";
import {moment} from "obsidian";
export default class DoubanMusicLoadHandler extends DoubanAbstractLoadHandler<DoubanMusicSubject> {
@ -31,7 +33,26 @@ export default class DoubanMusicLoadHandler extends DoubanAbstractLoadHandler<Do
return extract && extract.type && (extract.type.contains("音乐") || extract.type.contains("Music") || extract.type.contains("music"));
}
parseSubjectFromHtml(html: CheerioAPI): DoubanMusicSubject {
analysisUser(html: CheerioAPI, context: HandleContext): {data:CheerioAPI , userState: UserStateSubject} {
let rate = html('input#n_rating').val();
let tagsStr = html('span#rating').next().next().text().trim();
let tags = tagsStr ? tagsStr.replace('标签:', '').trim().split(' ') : null;
let stateWord = html('div#interest_sect_level > div.a_stars > span.mr10').text().trim();
let collectionDateStr = html('div#interest_sect_level > div.a_stars > span.mr10').next().text().trim();
let userState1 = DoubanAbstractLoadHandler.getUserState(stateWord);
let component = html('span#rating').next().next().next().next().text().trim();
const userState: UserStateSubject = {
tags: tags,
rate: rate?Number(rate):null,
state: userState1,
collectionDate: collectionDateStr?moment(collectionDateStr, 'YYYY-MM-DD').toDate():null,
comment: component
}
return {data: html, userState: userState};
}
parseSubjectFromHtml(html: CheerioAPI, context: HandleContext): DoubanMusicSubject {
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");

@ -6,6 +6,8 @@ import DoubanSubject from '../model/DoubanSubject';
import html2markdown from '@notable/html2markdown';
import HandleContext from "../model/HandleContext";
import {SupportType, TemplateKey} from "../../../constant/Constsant";
import {UserStateSubject} from "../model/UserStateSubject";
import {moment} from "obsidian";
export default class DoubanNoteLoadHandler extends DoubanAbstractLoadHandler<DoubanNoteSubject> {
@ -29,7 +31,27 @@ export default class DoubanNoteLoadHandler extends DoubanAbstractLoadHandler<Dou
return extract && extract.type && (extract.type.contains("日记") || extract.type.contains("Note") || extract.type.contains("Article"));
}
parseSubjectFromHtml(html: CheerioAPI): DoubanNoteSubject {
analysisUser(html: CheerioAPI, context: HandleContext): {data:CheerioAPI , userState: UserStateSubject} {
let rate = html(html('input#n_rating').get(0)).val();
let tagsStr = html(html('div#interest_sect_level > div.a_stars > span.color_gray').get(0)).text().trim();
let tags = tagsStr.replace('标签:', '').split(' ');
let stateWord = html(html('div#interest_sect_level > div.a_stars > span.mr10').get(0)).text().trim();
let collectionDateStr = html(html('div#interest_sect_level > div.a_stars > span.mr10 > span.collection_date').get(0)).text().trim();
let userState1 = DoubanAbstractLoadHandler.getUserState(stateWord);
let component = html(html('div#interest_sect_level > div.a_stars > span.color_gray').get(0)).next().next().text().trim();
const userState: UserStateSubject = {
tags: tags,
rate: rate?Number(rate):null,
state: userState1,
collectionDate: collectionDateStr?moment(collectionDateStr, 'YYYY-MM-DD').toDate():null,
comment: component
}
return {data: html, userState: userState};
}
parseSubjectFromHtml(html: CheerioAPI, context: HandleContext): DoubanNoteSubject {
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");

@ -5,6 +5,7 @@ import {i18nHelper} from "src/org/wanxp/lang/helper";
import {log} from "src/org/wanxp/utils/Logutil";
import HandleContext from "../model/HandleContext";
import {SupportType, TemplateKey} from "../../../constant/Constsant";
import {UserStateSubject} from "../model/UserStateSubject";
/**
*
@ -23,9 +24,13 @@ export default class DoubanOtherLoadHandler extends DoubanAbstractLoadHandler<Do
return false;
}
parseSubjectFromHtml(data: CheerioAPI): DoubanSubject {
parseSubjectFromHtml(data: CheerioAPI, context: HandleContext): DoubanSubject {
return undefined;
}
analysisUser(html: CheerioAPI, context: HandleContext): { data: CheerioAPI; userState: UserStateSubject } {
return {data: undefined, userState: undefined};
}
}

@ -41,9 +41,9 @@ export class DoubanSearchChooseItemHandler {
let doubanSubjectHandlers: DoubanSubjectLoadHandler<DoubanSubject>[] = this._doubanSubjectHandlers
.filter(h => h.support(searchExtract));
if (doubanSubjectHandlers && doubanSubjectHandlers.length > 0) {
doubanSubjectHandlers[0].handle(searchExtract.url, context);
await doubanSubjectHandlers[0].handle(searchExtract.url, context);
} else {
this._doubanSubjectHandlerDefault.handle(searchExtract.url, context);
await this._doubanSubjectHandlerDefault.handle(searchExtract.url, context);
}
}

@ -5,7 +5,10 @@ import DoubanSubject from "../model/DoubanSubject";
import DoubanTeleplaySubject from "../model/DoubanTeleplaySubject";
import SchemaOrg from "src/org/wanxp/utils/SchemaOrg";
import HandleContext from "../model/HandleContext";
import {SupportType, TemplateKey} from "../../../constant/Constsant";
import {PersonNameMode, SupportType, TemplateKey} from "../../../constant/Constsant";
import {aliases} from "css-select";
import {UserStateSubject} from "../model/UserStateSubject";
import {moment} from "obsidian";
/**
* teleplay
@ -27,29 +30,51 @@ export class DoubanTeleplayLoadHandler extends DoubanAbstractLoadHandler<DoubanT
.replaceAll("{{director}}", extract.director ? extract.director.map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, context)).filter(c => c).join(settings.arraySpilt) : "")
.replaceAll("{{actor}}", extract.actor ? extract.actor.map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, context)).filter(c => c).join(settings.arraySpilt) : "")
.replaceAll("{{author}}", extract.author ? extract.author.map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, context)).filter(c => c).join(settings.arraySpilt) : "")
.replaceAll("{{aliases}}", extract.aliases ? extract.aliases.join(settings.arraySpilt) : "")
.replaceAll("{{country}}", extract.country ? extract.country.join(settings.arraySpilt) : "")
.replaceAll("{{language}}", extract.language ? extract.language.join(settings.arraySpilt) : "")
.replaceAll("{{IMDb}}", extract.IMDb ? extract.IMDb : "")
.replaceAll("{{time}}", extract.time ? extract.time : "")
.replaceAll("{{episode}}", extract.episode ? extract.episode : "")
;
}
support(extract: DoubanSubject): boolean {
return extract && extract.type && (extract.type.contains("电视剧") || extract.type.contains("Teleplay") || extract.type.contains("teleplay"));
}
analysisUser(html: CheerioAPI, context: HandleContext): {data:CheerioAPI , userState: UserStateSubject} {
let rate = html('input#n_rating').val();
const rating = html('span#rating');
let tagsStr = rating.next().next().text().trim();
let tags = tagsStr ? tagsStr.replace('标签:', '').trim().split(' ') : null;
let stateWord = html('div#interest_sect_level > div.a_stars > span.mr10').text().trim();
let collectionDateStr = html('div#interest_sect_level > div.a_stars > span.mr10 > span.collection_date').text().trim();
let userState1 = DoubanAbstractLoadHandler.getUserState(stateWord);
let component = rating.next().next().next().next().text().trim();
const userState: UserStateSubject = {
tags: tags,
rate: rate?Number(rate):null,
state: userState1,
collectionDate: collectionDateStr?moment(collectionDateStr, 'YYYY-MM-DD').toDate():null,
comment: component
}
return {data: html, userState: userState};
}
parseSubjectFromHtml(data: CheerioAPI): DoubanTeleplaySubject {
return data('script')
parseSubjectFromHtml(html: CheerioAPI, context: HandleContext): DoubanTeleplaySubject {
const teleplay:DoubanTeleplaySubject = html('script')
.get()
.filter(scd => "application/ld+json" == data(scd).attr("type"))
.filter(scd => "application/ld+json" == html(scd).attr("type"))
.map(i => {
let item = data(i).text();
let item = html(i).text();
item = super.html_decode(item);
let obj = JSON.parse(item.replace(/[\r\n\s+]/g, ''));
let idPattern = /(\d){5,10}/g;
let id = idPattern.exec(obj.url);
let name = obj.name;
let titleExec = /[\u4e00-\u9fa5]{2,20}/g.exec(name);
let title = titleExec ? titleExec[0] : name;
let originalTitleExec = /[a-zA-Z.\s\-]{2,50}/g.exec(name);
let originalTitle = originalTitleExec ? originalTitleExec[0] : name;
let title = super.getTitleNameByMode(name, PersonNameMode.CH_NAME, context)??name;
let originalTitle = super.getTitleNameByMode(name, PersonNameMode.EN_NAME, context) ?? name;
const result: DoubanTeleplaySubject = {
id: id ? id[0] : '',
@ -66,10 +91,52 @@ export class DoubanTeleplayLoadHandler extends DoubanAbstractLoadHandler<DoubanT
image: obj.image,
genre: obj.genre,
score: obj.aggregateRating ? obj.aggregateRating.ratingValue : undefined,
publisher: ""
publisher: "",
aliases: [""],
language: [""],
country: [],
episode: null,
time: null,
IMDb: null,
}
return result;
})[0];
let detailDom = html(html("#info").get(0));
let publish = detailDom.find("span.pl");
let valueMap = new Map<string, any>();
publish.map((index, info) => {
let key = html(info).text().trim();
let value;
if (key.indexOf('又名') >= 0 || key.indexOf('语言') >= 0 || key.indexOf('制片国家') >= 0) {
// value = html(info.next.next).text().trim();
let vas = html(info.next).text().trim();
value = vas.split("/").map((v) => v.trim());
} else if(key.indexOf('单集片长') >= 0) {
value = html(info.next.next).text().trim()
}else {
value = html(info.next).text().trim();
}
valueMap.set(TeleplayKeyValueMap.get(key), value);
})
teleplay.country = valueMap.has('country') ? valueMap.get('country') : [];
teleplay.language = valueMap.has('language') ? valueMap.get('language') : [];
teleplay.episode = valueMap.has('episode') ? valueMap.get('episode') : "";
teleplay.time = valueMap.has('time') ? valueMap.get('time') : "";
teleplay.aliases = valueMap.has('aliases') ? valueMap.get('aliases') : [];
teleplay.IMDb = valueMap.has('IMDb') ? valueMap.get('IMDb') : "";
return teleplay;
}
}
const TeleplayKeyValueMap: Map<string, string> = new Map(
[['制片国家/地区:', 'country'],
['语言:', 'language'],
['集数:', 'episode'],
['单集片长:', 'time'],
['又名:', 'aliases'],
['IMDb:', 'IMDb']
]
);

@ -8,5 +8,9 @@ export default class DoubanMovieSubject extends DoubanSubject {
actor: Person[];
aggregateRating: AggregateRating;
originalTitle: string;
aliases: string[];
language: string[];
country: string[];
time: string;
IMDb: string;
}

@ -8,4 +8,10 @@ export default class DoubanTeleplaySubject extends DoubanSubject {
actor: Person[];
aggregateRating: AggregateRating;
originalTitle: string;
aliases: string[];
language: string[];
country: string[];
episode: string;
time: string;
IMDb: string;
}

@ -6,6 +6,7 @@ import NetFileHandler from "src/org/wanxp/net/NetFileHandler";
import DoubanPlugin from "../../../main";
import SyncStatusHolder from "../../sync/model/SyncStatusHolder";
import {SyncConfig} from "../../sync/model/SyncConfig";
import DoubanSubject from "./DoubanSubject";
export default interface HandleContext {
plugin:DoubanPlugin;
@ -18,4 +19,5 @@ export default interface HandleContext {
syncStatusHolder?:SyncStatusHolder;
action:string;
syncConfig?: SyncConfig;
listItem?:DoubanSubject;
}

@ -34,6 +34,7 @@ class DoubanFuzzySuggester extends FuzzySuggestModal<DoubanSearchResultSubject>
onChooseItem(item: DoubanSearchResultSubject, evt: MouseEvent | KeyboardEvent): void {
this.plugin.showStatus(i18nHelper.getMessage('140204', item.title));
this.context.listItem = item;
this.plugin.doubanExtractHandler.handle(item, this.context);
}

@ -247,6 +247,28 @@ ${i18nHelper.getMessage('122004')}
<td>${i18nHelper.getMessage('310618')}</th>
<td>${i18nHelper.getMessage('310718')}</th>
</tr>
<tr>
<td>${i18nHelper.getMessage('320109')}</th>
<td>${i18nHelper.getMessage('310119')}</th>
<td>${i18nHelper.getMessage('310219')}</th>
<td>${i18nHelper.getMessage('310319')}</th>
<td>${i18nHelper.getMessage('310419')}</th>
<td>${i18nHelper.getMessage('310519')}</th>
<td>${i18nHelper.getMessage('310619')}</th>
<td>${i18nHelper.getMessage('310719')}</th>
</tr>
<tr>
<td>${i18nHelper.getMessage('320110')}</th>
<td>${i18nHelper.getMessage('310120')}</th>
<td>${i18nHelper.getMessage('310220')}</th>
<td>${i18nHelper.getMessage('310320')}</th>
<td>${i18nHelper.getMessage('310420')}</th>
<td>${i18nHelper.getMessage('310520')}</th>
<td>${i18nHelper.getMessage('310620')}</th>
<td>${i18nHelper.getMessage('310720')}</th>
</tr>
</table>`;

@ -5,10 +5,11 @@ import DoubanPageBroadcastSubject from '../model/DoubanPageBroadcastSubject';
import DoubanPlugin from "../../../main";
import DoubanSubject from 'src/org/wanxp/douban/data/model/DoubanSubject';
import HandleContext from "../../data/model/HandleContext";
import {SupportType, TemplateKey} from "../../../constant/Constsant";
import {SupportType} from "../../../constant/Constsant";
import { UserStateSubject } from '../../data/model/UserStateSubject';
//TODO will support in future version
class DoubanPageBroadcatLoadHandler extends DoubanAbstractLoadHandler<DoubanPageBroadcastSubject> {
class DoubanPageBroadcastLoadHandler extends DoubanAbstractLoadHandler<DoubanPageBroadcastSubject> {
constructor(doubanPlugin: DoubanPlugin) {
super(doubanPlugin);
@ -26,9 +27,13 @@ class DoubanPageBroadcatLoadHandler extends DoubanAbstractLoadHandler<DoubanPage
return extract && extract.type && (extract.type.contains("广播") || extract.type.contains("Broadcast"));
}
parseSubjectFromHtml(html: CheerioAPI): DoubanPageBroadcastSubject {
parseSubjectFromHtml(html: CheerioAPI, context: HandleContext): DoubanPageBroadcastSubject {
return null;
}
analysisUser(html: CheerioAPI, context: HandleContext): { data: CheerioAPI; userState: UserStateSubject } {
return {data: undefined, userState: undefined};
}
}

@ -1,24 +1,13 @@
import HandleContext from "../../data/model/HandleContext";
import {SyncConfig} from "../model/SyncConfig";
import DoubanPlugin from "../../../main";
import {App} from "obsidian";
import {App, moment} from "obsidian";
import {DoubanSyncHandler} from "./DoubanSyncHandler";
import DoubanOtherLoadHandler from "../../data/handler/DoubanOtherLoadHandler";
import DoubanMovieLoadHandler from "../../data/handler/DoubanMovieLoadHandler";
import DoubanBookLoadHandler from "../../data/handler/DoubanBookLoadHandler";
import {DoubanTeleplayLoadHandler} from "../../data/handler/DoubanTeleplayLoadHandler";
import DoubanMusicLoadHandler from "../../data/handler/DoubanMusicLoadHandler";
import DoubanNoteLoadHandler from "../../data/handler/DoubanNoteLoadHandler";
import DoubanGameLoadHandler from "../../data/handler/DoubanGameLoadHandler";
import { DoubanBroadcastSyncHandler } from "./DoubanBroadcastSyncHandler";
import {DoubanOtherSyncHandler} from "./DoubanOtherSyncHandler";
import { DoubanMovieSyncHandler } from "./DoubanMovieSyncHandler";
import { DoubanNoteSyncHandler } from "./DoubanNoteSyncHandler";
import { DoubanMusicSyncHandler } from "./DoubanMusicSyncHandler";
import { DoubanBookSyncHandler } from "./DoubanBookSyncHandler";
import DoubanSubjectLoadHandler from "../../data/handler/DoubanSubjectLoadHandler";
import DoubanSubject from "../../data/model/DoubanSubject";
import {DoubanAbstractSyncHandler} from "./DoubanAbstractSyncHandler";
import {i18nHelper} from "../../../lang/helper";
export default class SyncHandler {
private app: App;
@ -54,5 +43,31 @@ export default class SyncHandler {
await this.defaultSyncHandler.sync(this.syncConfig, this.context);
}
}
await this.showResult();
}
async showResult() {
const {syncStatusHolder} = this.context;
const {statusHandleMap} = syncStatusHolder;
const {syncResultMap} = syncStatusHolder;
let summary:string = `${i18nHelper.getMessage('syncall')}: ${syncStatusHolder.getTotal()}
`;
for (const [key, value] of statusHandleMap) {
// @ts-ignore
summary+= `${i18nHelper.getMessage(key)}: ${value}
`;
}
let details:string = '';
for (const [key, value] of syncResultMap) {
// @ts-ignore
details+= `${value.id}-[[${value.title}]]: ${i18nHelper.getMessage(value.status)}
`;
}
summary+= `${i18nHelper.getMessage('notsync')}: ${syncStatusHolder.getTotal() - syncStatusHolder.getHandle()}
`
const result : string = i18nHelper.getMessage('110037', summary, details);
const resultFileName = `${i18nHelper.getMessage('110038')}_${moment(new Date()).format('YYYYMMDDHHmmss')}`
await this.plugin.fileHandler.createNewNoteWithData(`${this.syncConfig.dataFilePath}/${resultFileName}`, result, true);
}
}

@ -9,7 +9,7 @@ export default class GlobalSyncStatusHolder {
constructor(syncConfig: SyncConfig) {
this.syncConfig = syncConfig;
this.total = 100;
this.handle = 1;
this.handle = 0;
}
handled(num:number) {

@ -6,4 +6,5 @@ export interface SyncConfig {
dataFileNamePath:string;
cacheImage:boolean;
attachmentPath:string;
templateFile:string;
}

@ -6,8 +6,8 @@ import GlobalStatusHolder from "../../model/GlobalStatusHolder";
export default class SyncStatusHolder extends GlobalSyncStatusHolder{
private syncResultMap: Map<string, SyncItemResult> = new Map();
private statusHandleMap: Map<SyncItemStatus, number> = new Map([
public syncResultMap: Map<string, SyncItemResult> = new Map();
public statusHandleMap: Map<SyncItemStatus, number> = new Map([
[SyncItemStatus.exists, 0],
[SyncItemStatus.replace, 0],
[SyncItemStatus.create, 0],

@ -112,8 +112,9 @@ export default class FileHandler {
* 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`)
* @return true if the file was successfully created
*/
async createNewNoteWithData(originalFilePath: string, data:string, showAfterCreate:boolean=false): Promise<void> {
async createNewNoteWithData(originalFilePath: string, data:string, showAfterCreate:boolean=false, showExistsError:boolean = true): Promise<boolean> {
const {vault} = this._app;
const {adapter} = vault;
const prependDirInput = FileUtil.join("", originalFilePath);
@ -122,6 +123,9 @@ export default class FileHandler {
const fileExists = await adapter.exists(filePath);
if (fileExists) {
if (!showExistsError) {
return false;
}
// If the file already exists, respond with error
throw new Error(i18nHelper.getMessage('110201').replace('{0}', filePath??''));
}
@ -135,6 +139,7 @@ export default class FileHandler {
const leaf = this._app.workspace.splitLeafOrActive();
await leaf.openFile(File);
}
return true;
}
/**

@ -22,9 +22,23 @@ export default {
'110034': `OutputFolder:`,
'110035': `FileName: (Tip:Support Variables And Path)`,
'110036': `Complete`,
'110037': `
### Summary
{0}
### Details
{1}
---
PS: This file could be delete if you want to.
`,
'110038': `DoubanSyncResult`,
'exists':`[exists]`,
'replace':`[replace]`,
'create':`[create]`,
'fail':`[fail]`,
'notsync':`[notSync]`,
'syncall':`[summary]`,
//DoubanSettingTab
'1201': `Obsidian Douban`,
@ -74,6 +88,9 @@ export default {
'124106': `Active type`,
'124107': `Delete custom variable`,
'121101': `Template File`,
'121102': `This template will be used when creating new notes. If keep empty, it will use default template`,
'120101': `Movie Template File`,
'120102': `This template will be used when creating new notes for Movie from Obsidian-Douban.`,
'120103': `Available template variables are :`,
@ -242,7 +259,8 @@ export default {
'310116': `totalPage:页数`,
'310117': `binding:装帧`,
'310118': `producer:出品方`,
'310119': `-`,
'310120': `-`,
//电影
'310201': `豆瓣ID`,
'310202': `电影名称`,
@ -251,17 +269,19 @@ export default {
'310205': `封面`,
'310206': `豆瓣网址`,
'310207': `简介`,
'310208': `(未知)`,
'310208': ``,
'310209': `上映日期`,
'310210': `类型`,
'310211': `director:导演`,
'310212': `author:编剧`,
'310213': `actor:主演`,
'310214': `originalTitle:原作名`,
'310215': `-`,
'310216': `-`,
'310217': `-`,
'310218': `-`,
'310215': `country:国家`,
'310216': `language:语言`,
'310217': `time:片长`,
'310218': `aliases:又名`,
'310219': `IMDb`,
'310220': `-`,
//电视剧
@ -279,10 +299,12 @@ export default {
'310312': `author:编剧`,
'310313': `actor:主演`,
'310314': `originalTitle:原作名`,
'310315': `-`,
'310316': `-`,
'310317': `-`,
'310318': `-`,
'310315': `country:国家`,
'310316': `language:语言`,
'310317': `time:片长`,
'310318': `aliases:又名`,
'310319': `IMDb`,
'310320': `episode:集数`,
@ -305,7 +327,8 @@ export default {
'310416': `-`,
'310417': `-`,
'310418': `-`,
'310419': `-`,
'310420': `-`,
//日记
'310501': `豆瓣ID`,
'310502': `日记标题`,
@ -325,7 +348,8 @@ export default {
'310516': `-`,
'310517': `-`,
'310518': `-`,
'310519': `-`,
'310520': `-`,
//游戏
'310601': `豆瓣ID`,
'310602': `游戏名称`,
@ -345,7 +369,8 @@ export default {
'310616': `-`,
'310617': `-`,
'310618': `-`,
'310619': `-`,
'310620': `-`,
//广播
'310701': `待开发`,
'310702': `待开发`,
@ -365,6 +390,9 @@ export default {
'310716': `-`,
'310717': `-`,
'310718': `-`,
'310719': `-`,
'310720': `-`,
'320101': `扩展1`,
'320102': `扩展2`,
@ -377,6 +405,8 @@ export default {
'320109': `扩展9`,
'320110': `扩展10`,
'320111': `扩展11`,
'320112': `扩展12`,
'320113': `扩展13`,
'330101': `今日日期`,
'330102': `当前时间`,

@ -1,5 +1,7 @@
//简体中文
import {SyncItemStatus} from "../../constant/Constsant";
export default {
//main.ts
'110001': '搜索豆瓣当前文档名并写入',
@ -22,7 +24,24 @@ export default {
'110034': `输出文件夹:`,
'110035': `文档名: (提示:支持参数化以及多级路径, 可用参数见配置界面)`,
'110036': `完成`,
'110037': `
###
{0}
###
{1}
---
:此文档可删除
`,
'110038': `豆瓣同步结果`,
'exists':`[未替换]`,
'replace':`[已替换]`,
'create':`[已创建]`,
'fail':`[失败]`,
'notsync':`[未进行]`,
'syncall':`[总数]`,
'110201': `{0} 文件已经存在.`,
'110202': `{0} 模板文件无法读取`,
@ -47,9 +66,6 @@ export default {
'100131': `登录豆瓣`,
'100132': `加载豆瓣登录页面失败`,
//DoubanSettingTab
'1201': `Obsidian-豆瓣`,
'120001': `豆瓣搜索地址`,
@ -64,7 +80,7 @@ export default {
'1220': `输出配置`,
'1230': `可用参数`,
'1204': `配置对应类型的模板文件, 如果为空则使用默认的文件模板. 模板可使用的参数列举在最下面.👇 `,
'1204': `配置对应类型的模板文件, 如果为空则使用默认模板. 模板可使用的参数列举在最下面.👇 `,
'1205': `🧡提示: 建议点击右侧'复制'默认模板按钮, 然后在新建的文件中粘贴修改模板, 最后回到此处选择对应模板. `,
'1240': `自定义属性`,
'1241': `自定义参数使用时请用'{{}}'包裹, 举例: 参数myType, 则使用时为{{myType}}. `,
@ -78,6 +94,8 @@ export default {
'124106': `生效类型`,
'124107': `删除自定义参数`,
'121101': `模板文件`,
'121102': `如果为空, 笔记将会会使用默认模板`,
'120101': `电影模板文件`,
'120102': `设置选择电影后导入的文本内容模板文件. `,
@ -105,7 +123,7 @@ export default {
'120307': `{{barcode}}, {{records}}`,
'120401': `日记模板文件`,
'120402': `设置选择电影后导入内容的模板文件. `,
'120402': `设置选择日记后导入内容的模板文件. `,
'120403': `支持以下参数名称 :`,
'120404': `{{id}}, {{title}}, {{type}}, {{image}},`,
'120405': `{{url}}, {{desc}}, {{datePublished}}`,
@ -113,7 +131,7 @@ export default {
'120407': `{{timePublished}}`,
'121301': `游戏模板文件`,
'121302': `选择电影后导入内容的模板文件. `,
'121302': `选择游戏后导入内容的模板文件. `,
'121303': `支持以下参数名称 :`,
'121304': `{{id}}, {{title}}, {{type}}, {{score}}, {{image}},`,
'121305': `{{url}}, {{desc}}, {{publisher}}, {{datePublished}}`,
@ -274,17 +292,19 @@ export default {
'310205': `封面`,
'310206': `豆瓣网址`,
'310207': `简介`,
'310208': `(固定值:未知)`,
'310208': ``,
'310209': `上映日期`,
'310210': `类型`,
'310211': `director:导演`,
'310212': `author:编剧`,
'310213': `actor:主演`,
'310214': `originalTitle:原作名`,
'310215': `-`,
'310216': `-`,
'310217': `-`,
'310218': `-`,
'310215': `country:国家`,
'310216': `language:语言`,
'310217': `time:片长`,
'310218': `aliases:又名`,
'310219': `IMDb`,
'310220': `-`,
//电视剧
@ -302,10 +322,12 @@ export default {
'310312': `author:编剧`,
'310313': `actor:主演`,
'310314': `originalTitle:原作名`,
'310315': `-`,
'310316': `-`,
'310317': `-`,
'310318': `-`,
'310315': `country:国家`,
'310316': `language:语言`,
'310317': `time:片长`,
'310318': `aliases:又名`,
'310319': `IMDb`,
'310320': `episode:集数`,
@ -444,7 +466,7 @@ export default {
'500704': `看过`,
'500004': `所有`,
'500110': `开启后,同步时若遇到同名文档则会覆盖`,
'500110': `开启后,同步时若遇到同路径下的同名文档则会覆盖`,

@ -101,12 +101,11 @@ export default class DoubanPlugin extends Plugin {
syncStatusHolder != null ?syncStatusHolder.create(subject.id, subject.title):null;
}
}else {
await this.fileHandler.createNewNoteWithData(filePath, content, context.showAfterCreate);
syncStatusHolder != null ?syncStatusHolder.create(subject.id, subject.title):null;
const created:boolean = await this.fileHandler.createNewNoteWithData(filePath, content, context.showAfterCreate, false);
created ?syncStatusHolder.create(subject.id, subject.title):syncStatusHolder.exists(subject.id, subject.title);
}
}else {
await this.fileHandler.createNewNoteWithData(filePath, content, context.showAfterCreate);
syncStatusHolder != null ?syncStatusHolder.create(subject.id, subject.title):null;
}
}

@ -27,6 +27,11 @@ class Logger {
return e;
}
public debug(e: any): any {
console.log(`OB-Douban:` + `${typeof e == 'string' ? e : JSON.stringify(e)}`);
return e;
}
public trace(e: any): any {
// return e;
console.log(`OB-Douban:` + `${typeof e == 'string' ? e : JSON.stringify(e)}`);

@ -18,5 +18,6 @@
"v1.7.0": "0.12.0",
"v1.7.1": "0.12.0",
"v1.7.2": "0.12.0",
"v1.7.3": "0.12.0"
"v1.7.3": "0.12.0",
"1.7.4": "0.12.0"
}