From 4d3dc61d33a345b0c1ef22e382ba0c90a1d04db2 Mon Sep 17 00:00:00 2001
From: Wanxp <977741432@qq.com>
Date: Thu, 6 Mar 2025 18:44:31 +0800
Subject: [PATCH] =?UTF-8?q?fix=20#139=201.=20=E4=BC=98=E5=8C=96=E5=AF=BC?=
=?UTF-8?q?=E5=85=A5=E9=85=8D=E7=BD=AE,=E5=A2=9E=E5=8A=A0=E6=9B=B4?=
=?UTF-8?q?=E5=A4=9A=E5=AF=BC=E5=85=A5=E6=97=B6=E7=9A=84=E9=80=89=E9=A1=B9?=
=?UTF-8?q?=202.=20=E4=BC=98=E5=8C=96=E5=AF=BC=E5=85=A5=E7=BB=93=E6=9E=9C?=
=?UTF-8?q?=E7=9A=84=E6=98=BE=E7=A4=BA=EF=BC=8C=E7=8E=B0=E5=9C=A8=E4=BC=9A?=
=?UTF-8?q?=E5=9C=A8=E7=BB=93=E6=9E=9C=E6=96=87=E6=9C=AC=E4=B8=AD=E6=98=BE?=
=?UTF-8?q?=E7=A4=BA=E5=85=B7=E4=BD=93=E7=9A=84=E6=9D=A1=E4=BB=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/org/wanxp/constant/Constsant.ts | 19 +-
src/org/wanxp/constant/DefaultSettings.ts | 1 +
src/org/wanxp/constant/DoubanUserState.ts | 15 +-
.../wanxp/douban/component/DoubanSyncModal.ts | 80 ++-
.../wanxp/douban/data/model/HandleContext.ts | 1 +
src/org/wanxp/douban/data/model/SearchPage.ts | 25 +-
.../wanxp/douban/data/model/SearchPageInfo.ts | 4 +
.../douban/data/model/SearchPageTypeOf.ts | 29 ++
.../douban/data/model/SubjectListItem.ts | 1 +
.../douban/setting/TemplateSettingHelper.ts | 3 +-
.../setting/model/DoubanPluginSetting.ts | 3 +-
.../setting/model/FileTreeSelectSuggest.ts | 13 +-
.../sync/handler/DoubanAbstractSyncHandler.ts | 460 ++++++++++++++++--
.../wanxp/douban/sync/handler/SyncHandler.ts | 47 +-
.../handler/list/DoubanAbstractListHandler.ts | 156 +++---
.../sync/handler/list/DoubanListHandler.ts | 4 +-
src/org/wanxp/douban/sync/model/SyncConfig.ts | 8 +-
.../wanxp/douban/sync/model/SyncItemResult.ts | 8 +-
.../douban/sync/model/SyncStatusHolder.ts | 56 ++-
src/org/wanxp/lang/helper.ts | 21 +-
src/org/wanxp/lang/locale/en.ts | 24 +-
src/org/wanxp/lang/locale/zh-cn.ts | 30 +-
src/org/wanxp/main.ts | 7 +-
styles.css | 20 +-
24 files changed, 855 insertions(+), 180 deletions(-)
create mode 100644 src/org/wanxp/douban/data/model/SearchPageTypeOf.ts
diff --git a/src/org/wanxp/constant/Constsant.ts b/src/org/wanxp/constant/Constsant.ts
index 4912e92..dc45f67 100644
--- a/src/org/wanxp/constant/Constsant.ts
+++ b/src/org/wanxp/constant/Constsant.ts
@@ -223,7 +223,7 @@ export const SyncTypeUrlDomain: Map = new Map([
* 同步模式选项
*/
// @ts-ignore
-export const SyncTypeRecords: { [key in SyncType]: string } = {
+export const SyncTypeRecords: { [key in SyncType | string]: string } = {
[SyncType.movie]: i18nHelper.getMessage('504103'),
[SyncType.teleplay]: i18nHelper.getMessage('504107'),
[SyncType.book]: i18nHelper.getMessage('504102'),
@@ -257,6 +257,7 @@ export enum SyncItemStatus {
replace = 'replace',
create = 'create',
fail = 'fail',
+ failByDiffType = 'failByDiffType',
unHandle = 'unHandle',
}
@@ -459,15 +460,15 @@ export enum SyncConditionType {
* 最近新变动
*/
ALL = "all",
- /**
- * 最近新变动
- */
- LAST_UPDATE = "lastUpdate",
+ // /**
+ // * 最近新变动
+ // */
+ // LAST_UPDATE = "lastUpdate",
/**
* 最近10条
*/
- LAST_TEN = "lastTen",
+ LAST_THIRTY = "lastThirty",
/**
* 自定义时间
@@ -485,10 +486,10 @@ export enum SyncConditionType {
* 名称模式选项
*/
// @ts-ignore
-export const SyncConditionTypeRecords: { [key in SyncConditionType]: string } = {
+export const SyncConditionTypeRecords: { [key in SyncConditionType|string]: string } = {
[SyncConditionType.ALL]: i18nHelper.getMessage('110071'),
- [SyncConditionType.LAST_UPDATE]: i18nHelper.getMessage('110072'),
- [SyncConditionType.LAST_TEN]: i18nHelper.getMessage('110075'),
+ // [SyncConditionType.LAST_UPDATE]: i18nHelper.getMessage('110072'),
+ [SyncConditionType.LAST_THIRTY]: i18nHelper.getMessage('110075'),
[SyncConditionType.CUSTOM_ITEM]: i18nHelper.getMessage('110076'),
[SyncConditionType.CUSTOM_TIME]: i18nHelper.getMessage('110074'),
diff --git a/src/org/wanxp/constant/DefaultSettings.ts b/src/org/wanxp/constant/DefaultSettings.ts
index 94af101..e84eaa4 100644
--- a/src/org/wanxp/constant/DefaultSettings.ts
+++ b/src/org/wanxp/constant/DefaultSettings.ts
@@ -51,6 +51,7 @@ export const DEFAULT_SETTINGS: DoubanPluginSetting = {
cacheHighQuantityImage: true,
attachmentPath: 'assets',
syncHandledDataArray: [],
+ // syncLastUpdateTime: new Map(),
scoreSetting: {
starFull: '⭐',
starEmpty: '☆',
diff --git a/src/org/wanxp/constant/DoubanUserState.ts b/src/org/wanxp/constant/DoubanUserState.ts
index e9a1e1d..16c598f 100644
--- a/src/org/wanxp/constant/DoubanUserState.ts
+++ b/src/org/wanxp/constant/DoubanUserState.ts
@@ -1,5 +1,5 @@
import {i18nHelper} from "../lang/helper";
-import {SupportType} from "./Constsant";
+import {SupportType, SyncType} from "./Constsant";
export enum DoubanSubjectState {
not = 'not',
@@ -123,6 +123,19 @@ export const DoubanSubjectStateRecords_MUSIC_SYNC: { [key in DoubanSubjectState]
[DoubanSubjectState.collect]: i18nHelper.getMessage('500404'),
}
+// @ts-ignore
+export const DoubanSubjectStateRecords_SYNC: { [key in SyncType]: Record } = {
+ [SyncType.movie]:DoubanSubjectStateRecords_MOVIE_SYNC,
+ [SyncType.book]:DoubanSubjectStateRecords_BOOK_SYNC,
+ [SyncType.music]:DoubanSubjectStateRecords_MUSIC_SYNC,
+ // [SyncType.note]:DoubanSubjectStateRecords_NOTE_SYNC,
+ // [SyncType.game]:DoubanSubjectStateRecords_GAME_SYNC,
+ [SyncType.teleplay]:DoubanSubjectStateRecords_TELEPLAY_SYNC,
+ // [SyncType.theater]:DoubanSubjectStateRecords_THEATER_SYNC,
+}
+
+
+
export const DoubanSubjectStateRecords_KEY_WORD_TYPE: Map = new Map (
[['我看过这部电视剧', SupportType.TELEPLAY],
['我最近看过这部电视剧', SupportType.TELEPLAY],
diff --git a/src/org/wanxp/douban/component/DoubanSyncModal.ts b/src/org/wanxp/douban/component/DoubanSyncModal.ts
index abcbbab..7f199bc 100644
--- a/src/org/wanxp/douban/component/DoubanSyncModal.ts
+++ b/src/org/wanxp/douban/component/DoubanSyncModal.ts
@@ -15,7 +15,7 @@ import {
SyncTypeRecords
} from "../../constant/Constsant";
import {
- ALL,
+ ALL, DoubanSubjectState, DoubanSubjectStateRecords,
DoubanSubjectStateRecords_BOOK_SYNC,
DoubanSubjectStateRecords_BROADCAST_SYNC,
DoubanSubjectStateRecords_MOVIE_SYNC,
@@ -36,6 +36,7 @@ import {ArraySetting, DEFAULT_SETTINGS_ARRAY_NAME} from "../setting/model/ArrayS
import {arraySettingDisplay} from "../setting/ArrayDisplayTypeSettingsHelper";
import {DatePickComponent} from "./DatePickComponent";
import {NumberComponent} from "./NumberComponent";
+import {log} from "../../utils/Logutil";
export class DoubanSyncModal extends Modal {
plugin: DoubanPlugin;
@@ -107,7 +108,16 @@ export class DoubanSyncModal extends Modal {
progress.innerHTML = `
${syncStatus.getHasHandle()}/${syncStatus.getTotal()}:${i18nHelper.getMessage('110036')}
-
`
+
+
+
+${i18nHelper.getMessage('110090', syncStatus.getTypeName(), syncStatus.getScopeName(), syncStatus.getAllTotal(), syncStatus.getTotal())}
+
+
+
+${syncStatus.getMessage()}
+
+`
backgroundButton.setDisabled(true);
stopButton.setButtonText(i18nHelper.getMessage('110036'))
return;
@@ -116,7 +126,16 @@ export class DoubanSyncModal extends Modal {
${syncStatus.getTotal() == 0 ? i18nHelper.getMessage('110043') : syncStatus.getHasHandle() + '/' + syncStatus.getTotal()}
${syncStatus.getHandle() == 0? '...' : i18nHelper.getMessage('110042') + ':' + TimeUtil.estimateTimeMsg(syncStatus.getNeedHandled()-syncStatus.getHandle(), syncStatus.getOverSize())}
-`}
+
+
+
+${i18nHelper.getMessage('110090', syncStatus.getTypeName(), syncStatus.getScopeName(), syncStatus.getAllTotal(), syncStatus.getTotal())}
+
+
+
+${syncStatus.getMessage()}
+
+`}
private showSyncConfig(contentEl: HTMLElement) {
if (this.timer != null) {
@@ -133,11 +152,11 @@ ${syncStatus.getHandle() == 0? '...' : i18nHelper.getMessage('110042') + ':' + T
attachmentPath: (settings.attachmentPath == '' || settings.attachmentPath == null) ? DEFAULT_SETTINGS.attachmentPath : settings.attachmentPath,
templateFile: (settings.movieTemplateFile == '' || settings.movieTemplateFile == null) ? DEFAULT_SETTINGS.movieTemplateFile : settings.movieTemplateFile,
incrementalUpdate: true,
- syncConditionType: SyncConditionType.LAST_UPDATE,
- syncConditionDateFromValue: null,
- syncConditionDateToValue: null,
- syncConditionCountFromValue: null,
- syncConditionCountToValue: null
+ syncConditionType: SyncConditionType.ALL,
+ syncConditionDateFromValue: TimeUtil.getLastMonth(),
+ syncConditionDateToValue: new Date(),
+ syncConditionCountFromValue: 1,
+ syncConditionCountToValue: 30
};
this.showConfigPan(contentEl.createDiv('config'), syncConfig, false);
const controls = contentEl.createDiv("controls");
@@ -149,6 +168,9 @@ ${syncStatus.getHandle() == 0? '...' : i18nHelper.getMessage('110042') + ':' + T
const syncButton = new ButtonComponent(controls)
.setButtonText(i18nHelper.getMessage('110007'))
.onClick(async () => {
+ if (!this.plugin.userComponent.isLogin()) {
+ await this.plugin.userComponent.login();
+ }
if(!await this.plugin.checkLogin(this.context)) {
return;
}
@@ -461,12 +483,17 @@ function showCustomInputCount(containerEl: HTMLElement, config: SyncConfig, disa
containerEl.createEl('span', { text: i18nHelper.getMessage('110078') })
const fromField = new TextComponent(containerEl);
fromField.setPlaceholder(i18nHelper.getMessage('110080'))
- .setValue(config.syncConditionCountFromValue)
+ .setValue(config.syncConditionCountFromValue + '')
.onChange(async (value) => {
if (!value) {
+ config.syncConditionCountFromValue = 1;
return;
}
- config.syncConditionCountFromValue = value;
+ try {
+ config.syncConditionCountFromValue = parseInt(value);
+ }catch (e) {
+ log.notice(i18nHelper.getMessage('112080'))
+ }
}).setDisabled(disable);
let fromEl = fromField.inputEl;
fromEl.addClass('obsidian_douban_settings_input')
@@ -481,12 +508,17 @@ function showCustomInputCount(containerEl: HTMLElement, config: SyncConfig, disa
containerEl.createEl('span', { text: i18nHelper.getMessage('110078') })
const toField = new TextComponent(containerEl);
toField.setPlaceholder(i18nHelper.getMessage('110080'))
- .setValue(config.syncConditionCountToValue)
+ .setValue(config.syncConditionCountToValue + '')
.onChange(async (value) => {
if (!value) {
+ config.syncConditionCountToValue = 30;
return;
}
- config.syncConditionCountToValue = value;
+ try {
+ config.syncConditionCountToValue = parseInt(value);
+ }catch (e) {
+ log.notice(i18nHelper.getMessage('112080'))
+ }
}).setDisabled(disable);
let toEl = toField.inputEl;
toEl.addClass('obsidian_douban_settings_input')
@@ -495,6 +527,9 @@ function showCustomInputCount(containerEl: HTMLElement, config: SyncConfig, disa
if (lang == 'zh') {
containerEl.createEl('span', {text: i18nHelper.getMessage('110073')})
}
+ containerEl.createEl('span', {text: ' '})
+ const buttopn = new ButtonComponent(containerEl).setIcon('help').setTooltip(i18nHelper.getMessage('110095'))
+ containerEl.appendChild(buttopn.buttonEl);
}
function showCustomInputTime(containerEl: HTMLElement, config: SyncConfig, disable: boolean) {
@@ -502,14 +537,18 @@ function showCustomInputTime(containerEl: HTMLElement, config: SyncConfig, disab
const fromDateField = new TextComponent(containerEl);
const fromDateEl = fromDateField.inputEl;
fromDateEl.type = 'date';
- fromDateEl.value = config.syncConditionDateFromValue??TimeUtil.getLastMonth().toISOString().substring(0, 10);
+ fromDateEl.value = config.syncConditionDateFromValue ? config.syncConditionDateFromValue.toISOString().substring(0, 10) : TimeUtil.getLastMonth().toISOString().substring(0, 10);
fromDateField.setPlaceholder(i18nHelper.getMessage('110075'))
- .setValue(config.syncConditionDateFromValue)
+ .setValue(config.syncConditionDateFromValue ? config.syncConditionDateFromValue.toISOString().substring(0, 10) : TimeUtil.getLastMonth().toISOString().substring(0, 10))
.onChange(async (value) => {
if (!value) {
return;
}
- config.syncConditionDateFromValue = value;
+ try {
+ config.syncConditionDateFromValue = new Date(value);
+ }catch (e) {
+ log.notice(i18nHelper.getMessage('110082'))
+ }
}).setDisabled(disable);
fromDateEl.addClass('obsidian_douban_settings_input')
containerEl.appendChild(fromDateEl);
@@ -518,16 +557,21 @@ function showCustomInputTime(containerEl: HTMLElement, config: SyncConfig, disab
const toDateField = new TextComponent(containerEl);
let toDateEl = toDateField.inputEl;
toDateEl.type = 'date';
- toDateEl.value = config.syncConditionDateToValue??new Date().toISOString().substring(0, 10);
+ toDateEl.value = config.syncConditionDateToValue ? config.syncConditionDateToValue.toISOString().substring(0, 10) : new Date().toISOString().substring(0, 10);
toDateField.setPlaceholder(i18nHelper.getMessage('110075'))
- .setValue(config.syncConditionDateFromValue)
+ .setValue(config.syncConditionDateToValue ? config.syncConditionDateToValue.toISOString().substring(0, 10) : new Date().toISOString().substring(0, 10))
.onChange(async (value) => {
if (!value) {
return;
}
- config.syncConditionDateFromValue = value;
+ try {
+ config.syncConditionDateToValue = new Date(value);
+ }catch (e) {
+ log.notice(i18nHelper.getMessage('110082'))
+ }
}).setDisabled(disable);
toDateEl.addClass('obsidian_douban_settings_input')
containerEl.appendChild(toDateEl);
+ new ButtonComponent(containerEl).setIcon('help').setTooltip(i18nHelper.getMessage('110095'))
}
\ No newline at end of file
diff --git a/src/org/wanxp/douban/data/model/HandleContext.ts b/src/org/wanxp/douban/data/model/HandleContext.ts
index eea65c0..8a3996d 100644
--- a/src/org/wanxp/douban/data/model/HandleContext.ts
+++ b/src/org/wanxp/douban/data/model/HandleContext.ts
@@ -26,5 +26,6 @@ export default interface HandleContext {
syncActive?:boolean;
searchPage?:SearchPageInfo;
+ syncOffset?:number;
}
diff --git a/src/org/wanxp/douban/data/model/SearchPage.ts b/src/org/wanxp/douban/data/model/SearchPage.ts
index 1f4aee8..6a27f6f 100644
--- a/src/org/wanxp/douban/data/model/SearchPage.ts
+++ b/src/org/wanxp/douban/data/model/SearchPage.ts
@@ -1,21 +1,14 @@
-import {SearchPageInfo} from "./SearchPageInfo";
-import {SupportType} from "../../../constant/Constsant";
+import { SearchPageInfo } from "./SearchPageInfo";
+import { SupportType } from "../../../constant/Constsant";
+import {SearchPageTypeOf} from "./SearchPageTypeOf";
-export class SearchPage extends SearchPageInfo{
+export class SearchPage extends SearchPageTypeOf {
- private _list:any[];
-
-
- constructor(total: number, pageNum: number, pageSize: number, type:SupportType, list: any[]) {
- super(total, pageNum, pageSize, type);
- this._list = list;
- }
-
- public get list() {
- return this._list;
- }
-
- public static empty(type:SupportType):SearchPage {
+ public static empty(type: SupportType): SearchPage {
return new SearchPage(0, 0, 0, type, []);
}
+
+ static emptyWithNoType() {
+ return new SearchPage(0, 0, 0, null, []);
+ }
}
diff --git a/src/org/wanxp/douban/data/model/SearchPageInfo.ts b/src/org/wanxp/douban/data/model/SearchPageInfo.ts
index 1224023..9a1dd8a 100644
--- a/src/org/wanxp/douban/data/model/SearchPageInfo.ts
+++ b/src/org/wanxp/douban/data/model/SearchPageInfo.ts
@@ -56,6 +56,10 @@ export class SearchPageInfo {
return this._total;
}
+ public set total(total: number) {
+ this._total = total;
+ }
+
get pageSize(): number {
return this._pageSize;
}
diff --git a/src/org/wanxp/douban/data/model/SearchPageTypeOf.ts b/src/org/wanxp/douban/data/model/SearchPageTypeOf.ts
new file mode 100644
index 0000000..3d3391b
--- /dev/null
+++ b/src/org/wanxp/douban/data/model/SearchPageTypeOf.ts
@@ -0,0 +1,29 @@
+import { SearchPageInfo } from "./SearchPageInfo";
+import { SupportType } from "../../../constant/Constsant";
+
+export class SearchPageTypeOf extends SearchPageInfo {
+ private _list: T[];
+
+ constructor(
+ total: number,
+ pageNum: number,
+ pageSize: number,
+ type: SupportType,
+ list: T[],
+ ) {
+ super(total, pageNum, pageSize, type);
+ this._list = list;
+ }
+
+ public get list() {
+ return this._list;
+ }
+
+ public static empty(type: SupportType): SearchPageTypeOf {
+ return new SearchPageTypeOf(0, 0, 0, type, []);
+ }
+
+ static emptyWithNoType() {
+ return new SearchPageTypeOf(0, 0, 0, null, []);
+ }
+}
diff --git a/src/org/wanxp/douban/data/model/SubjectListItem.ts b/src/org/wanxp/douban/data/model/SubjectListItem.ts
index 8c9bea2..1c96dc6 100644
--- a/src/org/wanxp/douban/data/model/SubjectListItem.ts
+++ b/src/org/wanxp/douban/data/model/SubjectListItem.ts
@@ -2,4 +2,5 @@ export interface SubjectListItem {
id:string;
url:string;
title:string;
+ updateDate: Date | null;
}
diff --git a/src/org/wanxp/douban/setting/TemplateSettingHelper.ts b/src/org/wanxp/douban/setting/TemplateSettingHelper.ts
index b2a7dde..769589e 100644
--- a/src/org/wanxp/douban/setting/TemplateSettingHelper.ts
+++ b/src/org/wanxp/douban/setting/TemplateSettingHelper.ts
@@ -38,7 +38,7 @@ export function createFileSelectionSetting({containerEl, name, desc, placeholder
if (oldValue) {
v = oldValue;
}
- new FileTreeSelectSuggest(manager.app, search.inputEl);
+ const fileTreeSelectSuggest = new FileTreeSelectSuggest(manager.app, search.inputEl, manager, key);
// @ts-ignore
search.setValue(v);
// @ts-ignore
@@ -48,6 +48,7 @@ export function createFileSelectionSetting({containerEl, name, desc, placeholder
search.onChange(async (value: string) => {
manager.updateSetting(key, value);
});
+
});
setting.addExtraButton((button) => {
diff --git a/src/org/wanxp/douban/setting/model/DoubanPluginSetting.ts b/src/org/wanxp/douban/setting/model/DoubanPluginSetting.ts
index fd6c4eb..90cde78 100644
--- a/src/org/wanxp/douban/setting/model/DoubanPluginSetting.ts
+++ b/src/org/wanxp/douban/setting/model/DoubanPluginSetting.ts
@@ -36,6 +36,7 @@ export interface DoubanPluginSetting {
pictureBedType: string;
pictureBedSetting: PictureBedSetting;
syncHandledDataArray: SyncHandledData[],
+ // syncLastUpdateTime: Map,
arraySettings: ArraySetting[],
- scoreSetting: ScoreSetting,
+ scoreSetting: ScoreSetting,
}
diff --git a/src/org/wanxp/douban/setting/model/FileTreeSelectSuggest.ts b/src/org/wanxp/douban/setting/model/FileTreeSelectSuggest.ts
index df453db..be0befc 100644
--- a/src/org/wanxp/douban/setting/model/FileTreeSelectSuggest.ts
+++ b/src/org/wanxp/douban/setting/model/FileTreeSelectSuggest.ts
@@ -1,8 +1,17 @@
-import {TAbstractFile, TFile, TFolder} from "obsidian";
+import {App, TAbstractFile, TFile, TFolder} from "obsidian";
import {TextInputSuggest} from "./TextInputSuggest";
+import SettingsManager from "../SettingsManager";
export class FileTreeSelectSuggest extends TextInputSuggest {
parentPath: string = "/";
+ settingKey: string = "";
+ manager: SettingsManager;
+
+ constructor(app: App, inputEl: HTMLInputElement, manager: SettingsManager, settingKey:string) {
+ super(app, inputEl);
+ this.manager = manager;
+ this.settingKey = settingKey;
+ }
getSuggestions(inputStr: string): TAbstractFile[] {
const files: TAbstractFile[] = [];
@@ -71,6 +80,8 @@ export class FileTreeSelectSuggest extends TextInputSuggest {
this.inputEl.value += "/";
this.inputEl.trigger("input");
}else {
+ //@ts-ignore
+ this.manager.updateSetting(this.settingKey, file.path);
this.close();
}
diff --git a/src/org/wanxp/douban/sync/handler/DoubanAbstractSyncHandler.ts b/src/org/wanxp/douban/sync/handler/DoubanAbstractSyncHandler.ts
index 494e2a7..ab4c419 100644
--- a/src/org/wanxp/douban/sync/handler/DoubanAbstractSyncHandler.ts
+++ b/src/org/wanxp/douban/sync/handler/DoubanAbstractSyncHandler.ts
@@ -1,25 +1,67 @@
import DoubanPlugin from "../../../main";
-import {BasicConst, SubjectHandledStatus, SyncType} from "../../../constant/Constsant";
-import {DoubanSyncHandler} from "./DoubanSyncHandler";
-import {SyncConfig} from "../model/SyncConfig";
+import {
+ BasicConst,
+ PAGE_SIZE,
+ SyncConditionType,
+ SyncType,
+} from "../../../constant/Constsant";
+import { DoubanSyncHandler } from "./DoubanSyncHandler";
+import { SyncConfig } from "../model/SyncConfig";
import HandleContext from "../../data/model/HandleContext";
-import {SubjectListItem} from "../../data/model/SubjectListItem";
-import {sleepRange} from "../../../utils/TimeUtil";
+import { SubjectListItem } from "../../data/model/SubjectListItem";
+import { sleepRange } from "../../../utils/TimeUtil";
import DoubanSubjectLoadHandler from "../../data/handler/DoubanSubjectLoadHandler";
-import {DoubanListHandler} from "./list/DoubanListHandler";
+import { DoubanListHandler } from "./list/DoubanListHandler";
import DoubanSubject from "../../data/model/DoubanSubject";
-import {log} from "../../../utils/Logutil";
-import {i18nHelper} from "../../../lang/helper";
+import { log } from "../../../utils/Logutil";
+import { i18nHelper } from "../../../lang/helper";
+import { SearchPage } from "../../data/model/SearchPage";
+import {SearchPageTypeOf} from "../../data/model/SearchPageTypeOf";
-export abstract class DoubanAbstractSyncHandler implements DoubanSyncHandler{
+function toDateList(dataList: SubjectListItem[]): Date[] {
+ const dateList = dataList
+ .map((item) => item.updateDate)
+ .sort((a, b) => {
+ try {
+ return a.getTime() - b.getTime();
+ } catch (e) {
+ }
+ return 0;
+ });
+ return dateList;
+}
+function testTouchEndCondition(searchPage: SearchPage, context: HandleContext) {
+ const { syncConfig } = context;
+ if (!syncConfig) {
+ return false;
+ }
+ switch (syncConfig.syncConditionType) {
+ case SyncConditionType.ALL:
+ return false;
+ case SyncConditionType.LAST_THIRTY:
+ return searchPage.pageNum >= 0;
+ case SyncConditionType.CUSTOM_ITEM:
+ const syncConditionCountToValue = syncConfig.syncConditionCountToValue? syncConfig.syncConditionCountToValue : searchPage.total;
+ return searchPage.start + PAGE_SIZE - 1 >= syncConditionCountToValue;
+ case SyncConditionType.CUSTOM_TIME:
+ return true;
+ }
+ return false;
+}
+
+export abstract class DoubanAbstractSyncHandler
+ implements DoubanSyncHandler
+{
private plugin: DoubanPlugin;
- private doubanSubjectLoadHandler:DoubanSubjectLoadHandler;
- private doubanListHandlers:DoubanListHandler[];
+ private doubanSubjectLoadHandler: DoubanSubjectLoadHandler;
+ private doubanListHandlers: DoubanListHandler[];
- constructor(plugin: DoubanPlugin,
- doubanSubjectLoadHandler:DoubanSubjectLoadHandler,
- doubanListHandlers:DoubanListHandler[]) {
+ constructor(
+ plugin: DoubanPlugin,
+ doubanSubjectLoadHandler: DoubanSubjectLoadHandler,
+ doubanListHandlers: DoubanListHandler[],
+ ) {
this.plugin = plugin;
this.doubanSubjectLoadHandler = doubanSubjectLoadHandler;
this.doubanListHandlers = doubanListHandlers;
@@ -31,61 +73,387 @@ export abstract class DoubanAbstractSyncHandler implem
abstract getSyncType(): SyncType;
- async sync(syncConfig: SyncConfig, context: HandleContext): Promise{
- return Promise.resolve()
- .then(() => this.getItems(syncConfig, context))
- .then(items => this.removeExists(items , syncConfig, context))
- .then(items => this.handleItems(items, context));
+ async sync(syncConfig: SyncConfig, context: HandleContext): Promise {
+ if (syncConfig.syncConditionType == SyncConditionType.CUSTOM_TIME) {
+ await this.syncByTimeLimit(syncConfig, context);
+ } else if (syncConfig.syncConditionType == SyncConditionType.CUSTOM_ITEM) {
+ await this.syncByCountLimit(syncConfig, context);
+ }else if (syncConfig.syncConditionType == SyncConditionType.ALL) {
+ await this.syncAll(syncConfig, context);
+ }else if (syncConfig.syncConditionType == SyncConditionType.LAST_THIRTY) {
+ await this.syncLastThirty(syncConfig, context);
+ }else {
+ log.warn(i18nHelper.getMessage("110083"));
+ }
}
+ async getByTimeLimit(syncConfig: SyncConfig, context: HandleContext): Promise {
+ let startDate = syncConfig.syncConditionDateFromValue
+ ? new Date(syncConfig.syncConditionDateFromValue)
+ : null;
+ let endDate = syncConfig.syncConditionDateToValue
+ ? new Date(syncConfig.syncConditionDateToValue)
+ : null;
+ if (!startDate && !endDate) {
+ log.warn(i18nHelper.getMessage("110081"));
+ return;
+ }
+ const cacheList = new Map>();
+ let searchPage = await this.getItems(syncConfig, context);
+ if (!searchPage) {
+ return;
+ }
+ const total = searchPage.total;
+ const lastPage = total / PAGE_SIZE + 1;
+ if (lastPage == 1) {
+ return searchPage.list;
+ }
+ let leftPage = 1;
+ let startPage = 1;
+ let rightPage = lastPage;
+ let endPage = lastPage;
+ let currentPage = 1;
+ cacheList.set(currentPage, searchPage);
+ if (startDate != null) {
+ do {
+ if (!context.plugin.statusHolder.syncing()) {
+ break;
+ }
+ let page = cacheList.get(currentPage);
+ if (!page) {
+ page = await this.getItems(syncConfig, context);
+ if (!page) {
+ break;
+ }
+ cacheList.set(currentPage, page);
+ }
+ const pageItems = page.list;
+ const pageDateList = toDateList(pageItems);
+ if (pageDateList[pageDateList.length - 1] >= startDate) {
+ leftPage = currentPage;
+ endPage = currentPage;
+ currentPage = Math.ceil((leftPage + rightPage) / 2);
+ }else {
+ rightPage = currentPage;
+ endPage = currentPage;
+ currentPage = Math.floor((leftPage + rightPage) / 2);
+ }
+ if (currentPage == leftPage || currentPage == rightPage) {
+ break;
+ }
+ } while (currentPage < lastPage);
+ }
+ leftPage = 1;
+ rightPage = lastPage;
+ currentPage = 1;
+ if (endDate != null) {
+ do {
+ if (!context.plugin.statusHolder.syncing()) {
+ break;
+ }
+ let page = cacheList.get(currentPage);
+ if (!page) {
+ page = await this.getItems(syncConfig, context);
+ if (!page) {
+ break;
+ }
+ cacheList.set(currentPage, page);
+ }
+ const pageItems = page.list;
+ const pageDateList = toDateList(pageItems);
+ if (pageDateList[0] <= endDate) {
+ rightPage = currentPage;
+ startPage = currentPage;
+ currentPage = Math.ceil((leftPage + rightPage) / 2);
+ }else {
+ leftPage = currentPage;
+ startPage = currentPage;
+ currentPage = Math.floor((leftPage + rightPage) / 2);
+ }
+ if (currentPage == leftPage || currentPage == rightPage) {
+ break;
+ }
+ } while (currentPage < lastPage);
+ }
+ let needHandleItems:SubjectListItem[] = [];
+ for (let pageNum = startPage; pageNum <= endPage; pageNum++) {
+ if (!context.plugin.statusHolder.syncing()) {
+ break;
+ }
+ let page = cacheList.get(pageNum);
+ if (!page) {
+ page = await this.getItems(syncConfig, context);
+ if (!page) {
+ break;
+ }
+ cacheList.set(pageNum, page);
+ }
+ const pageItems = page.list;
+ needHandleItems = needHandleItems.concat(pageItems
+ .filter((item) => {
+ const itemDate = item.updateDate;
+ return (!startDate || itemDate >= startDate) && (!endDate || itemDate <= endDate);
+ }
+ ));
+ }
+ return needHandleItems;
+
+ }
+ async syncByTimeLimit(syncConfig: SyncConfig, context: HandleContext) {
+ const items = await this.getByTimeLimit(syncConfig, context);
+ if (!items || items.length == 0) {
+ return;
+ }
+
+ let subjectListItems = await this.removeExists(
+ items,
+ syncConfig,
+ context,
+ );
+
+ const searchPage = new SearchPageTypeOf(subjectListItems.length,
+ 1,
+ subjectListItems.length,
+ null,subjectListItems);
+ await this.handleItems(searchPage, subjectListItems, context);
- private async getItems(syncConfig:SyncConfig, context:HandleContext):Promise {
- const supportHandlers:DoubanListHandler[] = this.doubanListHandlers.filter((h) => h.support(syncConfig));
- let items:SubjectListItem[] = [];
- for(const handler of supportHandlers) {
- if (!context.plugin.statusHolder.syncing()) {
- return [];
- }
- const item = await handler.getAllPageList(context);
- if (item) {
- items = items.concat(item);
- }
- }
- return items;
}
- private async removeExists(items:SubjectListItem[], syncConfig: SyncConfig, context: HandleContext):Promise {
+ private async getItems(
+ syncConfig: SyncConfig,
+ context: HandleContext,
+ ): Promise> {
+ const supportHandlers: DoubanListHandler[] =
+ this.doubanListHandlers.filter((h) => h.support(syncConfig));
+ const handler = supportHandlers[0];
+ if (!context.plugin.statusHolder.syncing()) {
+ return SearchPage.emptyWithNoType();
+ }
+ const item = await handler.getPageData(context);
+ if (!context.plugin.statusHolder.syncing()) {
+ return SearchPage.emptyWithNoType();
+ }
+ return item;
+ }
+
+ private async removeExists(
+ items: SubjectListItem[],
+ syncConfig: SyncConfig,
+ context: HandleContext,
+ ): Promise {
if (!context.plugin.statusHolder.syncing()) {
return [];
}
return items;
}
- private async handleItems(items:SubjectListItem[], context:HandleContext):Promise {
+ private async handleItems(
+ searchPage: SearchPage,
+ items: SubjectListItem[],
+ context: HandleContext,
+ ): Promise {
if (!items || items.length == 0) {
- return ;
+ return;
}
- const {syncStatus} = context.syncStatusHolder;
- syncStatus.totalNum(items.length);
- const needHandled:number = items.filter(item => syncStatus.shouldSync(item.id)).length;
+ const { syncStatus } = context.syncStatusHolder;
+ syncStatus.totalNum(searchPage.total);
+ const needHandled: number =
+ syncStatus.getTotal() - syncStatus.getHasHandle();
syncStatus.setNeedHandled(needHandled);
for (const item of items) {
if (!context.plugin.statusHolder.syncing()) {
return;
}
try {
- if(syncStatus.shouldSync(item.id)) {
- let subject: DoubanSubject = await this.doubanSubjectLoadHandler.handle(item.id, context);
- await sleepRange(BasicConst.CALL_DOUBAN_DELAY, BasicConst.CALL_DOUBAN_DELAY + BasicConst.CALL_DOUBAN_DELAY_RANGE);
- }else {
+ if (syncStatus.shouldSync(item.id)) {
+ let subject: DoubanSubject =
+ await this.doubanSubjectLoadHandler.handle(
+ item.id,
+ context,
+ );
+
+ await sleepRange(
+ BasicConst.CALL_DOUBAN_DELAY,
+ BasicConst.CALL_DOUBAN_DELAY +
+ BasicConst.CALL_DOUBAN_DELAY_RANGE,
+ );
+ } else {
syncStatus.unHandle(item.id, item.title);
}
- }catch (e) {
- log.notice(i18nHelper.getMessage('130120'))
+ } catch (e) {
+ log.notice(i18nHelper.getMessage("130120"));
}
}
}
+ private async syncByCountLimit(syncConfig: SyncConfig, context: HandleContext) {
+ const {syncConditionCountFromValue, syncConditionCountToValue} = syncConfig;
+ const startOffset = Math.floor((syncConditionCountFromValue - 1)/ PAGE_SIZE) * PAGE_SIZE;
+ context.syncOffset = startOffset;
+ //结束点是第几条
+ let endOffsetNumberForCustom = 0;
+ let needHandleTotalCustomItem = 0;
+ let isFirstStep = true;
+ let handleCount = 0;
+ do {
+ let searchPage = await this.getItems(syncConfig, context);
+ if (!context.plugin.statusHolder.syncing()) {
+ break;
+ }
+ const {list, total} = searchPage;
+ if (
+ !searchPage ||
+ !list ||
+ list.length == 0
+ ) {
+ break;
+ }
+ if (syncConditionCountFromValue > total) {
+ context.syncStatusHolder.syncStatus.setMessage(i18nHelper.getMessage("130121", total));
+ break;
+ }
+ if (endOffsetNumberForCustom == 0) {
+ endOffsetNumberForCustom = Math.min(syncConditionCountToValue?syncConditionCountToValue:searchPage.total, searchPage.total);
+ needHandleTotalCustomItem = endOffsetNumberForCustom - syncConditionCountFromValue + 1;
+
+ }
+ let subjectListItems = [];
+
+ //在开始和结束同一页
+ if (Math.floor((syncConditionCountFromValue - 1) / PAGE_SIZE) == Math.floor((endOffsetNumberForCustom - 1) / PAGE_SIZE)) {
+ const startIndex = Math.floor((syncConditionCountFromValue - 1) % PAGE_SIZE);
+ const endIndex = Math.floor((endOffsetNumberForCustom - 1) % PAGE_SIZE);
+ subjectListItems = await this.removeExists(
+ list.slice(startIndex, endIndex + 1),
+ syncConfig,
+ context,
+ );
+ handleCount += (endIndex - startIndex + 1);
+ //第一页
+ } else if (isFirstStep) {
+ const startIndex = (syncConditionCountFromValue - 1) % PAGE_SIZE;
+ handleCount += (list.length - startIndex);
+ subjectListItems = await this.removeExists(
+ list.slice(startIndex),
+ syncConfig,
+ context,
+ );
+ isFirstStep = false;
+ }
+ //最后一页
+ else if (needHandleTotalCustomItem - handleCount <= PAGE_SIZE) {
+ const endIndex = needHandleTotalCustomItem - handleCount;
+ subjectListItems = await this.removeExists(
+ list.slice(0, endIndex),
+ syncConfig,
+ context,
+ );
+ handleCount += endIndex;
+ //中间页
+ } else {
+ subjectListItems = await this.removeExists(
+ list,
+ syncConfig,
+ context,
+ );
+ handleCount += PAGE_SIZE;
+ }
+
+
+ if (!subjectListItems || subjectListItems.length == 0) {
+ await sleepRange(
+ BasicConst.CALL_DOUBAN_DELAY,
+ BasicConst.CALL_DOUBAN_DELAY +
+ BasicConst.CALL_DOUBAN_DELAY_RANGE,
+ );
+ continue;
+ }
+
+ searchPage.total = needHandleTotalCustomItem;
+ //处理
+ await this.handleItems(searchPage, subjectListItems, context);
+
+ context.syncOffset = context.syncOffset + PAGE_SIZE;
+ await sleepRange(
+ BasicConst.CALL_DOUBAN_DELAY,
+ BasicConst.CALL_DOUBAN_DELAY +
+ BasicConst.CALL_DOUBAN_DELAY_RANGE,
+ );
+ } while (handleCount < needHandleTotalCustomItem);
+ }
+
+ private async syncAll(syncConfig: SyncConfig, context: HandleContext) {
+ //最多100000条
+ context.syncOffset = 0;
+ let handleCount = 0;
+ let totalForHandle = 0;
+ let isFirstStep = true;
+ do {
+ let searchPage = await this.getItems(syncConfig, context);
+ if (!context.plugin.statusHolder.syncing()) {
+ break;
+ }
+
+ const {list, total} = searchPage;
+ if (
+ !searchPage ||
+ !list ||
+ list.length == 0
+ ) {
+ break;
+ }
+ if (isFirstStep) {
+ totalForHandle = total;
+ isFirstStep = false;
+ }
+ handleCount += list.length;
+ let subjectListItems = await this.removeExists(
+ list,
+ syncConfig,
+ context,
+ );
+ if (!subjectListItems || subjectListItems.length == 0) {
+ await sleepRange(
+ BasicConst.CALL_DOUBAN_DELAY,
+ BasicConst.CALL_DOUBAN_DELAY +
+ BasicConst.CALL_DOUBAN_DELAY_RANGE,
+ );
+ continue;
+ }
+ await this.handleItems(searchPage, subjectListItems, context);
+ context.syncOffset = context.syncOffset + PAGE_SIZE;
+ await sleepRange(
+ BasicConst.CALL_DOUBAN_DELAY,
+ BasicConst.CALL_DOUBAN_DELAY +
+ BasicConst.CALL_DOUBAN_DELAY_RANGE,
+ );
+ } while (handleCount <= totalForHandle);
+ }
+
+ private async syncLastThirty(syncConfig: SyncConfig, context: HandleContext) {
+ context.syncOffset = 0;
+ let searchPage = await this.getItems(syncConfig, context);
+ if (!context.plugin.statusHolder.syncing()) {
+ return;
+ }
+ const {list, total} = searchPage;
+ if (
+ !searchPage ||
+ !list ||
+ list.length == 0
+ ) {
+ return;
+ }
+
+ let subjectListItems = await this.removeExists(
+ list,
+ syncConfig,
+ context,
+ );
+ if (!subjectListItems || subjectListItems.length == 0) {
+ return;
+ }
+ searchPage.total = Math.min(list.length, total);
+ await this.handleItems(searchPage, subjectListItems, context);
+ }
}
-
-
diff --git a/src/org/wanxp/douban/sync/handler/SyncHandler.ts b/src/org/wanxp/douban/sync/handler/SyncHandler.ts
index 4cb419e..90cbdf3 100644
--- a/src/org/wanxp/douban/sync/handler/SyncHandler.ts
+++ b/src/org/wanxp/douban/sync/handler/SyncHandler.ts
@@ -9,6 +9,7 @@ import { DoubanMusicSyncHandler } from "./DoubanMusicSyncHandler";
import { DoubanBookSyncHandler } from "./DoubanBookSyncHandler";
import {i18nHelper} from "../../../lang/helper";
import {DoubanTeleplaySyncHandler} from "./DoubanTeleplaySyncHandler";
+import {SyncConditionType} from "../../../constant/Constsant";
export default class SyncHandler {
private app: App;
@@ -18,6 +19,7 @@ export default class SyncHandler {
private syncHandlers: DoubanSyncHandler[];
private defaultSyncHandler: DoubanSyncHandler;
+
constructor(app: App, plugin: DoubanPlugin, syncConfig: SyncConfig, context: HandleContext) {
this.app = app;
this.plugin = plugin;
@@ -38,6 +40,10 @@ export default class SyncHandler {
async sync() {
if (this.syncConfig && this.syncConfig.syncType && this.syncConfig.scope) {
+ if(this.checkSyncConfig()) {
+ this.context.syncStatusHolder.syncStatus.setMessage(this.checkSyncConfig());
+ return;
+ }
let syncHandler = this.syncHandlers.find(handler => handler.support(this.syncConfig.syncType));
if (syncHandler) {
await syncHandler.sync(this.syncConfig, this.context);
@@ -53,6 +59,25 @@ export default class SyncHandler {
const {syncStatus} = syncStatusHolder;
const {statusHandleMap} = syncStatus;
const {syncResultMap} = syncStatus;
+ const {syncConfig} = this;
+
+ let extendCondition = '';
+ if (syncConfig.syncConditionType == SyncConditionType.CUSTOM_ITEM) {
+ extendCondition = `${syncConfig.syncConditionCountFromValue} - ${syncConfig.syncConditionCountToValue}`;
+ } else if (syncConfig.syncConditionType == SyncConditionType.CUSTOM_TIME) {
+ extendCondition = `${syncConfig.syncConditionDateFromValue.toISOString().substring(0, 10)} - ${syncConfig.syncConditionDateToValue.toISOString().substring(0, 10)}`;
+ }
+
+
+ const condition = `
+1. ${i18nHelper.getMessage('110030')} \`${syncStatus.getTypeName()}\`
+2. ${i18nHelper.getMessage('110032')} \`${syncStatus.getScopeName()}\`
+3. ${i18nHelper.getMessage('110070')} \`${syncStatus.getSyncConditionName()}\`${extendCondition? (' => ' + extendCondition) : ''}
+4. ${i18nHelper.getMessage('110039')} \`${syncConfig.incrementalUpdate?i18nHelper.getMessage('110055'):i18nHelper.getMessage('110056')}\`
+5. ${i18nHelper.getMessage('110031')} \`${syncConfig.force?i18nHelper.getMessage('110055'):i18nHelper.getMessage('110056')}\`
+`
+
+
let summary:string
= `${i18nHelper.getMessage('110053', i18nHelper.getMessage('110050'), i18nHelper.getMessage('110051'), i18nHelper.getMessage('110052'))}
|-----|----|----------------------------------|
@@ -79,8 +104,28 @@ export default class SyncHandler {
}
}
- const result : string = i18nHelper.getMessage('110037', summary, details);
+ const result : string = i18nHelper.getMessage('110037', condition, summary, details);
const resultFileName = `${i18nHelper.getMessage('110038')}_${moment(new Date()).format('YYYYMMDDHHmmss')}`
await this.plugin.fileHandler.createNewNoteWithData(`${this.syncConfig.dataFilePath}/${resultFileName}`, result, true);
}
+
+ private checkSyncConfig() {
+ const {syncConfig} = this;
+ switch (syncConfig.syncConditionType) {
+ case SyncConditionType.CUSTOM_ITEM:
+ if (syncConfig.syncConditionCountFromValue && syncConfig.syncConditionCountToValue) {
+ if (syncConfig.syncConditionCountFromValue > syncConfig.syncConditionCountToValue) {
+ return i18nHelper.getMessage('110044');
+ }
+ }
+ break;
+ case SyncConditionType.CUSTOM_TIME:
+ if (syncConfig.syncConditionDateToValue && syncConfig.syncConditionDateFromValue) {
+ if (syncConfig.syncConditionDateFromValue > syncConfig.syncConditionDateToValue) {
+ return i18nHelper.getMessage('110045');
+ }
+ }
+
+ }
+ }
}
diff --git a/src/org/wanxp/douban/sync/handler/list/DoubanAbstractListHandler.ts b/src/org/wanxp/douban/sync/handler/list/DoubanAbstractListHandler.ts
index 5b461a4..a56cbba 100644
--- a/src/org/wanxp/douban/sync/handler/list/DoubanAbstractListHandler.ts
+++ b/src/org/wanxp/douban/sync/handler/list/DoubanAbstractListHandler.ts
@@ -1,88 +1,124 @@
-import { request, RequestUrlParam} from "obsidian";
-import {i18nHelper} from 'src/org/wanxp/lang/helper';
-import {log} from "src/org/wanxp/utils/Logutil";
-import {CheerioAPI, load} from "cheerio";
+import { request, RequestUrlParam } from "obsidian";
+import { i18nHelper } from "src/org/wanxp/lang/helper";
+import { log } from "src/org/wanxp/utils/Logutil";
+import { CheerioAPI, load } from "cheerio";
import HandleContext from "../../../data/model/HandleContext";
-import {doubanSubjectSyncListUrl} from "../../../../constant/Douban";
-import {BasicConst, PAGE_SIZE, SyncType, SyncTypeUrlDomain} from "../../../../constant/Constsant";
-import {SubjectListItem} from "../../../data/model/SubjectListItem";
-import {DoubanListHandler} from "./DoubanListHandler";
-import {SyncConfig} from "../../model/SyncConfig";
-import { sleepRange} from "../../../../utils/TimeUtil";
-import {ALL} from "../../../../constant/DoubanUserState";
+import { doubanSubjectSyncListUrl } from "../../../../constant/Douban";
+import {
+ BasicConst,
+ PAGE_SIZE,
+ SyncType,
+ SyncTypeUrlDomain,
+} from "../../../../constant/Constsant";
+import { SubjectListItem } from "../../../data/model/SubjectListItem";
+import { DoubanListHandler } from "./DoubanListHandler";
+import { SyncConfig } from "../../model/SyncConfig";
+import { sleepRange } from "../../../../utils/TimeUtil";
+import { ALL } from "../../../../constant/DoubanUserState";
import HttpUtil from "../../../../utils/HttpUtil";
-import {DoubanHttpUtil} from "../../../../utils/DoubanHttpUtil";
+import { DoubanHttpUtil } from "../../../../utils/DoubanHttpUtil";
+import { SearchPage } from "../../../data/model/SearchPage";
+import {SearchPageTypeOf} from "../../../data/model/SearchPageTypeOf";
-export default abstract class DoubanAbstractListHandler implements DoubanListHandler{
+export default abstract class DoubanAbstractListHandler
+ implements DoubanListHandler
+{
+ async getPageData(context: HandleContext): Promise {
+ let all: SubjectListItem[] = [];
+ let pages: SearchPage = SearchPage.emptyWithNoType();
- async getAllPageList(context: HandleContext):Promise{
- let all:SubjectListItem[] = [];
- let pages:SubjectListItem[] = [];
- let start = 0;
- do {
- await sleepRange(BasicConst.CALL_DOUBAN_DELAY,
- BasicConst.CALL_DOUBAN_DELAY + BasicConst.CALL_DOUBAN_DELAY_RANGE);
- const url:string = this.getUrl(context, start);
- if (!context.plugin.statusHolder.syncing()) {
- return [];
- }
- pages = await this.getPageList(url, context);
- if (pages) {
- all = all.concat(pages);
- }
- start = start + PAGE_SIZE;
- } while (pages && pages.length > 0)
- return all;
+ const url: string = this.getUrl(context, context.syncOffset);
+ if (!context.plugin.statusHolder.syncing()) {
+ return SearchPage.emptyWithNoType();
+ }
+ let subjectListItemSearchPageTypeOf = await this.getPageList(url, context);
+ if (subjectListItemSearchPageTypeOf) {
+ context.plugin.statusHolder.syncStatus.setAllTotal(subjectListItemSearchPageTypeOf.total)
+ }
+ return subjectListItemSearchPageTypeOf;
}
- async delay(ms: number) {
+ async delay(ms: number) {}
+
+ private getUrl(context: HandleContext, start: number) {
+ return doubanSubjectSyncListUrl(
+ this.getSyncTypeDomain(),
+ context.userComponent.getUserId(),
+ this.getDoType(),
+ start,
+ );
}
- private getUrl(context: HandleContext, start:number) {
- return doubanSubjectSyncListUrl(this.getSyncTypeDomain(), context.userComponent.getUserId(), this.getDoType(), start);
- }
+ abstract getDoType(): string;
- abstract getDoType():string;
+ abstract getSyncType(): SyncType;
- abstract getSyncType():SyncType;
-
- getSyncTypeDomain():string {
+ getSyncTypeDomain(): string {
return SyncTypeUrlDomain.get(this.getSyncType());
}
- async getPageList(url: string, context: HandleContext):Promise {
- return DoubanHttpUtil.httpRequestGet(url, context.plugin.settingsManager.getHeaders(), context.plugin.settingsManager)
+ async getPageList(
+ url: string,
+ context: HandleContext,
+ ): Promise> {
+ return DoubanHttpUtil.httpRequestGet(
+ url,
+ context.plugin.settingsManager.getHeaders(),
+ context.plugin.settingsManager,
+ )
.then(load)
- .then(data => this.parseSubjectFromHtml(data, context))
- .catch(e => log
- .error(
- i18nHelper.getMessage('130101')
- .replace('{0}', e.toString())
- , e));
- ;
-
+ .then((data) => this.parseSubjectFromHtml(data, context))
+ .catch((e) =>
+ log.error(
+ i18nHelper
+ .getMessage("130101")
+ .replace("{0}", e.toString()),
+ e,
+ ),
+ );
}
-
-
-
-
- parseSubjectFromHtml(dataHtml: CheerioAPI, context: HandleContext):SubjectListItem[] {
- return dataHtml('.item-show')
+ parseSubjectFromHtml(
+ dataHtml: CheerioAPI,
+ context: HandleContext,
+ ): SearchPageTypeOf {
+ const items = dataHtml(".item-show")
.get()
.map((i: any) => {
const item = dataHtml(i);
- const linkValue:string = item.find('div.title > a').attr('href');
- const titleValue:string = item.find('div.title > a').text().trim();
+ const linkValue: string = item
+ .find("div.title > a")
+ .attr("href");
+ const titleValue: string = item
+ .find("div.title > a")
+ .text()
+ .trim();
+ const updateDateStr: string = item.find("div.date").text().trim();
+ let updateDate = null;
+ try {
+ updateDate = new Date(updateDateStr);
+ }catch (e) {
+ console.error(e);
+ log.info("parse date error:" + titleValue);
+ }
let idPattern = /(\d){5,10}/g;
let ececResult = idPattern.exec(linkValue);
- return ececResult?{id: ececResult[0], url: linkValue, title: titleValue}:null;
+ return !ececResult ? null : {id: ececResult[0], url: linkValue, title: titleValue, updateDate: updateDate};
// return linkValue;
- })
+ });
+ const subjectNumText = dataHtml(".subject-num").text().trim();
+ const totalNumMatch = subjectNumText.match(/\/\s*(\d+)/);
+ const totalNum = totalNumMatch ? parseInt(totalNumMatch[1], 10) : 0;
+ return new SearchPage(
+ totalNum,
+ Math.floor(context.syncOffset / PAGE_SIZE) + 1,
+ PAGE_SIZE,
+ null,
+ items,
+ );
}
support(config: SyncConfig): boolean {
return this.getDoType() == config.scope || ALL == config.scope;
}
}
-
diff --git a/src/org/wanxp/douban/sync/handler/list/DoubanListHandler.ts b/src/org/wanxp/douban/sync/handler/list/DoubanListHandler.ts
index 252cc62..1d35c7c 100644
--- a/src/org/wanxp/douban/sync/handler/list/DoubanListHandler.ts
+++ b/src/org/wanxp/douban/sync/handler/list/DoubanListHandler.ts
@@ -1,10 +1,10 @@
import HandleContext from "../../../data/model/HandleContext";
-import {SubjectListItem} from "../../../data/model/SubjectListItem";
import {SyncConfig} from "../../model/SyncConfig";
+import {SearchPage} from "../../../data/model/SearchPage";
export interface DoubanListHandler {
- getAllPageList(context: HandleContext):Promise;
+ getPageData(context: HandleContext):Promise;
support(config:SyncConfig):boolean;
}
diff --git a/src/org/wanxp/douban/sync/model/SyncConfig.ts b/src/org/wanxp/douban/sync/model/SyncConfig.ts
index 03b89d6..22c7fe6 100644
--- a/src/org/wanxp/douban/sync/model/SyncConfig.ts
+++ b/src/org/wanxp/douban/sync/model/SyncConfig.ts
@@ -1,10 +1,10 @@
export interface SyncConfig {
syncType: string,
syncConditionType: string,
- syncConditionCountFromValue: string,
- syncConditionCountToValue: string,
- syncConditionDateFromValue: string,
- syncConditionDateToValue: string,
+ syncConditionCountFromValue: number,
+ syncConditionCountToValue: number,
+ syncConditionDateFromValue: Date,
+ syncConditionDateToValue: Date,
scope: string,
force: boolean,
dataFilePath: string;
diff --git a/src/org/wanxp/douban/sync/model/SyncItemResult.ts b/src/org/wanxp/douban/sync/model/SyncItemResult.ts
index e26580f..f55ec67 100644
--- a/src/org/wanxp/douban/sync/model/SyncItemResult.ts
+++ b/src/org/wanxp/douban/sync/model/SyncItemResult.ts
@@ -1,7 +1,7 @@
-import {SyncItemStatus} from "../../../constant/Constsant";
+import { SyncItemStatus } from "../../../constant/Constsant";
export interface SyncItemResult {
- id:string,
- title:string,
- status:SyncItemStatus,
+ id: string;
+ title: string;
+ status: SyncItemStatus;
}
diff --git a/src/org/wanxp/douban/sync/model/SyncStatusHolder.ts b/src/org/wanxp/douban/sync/model/SyncStatusHolder.ts
index 5d7c0cf..aca69ef 100644
--- a/src/org/wanxp/douban/sync/model/SyncStatusHolder.ts
+++ b/src/org/wanxp/douban/sync/model/SyncStatusHolder.ts
@@ -1,7 +1,18 @@
import {SyncConfig} from "./SyncConfig";
import {SyncItemResult} from "./SyncItemResult";
-import {BasicConst, SyncItemStatus} from "../../../constant/Constsant";
+import {
+ BasicConst,
+ SupportType,
+ SyncConditionTypeRecords,
+ SyncItemStatus,
+ SyncTypeRecords
+} from "../../../constant/Constsant";
import {SyncHandledData} from "../../setting/model/SyncHandledData";
+import {
+ DoubanSubjectState,
+ DoubanSubjectStateRecords,
+ DoubanSubjectStateRecords_SYNC
+} from "../../../constant/DoubanUserState";
export default class SyncStatusHolder {
@@ -12,15 +23,20 @@ export default class SyncStatusHolder {
[SyncItemStatus.replace, 0],
[SyncItemStatus.create, 0],
[SyncItemStatus.fail, 0],
- [SyncItemStatus.unHandle, 0],
+ [SyncItemStatus.failByDiffType, 0],
+ [SyncItemStatus.unHandle, 0],
]);
private key: string;
+ //不管处不处理的总数,比如会包含已经存在的,或者条件没覆盖的部分,比如过滤条件选择了1-2条,但总共其实有10条
+ private allTotal: number;
public syncConfig: SyncConfig;
+ //处理的总数
private total:number;
private handle:number;
private needHandled:number;
+ private message:string = '';
constructor(syncConfig: SyncConfig) {
this.syncConfig = syncConfig;
@@ -46,6 +62,16 @@ export default class SyncStatusHolder {
return this.handle;
}
+ getAllTotal():number {
+ return this.allTotal;
+ }
+
+ setAllTotal(allTotal:number) {
+ this.allTotal = allTotal;
+ }
+
+
+
/**
* 已处理总数,包含已经存在不需要同步的部分
*/
@@ -86,6 +112,10 @@ export default class SyncStatusHolder {
this.updateResult(id, title, SyncItemStatus.fail);
}
+ public failByDiffType(id:string, title:string) {
+ this.updateResult(id, title, SyncItemStatus.failByDiffType);
+ }
+
private updateResult(id:string, title:string, status:SyncItemStatus) {
this.syncResultMap.set(id, {id: id,title:title,status:status});
this.statusHandleMap.set(status, this.statusHandleMap.get(status) + 1);
@@ -161,4 +191,26 @@ export default class SyncStatusHolder {
return false;
}
+ public setMessage(s: string) {
+ this.message = s;
+ }
+
+ public getMessage() {
+ return this.message;
+ }
+
+ public getScopeName():string {
+ //@ts-ignore
+ return DoubanSubjectStateRecords_SYNC[this.syncConfig.syncType][this.syncConfig.scope];
+ }
+
+ public getTypeName():string {
+ return SyncTypeRecords[this.syncConfig.syncType];
+
+
+ }
+
+ public getSyncConditionName() {
+ return SyncConditionTypeRecords[this.syncConfig.syncConditionType];
+ }
}
diff --git a/src/org/wanxp/lang/helper.ts b/src/org/wanxp/lang/helper.ts
index 11b310d..782e907 100644
--- a/src/org/wanxp/lang/helper.ts
+++ b/src/org/wanxp/lang/helper.ts
@@ -11,19 +11,34 @@ const locale = localeMap[lang || 'en'];
export default class I18nHelper {
- public getMessage(str: keyof typeof en, ...params: any[]): string {
+ public getMessage(str: keyof typeof en | string, ...params: any[]): string {
if (!locale) {
console.error('Error: obsidian douban locale not found', lang);
}
-
+ // @ts-ignore
let val:string = (locale && locale[str]) || en[str];
if (params) {
for (let i:number = 0;i < params.length;i++) {
- val = val.replaceAll(`{${i}}`, params[i])
+ val = this.replaceAll(i, val, params[i])
}
}
return val;
}
+
+ private replaceAll(index: number, message: string, replace: string): string {
+ const placeholderRegex = new RegExp(`\\{${index}:([^}]+)\\}`);
+ const match = message.match(placeholderRegex);
+ if (!match) {
+ return message.replaceAll(`{${index}}`, replace);
+ }
+ const defaultValue = match ? match[1] : '';
+
+ // If replace is undefined or null, use the default value
+ const replacement = (replace === undefined || replace === null) ? defaultValue : replace;
+
+ // Replace the specific placeholder with the replacement value
+ return message.replace(placeholderRegex, replacement);
+ }
}
export const i18nHelper: I18nHelper = new I18nHelper();
diff --git a/src/org/wanxp/lang/locale/en.ts b/src/org/wanxp/lang/locale/en.ts
index 78d3293..949fcb4 100644
--- a/src/org/wanxp/lang/locale/en.ts
+++ b/src/org/wanxp/lang/locale/en.ts
@@ -23,12 +23,15 @@ export default {
'110035': `FileName: (Tip:Support Variables And Path)`,
'110036': `Complete`,
'110037': `
-### Summary
+### Condition
{0}
-### Details
+### Summary
{1}
+### Details
+{2}
+
---
PS: This file could be delete if you want to.
`,
@@ -38,16 +41,20 @@ PS: This file could be delete if you want to.
'110041': `IncrementalSync`,
'110042': `EstimateTime`,
'110043': `Loading Menu`,
+ '110044': `Custom Count Input End Must Bigger Than Start`,
+ '110045': `Custom Time Input End Must Bigger Than Start`,
'110050': `Type`,
'110051': `Number`,
'110052': `Description`,
'110152': `Confirm`,
+ '110055': `Enable`,
+ '110056': `Disable`,
'110070': `Sync Scope:`,
'110071': `All`,
'110072': `Recent Changes`,
- '110075': `Last 10 Items`,
+ '110075': `Last 30 Items`,
'110074': `Custom Time`,
'110076': `Custom Count`,
'110077': `From`,
@@ -55,12 +62,21 @@ PS: This file could be delete if you want to.
'110079': `To`,
'110073': `Items`,
'110080': `Number`,
+ '112080': `Custom Count Input not a number`,
+ '110081': `Custom Time must input both start and end or only one`,
+ '110082': `Custom Time must input format: YYYY-MM-DD`,
+ '110083': `Not Support`,
+ '110090': `The total number of {0} for status {1} is {2}, and the number that needs to be synchronized is {3}`,
+ '110091': `Error`,
+ '110095': `The smaller the number, the closer to now. For example, the latest update on Douban is the first one, and the earliest update is the last one.`,
+ '110096': `This is the update time of our entry on Douban`,
'exists':`[exists]`,
'unHandle':`[unHandle]`,
'replace':`[replace]`,
'create':`[create]`,
'fail':`[fail]`,
+ 'failByDiffType': `[fail by diff type]`,
'syncall':`[summary]`,
'notsync':`[notsync]`,
@@ -69,6 +85,7 @@ PS: This file could be delete if you want to.
'replace_desc': `replace`,
'create_desc': `create`,
'fail_desc': `fail`,
+ 'failByDiffType_desc': `fail because of different type`,
'notsync_desc': `notsync`,
'syncall_desc': `syncall`,
@@ -309,6 +326,7 @@ PS: This file could be delete if you want to.
'130107': `Can not find array setting for {1} in {0} , Please add it in array settings`,
'130108': `Redirect times too much, please check your network or proxy`,
'130120': `An error occurred during Sync, but Sync will continue. Error item is {}`,
+ '130121': `An error occurred during Sync, Begin number is bigger than total number {0}, will not sync this item`,
'140201': `[OB-Douban]: searching '{0}'...`,
'140202': `[OB-Douban]: result {0} rows`,
diff --git a/src/org/wanxp/lang/locale/zh-cn.ts b/src/org/wanxp/lang/locale/zh-cn.ts
index a3a3c24..ec219ec 100644
--- a/src/org/wanxp/lang/locale/zh-cn.ts
+++ b/src/org/wanxp/lang/locale/zh-cn.ts
@@ -28,22 +28,38 @@ export default {
'110070': `同步范围:`,
'110071': `全部`,
'110072': `最新变动`,
- '110075': `最近10条`,
+ '110075': `最近30条`,
'110074': `自定义时间`,
'110076': `自定义条数`,
'110077': `从`,
'110078': `第`,
'110079': `到`,
'110073': `条`,
+ '110095': `数字越小代表越接近现在,比如在豆瓣上我们最新更新一条内容为第一条,反之最早更新的就是最后一条了`,
+ '110096': `这是我们在豆瓣上条目的更新时间`,
+
'110080': `数字`,
+ '112080': `自定义的数量输入不是个数字`,
+ '110081': `开始时间和结束时间必须填写一个或都填写`,
+ '110082': `时间录入格式必须是YYYY-MM-DD`,
+ '110083': `不支持当前同步条件`,
+ '110090': `[{0:未知}]状态为[{1:未知}]的总数为{2:未知},当前需要同步数为{3::未知}`,
+ '110091': `异常:`,
+ '110092': `情况:`,
+
+
+
'110037': `
-### 同步结果汇总
+### 同步条件
{0}
+### 同步结果汇总
+{1}
+
### 同步结果明细
{1}
@@ -52,20 +68,26 @@ export default {
`,
'110038': `豆瓣同步结果`,
'110039': `增量同步:`,
- '110040': `仅同步上面'笔记存放位置'目录中最近新增/同步失败/未同步的部分,不同步已同步的内容.若关闭则会全量同步.增量同步会更快,适合之前同步中途失败停止或最近有豆瓣新增了内容,全量同步适合修改了模板或修改了存放路径情况下进行.`,
+ '110040': `仅同步最近新增/同步失败/未同步的部分,增量适合之前同步中途失败停止或最近有豆瓣新增了内容,全量同步适合修改了模板或修改了存放路径情况下进行.`,
'110041': `使用增量`,
'110042': `预计处理时间`,
'110043': `正在获取需要同步的列表, 请稍后`,
+ '110044': `自定义条数的录入结束数量不能比开始数量小`,
+ '110045': `自定义时间的录入结束时间不能比开始时间小`,
+
'110050': `类型`,
'110051': `数量`,
'110052': `说明`,
+ '110055': `开启`,
+ '110056': `关闭`,
'unHandle':`[已忽略]`,
'exists': `[未替换]`,
'replace': `[已替换]`,
'create': `[已创建]`,
'fail': `[已失败]`,
+ 'failByDiffType': `[类型不匹配]`,
'syncall': `[总数]`,
'notsync': `[未进行]`,
@@ -74,6 +96,7 @@ export default {
'replace_desc': `已经存在的同名文档,这次已被替换`,
'create_desc': `之前不存在的文档,这次直接新增`,
'fail_desc': `处理过程钟出现错误,未能成功`,
+ 'failByDiffType_desc': `失败,类型不匹配,比如想要同步的是电影,但是实际获取到的是电视剧`,
'notsync_desc': `因异常中断或提前终止导致还未处理`,
'syncall_desc': `您此次同步条件在豆瓣中的条目总数`,
@@ -308,6 +331,7 @@ export default {
'130106': `请尝试在Douban插件中登录后操作. 若还是无效果则尝试于12小时或24小时后再重试,或重置你的网络(如重新拨号或更换网络) `,
'130107': `参数{0}中指定的数组输出类型{1}不存在,请前往配置进行设置`,
'130120': `同步时发生错误,但同步将会继续。错误项目是 {}。`,
+ '130121': `总数只有{0}, 选择的开始比总数还要大,将不会同步。`,
'140201': `[OB-Douban]: 开始搜索'{0}'...`,
'140202': `[OB-Douban]: 搜索条数{0}条`,
diff --git a/src/org/wanxp/main.ts b/src/org/wanxp/main.ts
index 078b53e..4dc6ffb 100644
--- a/src/org/wanxp/main.ts
+++ b/src/org/wanxp/main.ts
@@ -57,7 +57,12 @@ export default class DoubanPlugin extends Plugin {
}
if (context.syncActive && extract.guessType && extract.guessType != extract.type) {
extract.handledStatus = SubjectHandledStatus.syncTypeDiffAbort;
- console.log(i18nHelper.getMessage('140102', extract.type, extract.title, extract.guessType));
+ if (Action.Sync == context.action) {
+ this.showStatus(i18nHelper.getMessage('140207', syncStatus.getHasHandle(), syncStatus.getTotal(), extract.title));
+ syncStatus.failByDiffType(extract.id, extract.title);
+ }else {
+ console.log(i18nHelper.getMessage('140102', extract.type, extract.title, extract.guessType));
+ }
return;
}
if (Action.Sync == context.action) {
diff --git a/styles.css b/styles.css
index d0c620b..6974aa2 100644
--- a/styles.css
+++ b/styles.css
@@ -1,3 +1,15 @@
+/* 获取主题颜色并定义新的颜色 */
+:root {
+ --obsidian-primary-color: var(--text-normal);
+ --obsidian-secondary-color: var(--background-primary);
+
+ /* 定义新的颜色,稍微调整亮度或饱和度 */
+ --plugin-primary-color: hsl(var(--obsidian-primary-color-h), var(--obsidian-primary-color-s), calc(var(--obsidian-primary-color-l) + 10%));
+ --plugin-secondary-color: hsl(var(--obsidian-secondary-color-h), var(--obsidian-secondary-color-s), calc(var(--obsidian-secondary-color-l) - 10%));
+}
+
+
+
.obsidian_douban_settings_area {
margin-left: 5px;
margin-right: 5px;
@@ -140,17 +152,17 @@
}
.obsidian_douban_settings_tab_header.active {
- background-color: #282828;
+ background-color: var(--plugin-primary-color);
font-weight: bold;
- border: 1px solid #323232;
+ border: 1px solid var(--plugin-secondary-color);
border-radius: 8px 8px 0 0; /* Rounded corners for the top */
}
.obsidian_douban_settings_tab_content.active {
- background-color: #282828;
+ background-color: var(--plugin-primary-color);
display: block;
padding: 10px;
- border: 1px solid #323232;
+ border: 1px solid var(--plugin-secondary-color);
border-radius: 0 8px 8px 8px; /* Rounded corners for the bottom */
}