add function sync breakpoint resume

This commit is contained in:
wanxp 2022-11-30 23:58:11 +08:00
parent 594cd3a40b
commit 36b35db78d
19 changed files with 367 additions and 160 deletions

@ -5,11 +5,52 @@ import {i18nHelper} from "../lang/helper";
*/ */
export const BasicConst = { export const BasicConst = {
YAML_FRONT_MATTER_SYMBOL: '---', YAML_FRONT_MATTER_SYMBOL: '---',
/**
*
*/
CLEAN_STATUS_BAR_DELAY: 5000, CLEAN_STATUS_BAR_DELAY: 5000,
CALL_DOUBAN_DELAY: 3000, /**
CALL_DOUBAN_DELAY_RANGE: 3000, * ()
*/
CALL_DOUBAN_DELAY: 4000,
/**
* ()
*/
CALL_DOUBAN_DELAY_RANGE: 4000,
/**
* 403
*/
SLOW_SIZE: 200,
/**
* ()
*/
CALL_DOUBAN_DELAY_SLOW: 10000,
/**
* ()
*/
CALL_DOUBAN_DELAY_RANGE_SLOW: 5000,
} }
/**
*
* @private
*/
export const ESTIMATE_TIME_PER:number = 2000;
/**
* +()
* @private
*/
export const ESTIMATE_TIME_PER_WITH_REQUEST_SLOW:number = ESTIMATE_TIME_PER + BasicConst.CALL_DOUBAN_DELAY_SLOW + BasicConst.CALL_DOUBAN_DELAY_RANGE_SLOW / 2;
/**
* +()
* @private
*/
export const ESTIMATE_TIME_PER_WITH_REQUEST:number = ESTIMATE_TIME_PER + BasicConst.CALL_DOUBAN_DELAY + BasicConst.CALL_DOUBAN_DELAY_RANGE / 2;
/** /**
* *
*/ */
@ -93,9 +134,17 @@ export const SyncTypeRecords: { [key in SyncType]: string } = {
[SyncType.music]: i18nHelper.getMessage('504106'), [SyncType.music]: i18nHelper.getMessage('504106'),
} }
/**
*
*/
export const PAGE_SIZE:number = 30; export const PAGE_SIZE:number = 30;
/**
* 403
*/
/** /**
* *
*/ */
@ -111,5 +160,8 @@ export enum SyncItemStatus {
replace= 'replace', replace= 'replace',
create= 'create', create= 'create',
fail= 'fail', fail= 'fail',
unHandle='unHandle',
} }

@ -30,5 +30,5 @@ export const DEFAULT_SETTINGS: DoubanPluginSetting = {
loginCookiesContent: '', loginCookiesContent: '',
cacheImage: true, cacheImage: true,
attachmentPath: 'assets', attachmentPath: 'assets',
syncHandledData: new Map(), syncHandledDataArray: [],
} }

