mirror of
https://github.com/Wanxp/obsidian-douban.git
synced 2026-04-04 00:28:43 +08:00
parent
ea700e481e
commit
9fe0d1bfc9
@ -223,7 +223,7 @@ export const SyncTypeUrlDomain: Map<SyncType, string> = 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'),
|
||||
|
||||
|
||||
@ -51,6 +51,7 @@ export const DEFAULT_SETTINGS: DoubanPluginSetting = {
|
||||
cacheHighQuantityImage: true,
|
||||
attachmentPath: 'assets',
|
||||
syncHandledDataArray: [],
|
||||
// syncLastUpdateTime: new Map<string, string>(),
|
||||
scoreSetting: {
|
||||
starFull: '⭐',
|
||||
starEmpty: '☆',
|
||||
|
||||
@ -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<DoubanSubjectState, string> } = {
|
||||
[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<string, SupportType> = new Map<string, SupportType> (
|
||||
[['我看过这部电视剧', SupportType.TELEPLAY],
|
||||
['我最近看过这部电视剧', SupportType.TELEPLAY],
|
||||
|
||||
@ -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 = `<p>
|
||||
<label for="file">${i18nHelper.getMessage('110033')}</label>
|
||||
<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>
|
||||
<p>
|
||||
<label for="file">${i18nHelper.getMessage('110092')}</label>
|
||||
<span>${i18nHelper.getMessage('110090', syncStatus.getTypeName(), syncStatus.getScopeName(), syncStatus.getAllTotal(), syncStatus.getTotal())}</span>
|
||||
</p>
|
||||
<p>
|
||||
<label for="file">${i18nHelper.getMessage('110091')}</label>
|
||||
<span>${syncStatus.getMessage()}</span>
|
||||
</p>
|
||||
`
|
||||
backgroundButton.setDisabled(true);
|
||||
stopButton.setButtonText(i18nHelper.getMessage('110036'))
|
||||
return;
|
||||
@ -116,7 +126,16 @@ export class DoubanSyncModal extends Modal {
|
||||
<label for="file">${i18nHelper.getMessage('110033')}</label>
|
||||
<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>
|
||||
<p>
|
||||
<label for="file">${i18nHelper.getMessage('110092')}</label>
|
||||
<span>${i18nHelper.getMessage('110090', syncStatus.getTypeName(), syncStatus.getScopeName(), syncStatus.getAllTotal(), syncStatus.getTotal())}</span>
|
||||
</p>
|
||||
<p>
|
||||
<label for="file">${i18nHelper.getMessage('110091')}</label>
|
||||
<span>${syncStatus.getMessage()}</span>
|
||||
</p>
|
||||
`}
|
||||
|
||||
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'))
|
||||
|
||||
}
|
||||
@ -26,5 +26,6 @@ export default interface HandleContext {
|
||||
syncActive?:boolean;
|
||||
|
||||
searchPage?:SearchPageInfo;
|
||||
syncOffset?:number;
|
||||
|
||||
}
|
||||
|
||||
@ -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<any> {
|
||||
|
||||
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, []);
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,6 +56,10 @@ export class SearchPageInfo {
|
||||
return this._total;
|
||||
}
|
||||
|
||||
public set total(total: number) {
|
||||
this._total = total;
|
||||
}
|
||||
|
||||
get pageSize(): number {
|
||||
return this._pageSize;
|
||||
}
|
||||
|
||||
29
src/org/wanxp/douban/data/model/SearchPageTypeOf.ts
Normal file
29
src/org/wanxp/douban/data/model/SearchPageTypeOf.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { SearchPageInfo } from "./SearchPageInfo";
|
||||
import { SupportType } from "../../../constant/Constsant";
|
||||
|
||||
export class SearchPageTypeOf<T> 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<any> {
|
||||
return new SearchPageTypeOf(0, 0, 0, type, []);
|
||||
}
|
||||
|
||||
static emptyWithNoType() {
|
||||
return new SearchPageTypeOf(0, 0, 0, null, []);
|
||||
}
|
||||
}
|
||||
@ -2,4 +2,5 @@ export interface SubjectListItem {
|
||||
id:string;
|
||||
url:string;
|
||||
title:string;
|
||||
updateDate: Date | null;
|
||||
}
|
||||
|
||||
@ -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) => {
|
||||
|
||||
@ -36,6 +36,7 @@ export interface DoubanPluginSetting {
|
||||
pictureBedType: string;
|
||||
pictureBedSetting: PictureBedSetting;
|
||||
syncHandledDataArray: SyncHandledData[],
|
||||
// syncLastUpdateTime: Map<string, string>,
|
||||
arraySettings: ArraySetting[],
|
||||
scoreSetting: ScoreSetting,
|
||||
scoreSetting: ScoreSetting,
|
||||
}
|
||||
|
||||
@ -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<TAbstractFile> {
|
||||
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<TAbstractFile> {
|
||||
this.inputEl.value += "/";
|
||||
this.inputEl.trigger("input");
|
||||
}else {
|
||||
//@ts-ignore
|
||||
this.manager.updateSetting(this.settingKey, file.path);
|
||||
this.close();
|
||||
}
|
||||
|
||||
|
||||
@ -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<T extends DoubanSubject> 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<T extends DoubanSubject>
|
||||
implements DoubanSyncHandler
|
||||
{
|
||||
private plugin: DoubanPlugin;
|
||||
private doubanSubjectLoadHandler:DoubanSubjectLoadHandler<T>;
|
||||
private doubanListHandlers:DoubanListHandler[];
|
||||
private doubanSubjectLoadHandler: DoubanSubjectLoadHandler<T>;
|
||||
private doubanListHandlers: DoubanListHandler[];
|
||||
|
||||
constructor(plugin: DoubanPlugin,
|
||||
doubanSubjectLoadHandler:DoubanSubjectLoadHandler<T>,
|
||||
doubanListHandlers:DoubanListHandler[]) {
|
||||
constructor(
|
||||
plugin: DoubanPlugin,
|
||||
doubanSubjectLoadHandler: DoubanSubjectLoadHandler<T>,
|
||||
doubanListHandlers: DoubanListHandler[],
|
||||
) {
|
||||
this.plugin = plugin;
|
||||
this.doubanSubjectLoadHandler = doubanSubjectLoadHandler;
|
||||
this.doubanListHandlers = doubanListHandlers;
|
||||
@ -31,61 +73,387 @@ export abstract class DoubanAbstractSyncHandler<T extends DoubanSubject> implem
|
||||
|
||||
abstract getSyncType(): SyncType;
|
||||
|
||||
async sync(syncConfig: SyncConfig, context: HandleContext): Promise<void>{
|
||||
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<void> {
|
||||
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<SubjectListItem[]> {
|
||||
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<number, SearchPageTypeOf<SubjectListItem>>();
|
||||
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<SubjectListItem>(subjectListItems.length,
|
||||
1,
|
||||
subjectListItems.length,
|
||||
null,subjectListItems);
|
||||
await this.handleItems(searchPage, subjectListItems, context);
|
||||
|
||||
private async getItems(syncConfig:SyncConfig, context:HandleContext):Promise<SubjectListItem[]> {
|
||||
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<SubjectListItem[]> {
|
||||
private async getItems(
|
||||
syncConfig: SyncConfig,
|
||||
context: HandleContext,
|
||||
): Promise<SearchPageTypeOf<SubjectListItem>> {
|
||||
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<SubjectListItem[]> {
|
||||
if (!context.plugin.statusHolder.syncing()) {
|
||||
return [];
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
private async handleItems(items:SubjectListItem[], context:HandleContext):Promise<void> {
|
||||
private async handleItems(
|
||||
searchPage: SearchPage,
|
||||
items: SubjectListItem[],
|
||||
context: HandleContext,
|
||||
): Promise<void> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<SearchPage> {
|
||||
let all: SubjectListItem[] = [];
|
||||
let pages: SearchPage = SearchPage.emptyWithNoType();
|
||||
|
||||
async getAllPageList(context: HandleContext):Promise<SubjectListItem[]>{
|
||||
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<SubjectListItem[]> {
|
||||
return DoubanHttpUtil.httpRequestGet(url, context.plugin.settingsManager.getHeaders(), context.plugin.settingsManager)
|
||||
async getPageList(
|
||||
url: string,
|
||||
context: HandleContext,
|
||||
): Promise<SearchPageTypeOf<SubjectListItem>> {
|
||||
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<SubjectListItem> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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<SubjectListItem[]>;
|
||||
getPageData(context: HandleContext):Promise<SearchPage>;
|
||||
|
||||
support(config:SyncConfig):boolean;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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`,
|
||||
|
||||
@ -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}条`,
|
||||
|
||||
@ -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) {
|
||||
|
||||
20
styles.css
20
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 */
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user