@ -20,6 +20,7 @@ import {DEFAULT_SETTINGS} from "../../constant/DefaultSettings";
import {createFileSelectionSetting} from "../setting/TemplateSettingHelper"; import {createFileSelectionSetting} from "../setting/TemplateSettingHelper";
import {FileSuggest} from "../setting/model/FileSuggest"; import {FileSuggest} from "../setting/model/FileSuggest";
import {getDefaultTemplateContent} from "../../constant/DefaultTemplateContent"; import {getDefaultTemplateContent} from "../../constant/DefaultTemplateContent";
import TimeUtil from "../../utils/TimeUtil";
export class DoubanSyncModal extends Modal { export class DoubanSyncModal extends Modal {
plugin: DoubanPlugin; plugin: DoubanPlugin;
@ -90,7 +91,7 @@ export class DoubanSyncModal extends Modal {
if (!this.plugin.statusHolder.syncStarted) { if (!this.plugin.statusHolder.syncStarted) {
progress.innerHTML = `<p> progress.innerHTML = `<p>
<label for="file">${i18nHelper.getMessage('110033')}</label> <label for="file">${i18nHelper.getMessage('110033')}</label>
<progress class="obsidian_douban_sync_slider" max="${syncStatus.getTotal() == 0 ? 1:syncStatus.getTotal()}" value="${syncStatus.getHandle()}"> </progress> <span> ${syncStatus.getHandle()}/${syncStatus.getTotal()}:${i18nHelper.getMessage('110036')} </span> <progress class="obsidian_douban_sync_slider" max="${syncStatus.getTotal() == 0 ? 1:syncStatus.getTotal()}" value="${syncStatus.getHasHandle()}"> </progress> <span> ${syncStatus.getHasHandle()}/${syncStatus.getTotal()}:${i18nHelper.getMessage('110036')} </span>
</p>` </p>`
backgroundButton.setDisabled(true); backgroundButton.setDisabled(true);
stopButton.setButtonText(i18nHelper.getMessage('110036')) stopButton.setButtonText(i18nHelper.getMessage('110036'))
@ -98,7 +99,8 @@ export class DoubanSyncModal extends Modal {
} }
progress.innerHTML = `<p> progress.innerHTML = `<p>
<label for="file">${i18nHelper.getMessage('110033')}</label> <label for="file">${i18nHelper.getMessage('110033')}</label>
<progress class="obsidian_douban_sync_slider" max="${syncStatus.getTotal() == 0 ? 1:syncStatus.getTotal()}" value="${syncStatus.getHandle()}"> </progress> <span> ${syncStatus.getHandle()}/${syncStatus.getTotal()} </span> <progress class="obsidian_douban_sync_slider" max="${syncStatus.getTotal() == 0 ? 1:syncStatus.getTotal()}" value="${syncStatus.getHasHandle()}"> </progress> <span> ${syncStatus.getTotal() == 0 ? i18nHelper.getMessage('110043') : syncStatus.getHasHandle() + '/' + syncStatus.getTotal()}
${syncStatus.getHandle() == 0? '...' : i18nHelper.getMessage('110042') + ':' + TimeUtil.estimateTimeMsg(syncStatus.getNeedHandled()-syncStatus.getHandle(), syncStatus.getOverSize())} </span>
</p>`} </p>`}
private showSyncConfig(contentEl: HTMLElement) { private showSyncConfig(contentEl: HTMLElement) {
@ -199,6 +201,7 @@ export class DoubanSyncModal extends Modal {
.setValue(config.syncType) .setValue(config.syncType)
.onChange((value) => { .onChange((value) => {
config.syncType = value; config.syncType = value;
config.templateFile = this.getDefaultTemplatePath(value);
this.openScopeDropdown(scopeSelections, config, disable); this.openScopeDropdown(scopeSelections, config, disable);
this.showTemplateFileSelectionSetting(templateFile, config, disable); this.showTemplateFileSelectionSetting(templateFile, config, disable);
}); });
@ -207,6 +210,23 @@ export class DoubanSyncModal extends Modal {
this.showTemplateFileSelectionSetting(templateFile, config, disable); this.showTemplateFileSelectionSetting(templateFile, config, disable);
} }
private getDefaultTemplatePath(value: string) {
let result:string = "";
const {settings} = this.plugin;
switch (value) {
case SyncType.movie:
result = (settings.movieTemplateFile == '' || settings.movieTemplateFile == null) ? DEFAULT_SETTINGS.movieTemplateFile : settings.movieTemplateFile
break;
case SyncType.book:
result = (settings.bookTemplateFile == '' || settings.bookTemplateFile == null) ? DEFAULT_SETTINGS.bookTemplateFile : settings.bookTemplateFile
break;
case SyncType.music:
result = (settings.musicTemplateFile == '' || settings.musicTemplateFile == null) ? DEFAULT_SETTINGS.musicTemplateFile : settings.musicTemplateFile
break;
}
return result;
}
private showScopeDropdown(containerEl:HTMLDivElement, scopeSelections: Record<string, string>, config: SyncConfig, disable:boolean) { private showScopeDropdown(containerEl:HTMLDivElement, scopeSelections: Record<string, string>, config: SyncConfig, disable:boolean) {
containerEl.empty(); containerEl.empty();
new Setting(containerEl) new Setting(containerEl)

@ -160,10 +160,9 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
log.error(i18nHelper.getMessage('130101', e.toString()), e); log.error(i18nHelper.getMessage('130101', e.toString()), e);
if (url) { if (url) {
let id = StringUtil.analyzeIdByUrl(url); let id = StringUtil.analyzeIdByUrl(url);
context.syncStatusHolder?context.syncStatusHolder.syncFail(id, ''):null; context.syncStatusHolder?context.syncStatusHolder.syncStatus.fail(id, ''):null;
}else { }else {
context.syncStatusHolder?context.syncStatusHolder.syncHandled(1):null; context.syncStatusHolder?context.syncStatusHolder.syncStatus.handled(1):null;
} }
}); });
; ;

@ -1,4 +1,5 @@
export interface SubjectListItem { export interface SubjectListItem {
id:string; id:string;
url:string; url:string;
title:string;
} }

@ -5,8 +5,7 @@ import { SyncTypeRecords} from "../../constant/Constsant";
import {DoubanSubjectState} from "../../constant/DoubanUserState"; import {DoubanSubjectState} from "../../constant/DoubanUserState";
import SyncStatusHolder from "../sync/model/SyncStatusHolder"; import SyncStatusHolder from "../sync/model/SyncStatusHolder";
import DoubanPlugin from "../../main"; import DoubanPlugin from "../../main";
import {HandleKey} from "../sync/model/HandledKey"; import {SyncHandledData} from "../setting/model/SyncHandledData";
import {HandleValue} from "../sync/model/HandleValue";
export default class GlobalStatusHolder { export default class GlobalStatusHolder {
public syncStatus:SyncStatusHolder; public syncStatus:SyncStatusHolder;
@ -48,64 +47,23 @@ export default class GlobalStatusHolder {
return this.syncStarted; return this.syncStarted;
} }
public syncReplace(id:string, title:string) { public async initHandledData() {
this.syncStatus.replace(id, title); this.syncStatus.initSyncHandledData(this._plugin.settings.syncHandledDataArray);
} }
public syncExists(id:string, title:string) { public async saveHandledData() {
this.syncStatus.exists(id, title);
}
public syncCreate(id:string, title:string) {
this.syncStatus.create(id, title);
}
public syncFail(id:string, title:string) {
this.syncStatus.fail(id, title);
}
public putSyncHandledData(handledData:Map<HandleKey, Set<HandleValue>>) {
this.syncStatus.handledData = handledData;
}
public initSyncHandledData() {
this.putSyncHandledData(this._plugin.settings.syncHandledData);
const incrementalUpdate:boolean = this.syncStatus.syncConfig.incrementalUpdate;
if (incrementalUpdate == false) {
this.syncStatus.resetSyncHandledSet();
}
}
public setTotal(total:number) {
this.syncStatus.setTotal(total);
}
syncHandled(num:number) {
this.syncStatus.handled(num);
}
syncTotalNum(num:number) {
this.syncStatus.setTotal(num);
}
getSyncTotal():number {
return this.syncStatus.getTotal();
}
getSyncHandle():number {
return this.syncStatus.getHandle();
}
private async saveHandledData() {
if(!this.syncStatus || !this.syncStatus.handledData) { if(!this.syncStatus || !this.syncStatus.handledData) {
return; return;
} }
this._plugin.settings.syncHandledData = this.syncStatus.handledData; const data:SyncHandledData[] = [];
this.syncStatus.handledData.forEach((value, key) => {
data.push({key: key, value: Array.from(value)});
})
this._plugin.settings.syncHandledDataArray = data;
await this._plugin.saveSettings(); await this._plugin.saveSettings();
} }
shouldSync(id: string) { public async onunload() {
return this.syncStatus.shouldSync(id); await this.saveHandledData();
} }
} }

@ -1,7 +1,5 @@
import {CustomProperty} from "./CustomProperty"; import {CustomProperty} from "./CustomProperty";
import {SyncConfig} from "../../sync/model/SyncConfig"; import {SyncHandledData} from "./SyncHandledData";
import {HandleKey} from "../../sync/model/HandledKey";
import {HandleValue} from "../../sync/model/HandleValue";
export interface DoubanPluginSetting { export interface DoubanPluginSetting {
movieTemplateFile: string, movieTemplateFile: string,
@ -24,5 +22,5 @@ export interface DoubanPluginSetting {
loginCookiesContent: string, loginCookiesContent: string,
cacheImage: boolean, cacheImage: boolean,
attachmentPath: string, attachmentPath: string,
syncHandledData?:Map<HandleKey, Set<HandleValue>>, syncHandledDataArray: SyncHandledData[],
} }

@ -0,0 +1,4 @@
export interface SyncHandledData {
key:string;
value:string[];
}

@ -65,14 +65,19 @@ export abstract class DoubanAbstractSyncHandler<T extends DoubanSubject> implem
if (!items || items.length == 0) { if (!items || items.length == 0) {
return ; return ;
} }
context.syncStatusHolder.setTotal(items.length); const {syncStatus} = context.syncStatusHolder;
syncStatus.totalNum(items.length);
const needHandled:number = items.filter(item => syncStatus.shouldSync(item.id)).length;
syncStatus.setNeedHandled(needHandled);
for (const item of items) { for (const item of items) {
await sleepRange(BasicConst.CALL_DOUBAN_DELAY, BasicConst.CALL_DOUBAN_DELAY + BasicConst.CALL_DOUBAN_DELAY_RANGE);
if (!context.plugin.statusHolder.syncing()) { if (!context.plugin.statusHolder.syncing()) {
return; return;
} }
if(context.syncStatusHolder.shouldSync(item.id)) { if(syncStatus.shouldSync(item.id)) {
await this.doubanSubjectLoadHandler.handle(item.url, context); await this.doubanSubjectLoadHandler.handle(item.url, context);
await sleepRange(BasicConst.CALL_DOUBAN_DELAY, BasicConst.CALL_DOUBAN_DELAY + BasicConst.CALL_DOUBAN_DELAY_RANGE);
}else {
syncStatus.unHandle(item.id, item.title);
} }
} }
} }

@ -48,24 +48,35 @@ export default class SyncHandler {
async showResult() { async showResult() {
const {syncStatusHolder} = this.context; const {syncStatusHolder} = this.context;
const {statusHandleMap} = syncStatusHolder.syncStatus; const {syncStatus} = syncStatusHolder;
const {syncResultMap} = syncStatusHolder.syncStatus; const {statusHandleMap} = syncStatus;
let summary:string = `${i18nHelper.getMessage('syncall')}: ${syncStatusHolder.getSyncTotal()} const {syncResultMap} = syncStatus;
let summary:string
= `${i18nHelper.getMessage('110053', i18nHelper.getMessage('110050'), i18nHelper.getMessage('110051'), i18nHelper.getMessage('110052'))}
|-----|----|----------------------------------|
`;
summary += `${i18nHelper.getMessage('110053', i18nHelper.getMessage('syncall'), syncStatus.getTotal(), i18nHelper.getMessage('syncall_desc'))}
`; `;
for (const [key, value] of statusHandleMap) { for (const [key, value] of statusHandleMap) {
// @ts-ignore // @ts-ignore
summary+= `${i18nHelper.getMessage(key)}: ${value} summary+= `${i18nHelper.getMessage('110053', i18nHelper.getMessage(key), value, i18nHelper.getMessage(key + '_desc'))}
`; `;
} }
summary += `${i18nHelper.getMessage('110053', i18nHelper.getMessage('notsync'), syncStatus.getTotal()-syncStatus.getHasHandle(), i18nHelper.getMessage('notsync_desc'))}
`;
let details:string = ''; let details:string = '';
for (const [key, value] of syncResultMap) { for (const [key, value] of syncResultMap) {
if (value.status == 'unHandle') {
// @ts-ignore
details+= `${value.id}- ${value.title} : ${i18nHelper.getMessage(value.status)}
`;
}else {
// @ts-ignore // @ts-ignore
details+= `${value.id}-[[${value.title}]]: ${i18nHelper.getMessage(value.status)} details+= `${value.id}-[[${value.title}]]: ${i18nHelper.getMessage(value.status)}
`; `;
} }
summary+= `${i18nHelper.getMessage('notsync')}: ${syncStatusHolder.getSyncTotal() - syncStatusHolder.getSyncHandle()}
`
}
const result : string = i18nHelper.getMessage('110037', summary, details); const result : string = i18nHelper.getMessage('110037', summary, details);
const resultFileName = `${i18nHelper.getMessage('110038')}_${moment(new Date()).format('YYYYMMDDHHmmss')}` const resultFileName = `${i18nHelper.getMessage('110038')}_${moment(new Date()).format('YYYYMMDDHHmmss')}`
await this.plugin.fileHandler.createNewNoteWithData(`${this.syncConfig.dataFilePath}/${resultFileName}`, result, true); await this.plugin.fileHandler.createNewNoteWithData(`${this.syncConfig.dataFilePath}/${resultFileName}`, result, true);

@ -75,9 +75,10 @@ export default abstract class DoubanAbstractListHandler implements DoubanListHan
.map((i: any) => { .map((i: any) => {
const item = dataHtml(i); const item = dataHtml(i);
const linkValue:string = item.find('div.title > a').attr('href'); const linkValue:string = item.find('div.title > a').attr('href');
const titleValue:string = item.find('div.title > a').text().trim();
let idPattern = /(\d){5,10}/g; let idPattern = /(\d){5,10}/g;
let ececResult = idPattern.exec(linkValue); let ececResult = idPattern.exec(linkValue);
return ececResult?{id: ececResult[0], url: linkValue}:null; return ececResult?{id: ececResult[0], url: linkValue, title: titleValue}:null;
// return linkValue; // return linkValue;
}) })
} }

@ -1,30 +0,0 @@
import {SyncConfig} from "./SyncConfig";
import {SyncItemStatus} from "../../../constant/Constsant";
export default class GlobalSyncStatusHolder {
public syncConfig: SyncConfig;
private total:number;
private handle:number;
constructor(syncConfig: SyncConfig) {
this.syncConfig = syncConfig;
this.total = 0;
this.handle = 0;
}
handled(num:number) {
this.handle = this.handle + num;
}
totalNum(num:number) {
this.total = num ;
}
getTotal():number {
return this.total;
}
getHandle():number {
return this.handle;
}
}

@ -1,3 +0,0 @@
export interface HandleValue {
v: string;
}

@ -1,3 +0,0 @@
export interface HandleKey {
k: string;
}

@ -1,25 +1,67 @@
import {SyncConfig} from "./SyncConfig"; import {SyncConfig} from "./SyncConfig";
import GlobalSyncStatusHolder from "./GlobalSyncStatusHolder";
import {SyncItemResult} from "./SyncItemResult"; import {SyncItemResult} from "./SyncItemResult";
import {SyncItemStatus} from "../../../constant/Constsant"; import {BasicConst, SyncItemStatus} from "../../../constant/Constsant";
import {HandleKey} from "./HandledKey"; import {SyncHandledData} from "../../setting/model/SyncHandledData";
import {HandleValue} from "./HandleValue";
export default class SyncStatusHolder extends GlobalSyncStatusHolder{ export default class SyncStatusHolder {
public handledData: Map<HandleKey, Set<HandleValue>>; public handledData: Map<string, Set<string>>;
public syncResultMap: Map<string, SyncItemResult> = new Map(); public syncResultMap: Map<string, SyncItemResult> = new Map();
public statusHandleMap: Map<SyncItemStatus, number> = new Map([ public statusHandleMap: Map<SyncItemStatus, number> = new Map([
[SyncItemStatus.exists, 0], [SyncItemStatus.exists, 0],
[SyncItemStatus.replace, 0], [SyncItemStatus.replace, 0],
[SyncItemStatus.create, 0], [SyncItemStatus.create, 0],
[SyncItemStatus.fail, 0], [SyncItemStatus.fail, 0],
[SyncItemStatus.unHandle, 0],
]); ]);
private key: string;
public syncConfig: SyncConfig;
private total:number;
private handle:number;
private needHandled:number;
constructor(syncConfig: SyncConfig) { constructor(syncConfig: SyncConfig) {
super(syncConfig) this.syncConfig = syncConfig;
this.total = 0;
this.handle = 0;
this.needHandled = 0;
this.key =this.getKey(syncConfig);
} }
handled(num:number) {
this.handle = this.handle + num;
}
totalNum(num:number) {
this.total = num ;
}
getTotal():number {
return this.total;
}
getHandle():number {
return this.handle;
}
/**
*
*/
getHasHandle():number {
return this.handle;
}
setNeedHandled(needHandled:number) {
this.needHandled = needHandled;
}
getNeedHandled():number {
return this.needHandled;
}
public replace(id:string, title:string) { public replace(id:string, title:string) {
this.putToHandled(id, title); this.putToHandled(id, title);
this.updateResult(id, title, SyncItemStatus.replace); this.updateResult(id, title, SyncItemStatus.replace);
@ -30,6 +72,11 @@ export default class SyncStatusHolder extends GlobalSyncStatusHolder{
this.updateResult(id, title, SyncItemStatus.exists); this.updateResult(id, title, SyncItemStatus.exists);
} }
public unHandle(id:string, title:string) {
this.updateResult(id, title, SyncItemStatus.unHandle);
}
public create(id:string, title:string) { public create(id:string, title:string) {
this.putToHandled(id, title); this.putToHandled(id, title);
this.updateResult(id, title, SyncItemStatus.create); this.updateResult(id, title, SyncItemStatus.create);
@ -42,37 +89,76 @@ export default class SyncStatusHolder extends GlobalSyncStatusHolder{
private updateResult(id:string, title:string, status:SyncItemStatus) { private updateResult(id:string, title:string, status:SyncItemStatus) {
this.syncResultMap.set(id, {id: id,title:title,status:status}); this.syncResultMap.set(id, {id: id,title:title,status:status});
this.statusHandleMap.set(status, this.statusHandleMap.get(status) + 1); this.statusHandleMap.set(status, this.statusHandleMap.get(status) + 1);
super.handled(1); this.handled(1);
} }
public setTotal(total:number) { public setTotal(total:number) {
super.totalNum(total); this.totalNum(total);
} }
private putToHandled(id: string, title: string) { private putToHandled(id: string, title: string) {
if (!this.handledData) { if (!this.handledData) {
this.handledData = new Map<HandleKey, Set<HandleValue>>(); this.handledData = new Map<string, Set<string>>();
} }
const key = {k: this.syncConfig.dataFilePath} const {key} = this;
if (!this.handledData.has(key)) { if (!this.handledData.has(key)) {
this.handledData.set(key, new Set<HandleValue>()); this.handledData.set(key, new Set<string>());
}
this.handledData.get(key).add({v:id})
}
resetSyncHandledSet() {
if (!this.handledData) {
return;
}
const key = {k: this.syncConfig.dataFilePath}
if (this.handledData.has(key)) {
this.handledData.set(key, new Set<HandleValue>());
} }
this.handledData.get(key).add(id)
} }
shouldSync(id: string) { shouldSync(id: string) {
const key = {k: this.syncConfig.dataFilePath} return this.handledData.get(this.key)?!this.handledData.get(this.key).has(id):true;
return !this.handledData.get(key).has({v:id});
} }
getKey(syncConfig: SyncConfig):string {
const type:string = syncConfig.syncType ? syncConfig.syncType : '';
const scope:string = syncConfig.scope ? syncConfig.scope : '';
const path:string = syncConfig.dataFilePath ? syncConfig.dataFilePath : '';
return `${path}+${type}+${scope}`;
}
getOverSize():boolean {
return this.getNeedHandled() > BasicConst.SLOW_SIZE;
}
public initSyncHandledData(data:SyncHandledData[]) {
this.handledData = new Map<string, Set<string>>();
const {handledData} = this;
data.forEach((d) => {
handledData.set(d.key,new Set<string>(d.value));
})
if (!this.syncConfig.incrementalUpdate) {
this.resetSyncHandledData();
}
this.resetTypeOtherSyncHandledData();
}
public resetSyncHandledData() {
return this.handledData.set(this.key, new Set());
}
public resetTypeOtherSyncHandledData() {
this.handledData.forEach((value, key) => {
if (this.needClearByKey(this.key, key)) {
value.clear();
}
});
}
private needClearByKey(handleKey:string, savedKey:string):boolean {
if (handleKey == savedKey) {
return false;
}
let handledKeys = handleKey.split('+');
let savedKeys = savedKey.split('+');
handledKeys = handledKeys??[''];
savedKeys = savedKeys??[''];
if (handledKeys[0] == savedKeys[0]) {
return true;
}
return false;
}
} }

@ -35,15 +35,31 @@ PS: This file could be delete if you want to.
'110038': `DoubanSyncResult`, '110038': `DoubanSyncResult`,
'110039': `SyncNotSync:`, '110039': `SyncNotSync:`,
'110040': `Only sync that haven't been synced yet. if not enabled, will sync all the subject'`, '110040': `Only sync that haven't been synced yet. if not enabled, will sync all the subject'`,
'110041': `If`, '110041': `IncrementalSync`,
'110042': `EstimateTime`,
'110043': `Loading Menu`,
'110050': `Type`,
'110051': `Number`,
'110052': `Description`,
'exists':`[exists]`, 'exists':`[exists]`,
'unHandle':`[unHandle]`,
'replace':`[replace]`, 'replace':`[replace]`,
'create':`[create]`, 'create':`[create]`,
'fail':`[fail]`, 'fail':`[fail]`,
'notsync':`[notSync]`,
'syncall':`[summary]`, 'syncall':`[summary]`,
'notsync':`[notsync]`,
'unHandle_desc':`unHandle`,
'exists_desc': `exists`,
'replace_desc': `replace`,
'create_desc': `create`,
'fail_desc': `fail`,
'notsync_desc': `notsync`,
'syncall_desc': `syncall`,
'110053':`|{0}|{1}|{2}|`,
//DoubanSettingTab //DoubanSettingTab
'1201': `Obsidian Douban`, '1201': `Obsidian Douban`,
@ -495,4 +511,9 @@ PS: This file could be delete if you want to.
'NOTE': `note`, 'NOTE': `note`,
'GAME': `game`, 'GAME': `game`,
'TELEPLAY': `teleplay`, 'TELEPLAY': `teleplay`,
'DAY': `D`,
'HOUR': `H`,
'MINUTE': `m`,
'SECOND': `S`,
} }

@ -38,13 +38,28 @@ export default {
'110039': `增量同步:`, '110039': `增量同步:`,
'110040': `仅同步上面'笔记存放位置'目录中最近新增/同步失败/未同步的部分,不同步已同步的内容.若关闭则会全量同步.增量同步会更快,适合之前同步中途失败停止或最近有豆瓣新增了内容,全量同步适合修改了模板或修改了存放路径情况下进行.`, '110040': `仅同步上面'笔记存放位置'目录中最近新增/同步失败/未同步的部分,不同步已同步的内容.若关闭则会全量同步.增量同步会更快,适合之前同步中途失败停止或最近有豆瓣新增了内容,全量同步适合修改了模板或修改了存放路径情况下进行.`,
'110041': `使用增量`, '110041': `使用增量`,
'110042': `预计处理时间`,
'110043': `同步目录加载中`,
'110050': `类型`,
'110051': `数量`,
'110052': `说明`,
'unHandle':`[已忽略]`,
'exists': `[未替换]`, 'exists': `[未替换]`,
'replace': `[已替换]`, 'replace': `[已替换]`,
'create': `[已创建]`, 'create': `[已创建]`,
'fail':`[失败]`, 'fail': `[已失败]`,
'notsync':`[未进行]`,
'syncall': `[总数]`, 'syncall': `[总数]`,
'notsync': `[未进行]`,
'unHandle_desc':`增量同步上次已进行,这次无需处理`,
'exists_desc': `已经存在的同名文档,这次无需同步`,
'replace_desc': `已经存在的同名文档,这次已被替换`,
'create_desc': `之前不存在的文档,这次直接新增`,
'fail_desc': `处理过程钟出现错误,未能成功`,
'notsync_desc': `因异常中断或提前终止导致还未处理`,
'syncall_desc': `您此次同步条件在豆瓣中的条目总数`,
'110201': `{0} 文件已经存在.`, '110201': `{0} 文件已经存在.`,
'110202': `{0} 模板文件无法读取`, '110202': `{0} 模板文件无法读取`,
@ -506,5 +521,9 @@ export default {
'GAME': `游戏`, 'GAME': `游戏`,
'TELEPLAY': `电视剧`, 'TELEPLAY': `电视剧`,
'DAY': ``,
'HOUR': ``,
'MINUTE': ``,
'SECOND': ``,
} }

@ -22,7 +22,6 @@ import {DoubanSyncModal} from "./douban/component/DoubanSyncModal";
import SyncHandler from "./douban/sync/handler/SyncHandler"; import SyncHandler from "./douban/sync/handler/SyncHandler";
import {SyncConfig} from "./douban/sync/model/SyncConfig"; import {SyncConfig} from "./douban/sync/model/SyncConfig";
import GlobalStatusHolder from "./douban/model/GlobalStatusHolder"; import GlobalStatusHolder from "./douban/model/GlobalStatusHolder";
import SyncStatusHolder from "./douban/sync/model/SyncStatusHolder";
export default class DoubanPlugin extends Plugin { export default class DoubanPlugin extends Plugin {
public settings: DoubanPluginSetting; public settings: DoubanPluginSetting;
@ -36,7 +35,7 @@ export default class DoubanPlugin extends Plugin {
async putToObsidian(context: HandleContext, extract: DoubanSubject) { async putToObsidian(context: HandleContext, extract: DoubanSubject) {
const {syncStatusHolder} = context; const {syncStatus} = context.syncStatusHolder;
try { try {
if (!extract) { if (!extract) {
@ -44,7 +43,7 @@ export default class DoubanPlugin extends Plugin {
return; return;
} }
if (Action.Sync == context.action) { if (Action.Sync == context.action) {
this.showStatus(i18nHelper.getMessage('140207', syncStatusHolder.getSyncHandle(), syncStatusHolder.getSyncTotal(), extract.title)); this.showStatus(i18nHelper.getMessage('140207', syncStatus.getHasHandle(), syncStatus.getTotal(), extract.title));
}else { }else {
this.showStatus(i18nHelper.getMessage('140204', extract.title)); this.showStatus(i18nHelper.getMessage('140204', extract.title));
} }
@ -53,13 +52,13 @@ export default class DoubanPlugin extends Plugin {
await this.putContentToObsidian(context, result); await this.putContentToObsidian(context, result);
} }
if (Action.Sync == context.action) { if (Action.Sync == context.action) {
this.showStatus(i18nHelper.getMessage('140208', syncStatusHolder.getSyncHandle(), syncStatusHolder.getSyncTotal(), extract.title)); this.showStatus(i18nHelper.getMessage('140208', syncStatus.getHasHandle(), syncStatus.getTotal(), extract.title));
}else { }else {
this.showStatus(i18nHelper.getMessage('140205', extract.title)); this.showStatus(i18nHelper.getMessage('140205', extract.title));
} }
} catch (e) { } catch (e) {
log.error(i18nHelper.getMessage('140206', e.message), e); log.error(i18nHelper.getMessage('140206', e.message), e);
syncStatusHolder!=null?syncStatusHolder.syncFail(extract.id, extract.title):null; syncStatus!=null?syncStatus.fail(extract.id, extract.title):null;
} finally { } finally {
this.clearStatusBarDelay(); this.clearStatusBarDelay();
} }
@ -89,20 +88,20 @@ export default class DoubanPlugin extends Plugin {
} }
filePath = filePath?filePath:DEFAULT_SETTINGS.dataFilePath; filePath = filePath?filePath:DEFAULT_SETTINGS.dataFilePath;
filePath = FileUtil.join(filePath, result.fileName); filePath = FileUtil.join(filePath, result.fileName);
const {syncStatusHolder} = context; const {syncStatus} = context.syncStatusHolder;
const {subject} = result; const {subject} = result;
const {content} = result; const {content} = result;
if (Action.Sync == context.action) { if (Action.Sync == context.action) {
if (context.syncStatusHolder.syncStatus.syncConfig.force) { if (context.syncStatusHolder.syncStatus.syncConfig.force) {
const exists:boolean = await this.fileHandler.createOrReplaceNewNoteWithData(filePath, content, context.showAfterCreate); const exists:boolean = await this.fileHandler.createOrReplaceNewNoteWithData(filePath, content, context.showAfterCreate);
if (exists) { if (exists) {
syncStatusHolder != null ? syncStatusHolder.syncReplace(subject.id, subject.title):null; syncStatus != null ? syncStatus.replace(subject.id, subject.title):null;
}else { }else {
syncStatusHolder != null ?syncStatusHolder.syncCreate(subject.id, subject.title):null; syncStatus != null ?syncStatus.create(subject.id, subject.title):null;
} }
}else { }else {
const created:boolean = await this.fileHandler.createNewNoteWithData(filePath, content, context.showAfterCreate, false); const created:boolean = await this.fileHandler.createNewNoteWithData(filePath, content, context.showAfterCreate, false);
created ?syncStatusHolder.syncCreate(subject.id, subject.title):syncStatusHolder.syncExists(subject.id, subject.title); created ?syncStatus.create(subject.id, subject.title):syncStatus.exists(subject.id, subject.title);
} }
}else { }else {
await this.fileHandler.createNewNoteWithData(filePath, content, context.showAfterCreate); await this.fileHandler.createNewNoteWithData(filePath, content, context.showAfterCreate);
@ -224,6 +223,13 @@ export default class DoubanPlugin extends Plugin {
} }
async onunload() {
if (this.statusHolder.syncStatus) {
await this.statusHolder.onunload();
}
}
@ -252,8 +258,7 @@ export default class DoubanPlugin extends Plugin {
// @ts-ignore // @ts-ignore
new Notice(i18nHelper.getMessage('140301', SyncTypeRecords[syncConfig.syncType])); new Notice(i18nHelper.getMessage('140301', SyncTypeRecords[syncConfig.syncType]));
this.initSyncDefaultSettings(syncConfig); this.initSyncDefaultSettings(syncConfig);
context.syncStatusHolder.initSyncHandledData(); context.syncStatusHolder.initHandledData();
// @ts-ignore // @ts-ignore
this.showStatus(i18nHelper.getMessage('140203', SyncTypeRecords[syncConfig.syncType])); this.showStatus(i18nHelper.getMessage('140203', SyncTypeRecords[syncConfig.syncType]));
const syncHandler = new SyncHandler(this.app, this, syncConfig, context); const syncHandler = new SyncHandler(this.app, this, syncConfig, context);

@ -1,9 +1,72 @@
import NumberUtil from "./NumberUtil"; import NumberUtil from "./NumberUtil";
import {log} from "./Logutil"; import {log} from "./Logutil";
import {BasicConst, ESTIMATE_TIME_PER_WITH_REQUEST, ESTIMATE_TIME_PER_WITH_REQUEST_SLOW} from "../constant/Constsant";
import {moment} from "obsidian";
import {Moment} from "moment";
import {i18nHelper} from "../lang/helper";
export default class TimeUtil { export default class TimeUtil {
/**
*
* @param needHandled
* @param overSlowSize
* @return
*/
public static estimateTime(needHandled:number, overSlowSize:boolean):number {
if (needHandled <= 0) {
return 0;
}
let times = 0;
if (overSlowSize) {
if (needHandled <= BasicConst.SLOW_SIZE) {
times = ESTIMATE_TIME_PER_WITH_REQUEST * needHandled;
}else {
times = ESTIMATE_TIME_PER_WITH_REQUEST * BasicConst.SLOW_SIZE + ESTIMATE_TIME_PER_WITH_REQUEST_SLOW * Math.max(needHandled - BasicConst.SLOW_SIZE, 0);
}
}else {
times = ESTIMATE_TIME_PER_WITH_REQUEST * needHandled;
}
return times;
}
public static estimateTimeMsg(needHandled:number, overSlowSize:boolean):string {
const times:number = this.estimateTime(needHandled, overSlowSize);
if (times <= 0) {
return 0+i18nHelper.getMessage('SECOND');
}
return this.formatDuring(times);
}
public static formatDuring(mss:number):string {
let show:boolean = false;
let message:string = "";
const days = Math.floor(mss / (1000 * 60 * 60 * 24));
const hours = Math.floor((mss % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((mss % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((mss % (1000 * 60)) / 1000);
if (days > 0) {
show = true;
message += days + i18nHelper.getMessage("DAY");
}
if (hours > 0 || show) {
show = true;
message += hours + i18nHelper.getMessage("HOUR");
}
if (minutes > 0 || show) {
show = true;
message += minutes + i18nHelper.getMessage("MINUTE");
}
if (seconds > 0 || show) {
message += seconds + i18nHelper.getMessage("SECOND");
}
return message;
}
} }