mirror of
https://github.com/Wanxp/obsidian-douban.git
synced 2026-04-07 19:08:43 +08:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4d3dc61d33 | |||
| 8f405600a5 | |||
| 93159d6200 | |||
| ef0ca4d0b9 |
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"id": "obsidian-douban-plugin",
|
"id": "obsidian-douban-plugin",
|
||||||
"name": "Douban",
|
"name": "Douban",
|
||||||
"version": "2.1.0",
|
"version": "2.2.0",
|
||||||
"minAppVersion": "0.12.0",
|
"minAppVersion": "0.12.0",
|
||||||
"description": "This is a plugin that can import movies/books/musics/notes/games info data from Douban for Obsidian .",
|
"description": "This is a plugin that can import movies/books/musics/notes/games info data from Douban for Obsidian .",
|
||||||
"author": "Wanxp",
|
"author": "Wanxp",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "obsidian-douban-plugin",
|
"name": "obsidian-douban-plugin",
|
||||||
"version": "2.1.0",
|
"version": "2.2.0",
|
||||||
"description": "This is a plugin for Obsidian (https://obsidian.md) that can import data from Douban (https://www.douban.com/).",
|
"description": "This is a plugin for Obsidian (https://obsidian.md) that can import data from Douban (https://www.douban.com/).",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -223,7 +223,7 @@ export const SyncTypeUrlDomain: Map<SyncType, string> = new Map([
|
|||||||
* 同步模式选项
|
* 同步模式选项
|
||||||
*/
|
*/
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
export const SyncTypeRecords: { [key in SyncType]: string } = {
|
export const SyncTypeRecords: { [key in SyncType | string]: string } = {
|
||||||
[SyncType.movie]: i18nHelper.getMessage('504103'),
|
[SyncType.movie]: i18nHelper.getMessage('504103'),
|
||||||
[SyncType.teleplay]: i18nHelper.getMessage('504107'),
|
[SyncType.teleplay]: i18nHelper.getMessage('504107'),
|
||||||
[SyncType.book]: i18nHelper.getMessage('504102'),
|
[SyncType.book]: i18nHelper.getMessage('504102'),
|
||||||
@ -257,6 +257,7 @@ export enum SyncItemStatus {
|
|||||||
replace = 'replace',
|
replace = 'replace',
|
||||||
create = 'create',
|
create = 'create',
|
||||||
fail = 'fail',
|
fail = 'fail',
|
||||||
|
failByDiffType = 'failByDiffType',
|
||||||
unHandle = 'unHandle',
|
unHandle = 'unHandle',
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -452,3 +453,44 @@ export const PictureBedSetting_PicGo ={
|
|||||||
export const PictureBedTypeRecords: { [key in PictureBedType]: string } = {
|
export const PictureBedTypeRecords: { [key in PictureBedType]: string } = {
|
||||||
[PictureBedType.PicGo]: PictureBedType.PicGo
|
[PictureBedType.PicGo]: PictureBedType.PicGo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export enum SyncConditionType {
|
||||||
|
/**
|
||||||
|
* 最近新变动
|
||||||
|
*/
|
||||||
|
ALL = "all",
|
||||||
|
// /**
|
||||||
|
// * 最近新变动
|
||||||
|
// */
|
||||||
|
// LAST_UPDATE = "lastUpdate",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最近10条
|
||||||
|
*/
|
||||||
|
LAST_THIRTY = "lastThirty",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义时间
|
||||||
|
*/
|
||||||
|
CUSTOM_TIME = "customTime",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义条数
|
||||||
|
*/
|
||||||
|
CUSTOM_ITEM = "customItem",
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 名称模式选项
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
export const SyncConditionTypeRecords: { [key in SyncConditionType|string]: string } = {
|
||||||
|
[SyncConditionType.ALL]: i18nHelper.getMessage('110071'),
|
||||||
|
// [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,
|
cacheHighQuantityImage: true,
|
||||||
attachmentPath: 'assets',
|
attachmentPath: 'assets',
|
||||||
syncHandledDataArray: [],
|
syncHandledDataArray: [],
|
||||||
|
// syncLastUpdateTime: new Map<string, string>(),
|
||||||
scoreSetting: {
|
scoreSetting: {
|
||||||
starFull: '⭐',
|
starFull: '⭐',
|
||||||
starEmpty: '☆',
|
starEmpty: '☆',
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import {i18nHelper} from "../lang/helper";
|
import {i18nHelper} from "../lang/helper";
|
||||||
import {SupportType} from "./Constsant";
|
import {SupportType, SyncType} from "./Constsant";
|
||||||
|
|
||||||
export enum DoubanSubjectState {
|
export enum DoubanSubjectState {
|
||||||
not = 'not',
|
not = 'not',
|
||||||
@ -123,6 +123,19 @@ export const DoubanSubjectStateRecords_MUSIC_SYNC: { [key in DoubanSubjectState]
|
|||||||
[DoubanSubjectState.collect]: i18nHelper.getMessage('500404'),
|
[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> (
|
export const DoubanSubjectStateRecords_KEY_WORD_TYPE: Map<string, SupportType> = new Map<string, SupportType> (
|
||||||
[['我看过这部电视剧', SupportType.TELEPLAY],
|
[['我看过这部电视剧', SupportType.TELEPLAY],
|
||||||
['我最近看过这部电视剧', SupportType.TELEPLAY],
|
['我最近看过这部电视剧', SupportType.TELEPLAY],
|
||||||
|
|||||||
@ -1,12 +1,18 @@
|
|||||||
import {ButtonComponent, Modal} from "obsidian";
|
import {App, ButtonComponent, Modal} from "obsidian";
|
||||||
import {i18nHelper} from "../../lang/helper";
|
import {i18nHelper} from "../../lang/helper";
|
||||||
|
import {create} from "istanbul-reports";
|
||||||
|
import DoubanPlugin from "../../main";
|
||||||
|
import {logger} from "bs-logger";
|
||||||
|
import {log} from "../../utils/Logutil";
|
||||||
|
|
||||||
export class ConfirmDialogModal extends Modal {
|
export class ConfirmDialogModal extends Modal {
|
||||||
private promise:Promise<any>;
|
private promise:Promise<any>;
|
||||||
private message:string;
|
private message:string;
|
||||||
|
private doubanPlugin: DoubanPlugin;
|
||||||
|
|
||||||
constructor(app: any, message:string, promise: Promise<any>) {
|
constructor(doubanPlugin: DoubanPlugin, message:string, promise: Promise<any>) {
|
||||||
super(app);
|
super(doubanPlugin.app);
|
||||||
|
this.doubanPlugin = doubanPlugin;
|
||||||
this.message = message;
|
this.message = message;
|
||||||
this.promise = promise;
|
this.promise = promise;
|
||||||
}
|
}
|
||||||
@ -23,7 +29,12 @@ export class ConfirmDialogModal extends Modal {
|
|||||||
.setButtonText(i18nHelper.getMessage('110152'))
|
.setButtonText(i18nHelper.getMessage('110152'))
|
||||||
.setCta()
|
.setCta()
|
||||||
.onClick(async () => {
|
.onClick(async () => {
|
||||||
await this.promise;
|
//临时特殊处理导入文件
|
||||||
|
if (this.message == i18nHelper.getMessage('125046')) {
|
||||||
|
createFileSelectModal(this.doubanPlugin);
|
||||||
|
}else {
|
||||||
|
await this.promise;
|
||||||
|
}
|
||||||
this.close();
|
this.close();
|
||||||
}).setClass( "obsidian_douban_search_button");
|
}).setClass( "obsidian_douban_search_button");
|
||||||
new ButtonComponent(controls)
|
new ButtonComponent(controls)
|
||||||
@ -33,3 +44,25 @@ export class ConfirmDialogModal extends Modal {
|
|||||||
}).setClass( "obsidian_douban_cancel_button");
|
}).setClass( "obsidian_douban_cancel_button");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function createFileSelectModal(doubanPlugin: DoubanPlugin) {
|
||||||
|
const input = document.createElement('input');
|
||||||
|
input.type = 'file';
|
||||||
|
input.accept = '.json';
|
||||||
|
input.multiple = false;
|
||||||
|
input.onchange = async () => {
|
||||||
|
const file = input.files[0];
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = async () => {
|
||||||
|
const settings:object = JSON.parse(reader.result as string);
|
||||||
|
try {
|
||||||
|
await doubanPlugin.settingsManager.loadAndSaveSettings(settings);
|
||||||
|
}catch (e) {
|
||||||
|
log.error(i18nHelper.getMessage('125043'), e);
|
||||||
|
}
|
||||||
|
log.notice(i18nHelper.getMessage('125044'))
|
||||||
|
};
|
||||||
|
reader.readAsText(file);
|
||||||
|
};
|
||||||
|
input.click();}
|
||||||
18
src/org/wanxp/douban/component/DatePickComponent.ts
Normal file
18
src/org/wanxp/douban/component/DatePickComponent.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* 日期选择组件
|
||||||
|
* 继承自 TextComponent
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {TextComponent} from 'obsidian';
|
||||||
|
|
||||||
|
export class DatePickComponent extends TextComponent {
|
||||||
|
constructor(container: HTMLElement, date: Date = new Date()) {
|
||||||
|
super(container);
|
||||||
|
this.inputEl.type = 'date';
|
||||||
|
this.inputEl.value = date.toISOString().substring(0, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue(): string {
|
||||||
|
return this.inputEl.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,7 +3,7 @@ import { log } from 'src/org/wanxp/utils/Logutil';
|
|||||||
import {i18nHelper} from "../../lang/helper";
|
import {i18nHelper} from "../../lang/helper";
|
||||||
import {DoubanSettingTab} from "../setting/DoubanSettingTab";
|
import {DoubanSettingTab} from "../setting/DoubanSettingTab";
|
||||||
import SettingsManager from "../setting/SettingsManager";
|
import SettingsManager from "../setting/SettingsManager";
|
||||||
import {constructDoubanTokenSettingsUI} from "../setting/BasicSettingsHelper";
|
import {constructDoubanTokenSettingsUI} from "../setting/LoginSettingsHelper";
|
||||||
|
|
||||||
// Credits go to zhaohongxuan's Weread Plugin : https://github.com/zhaohongxuan/obsidian-weread-plugin
|
// Credits go to zhaohongxuan's Weread Plugin : https://github.com/zhaohongxuan/obsidian-weread-plugin
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { log } from 'src/org/wanxp/utils/Logutil';
|
|||||||
import {i18nHelper} from "../../lang/helper";
|
import {i18nHelper} from "../../lang/helper";
|
||||||
import {DoubanSettingTab} from "../setting/DoubanSettingTab";
|
import {DoubanSettingTab} from "../setting/DoubanSettingTab";
|
||||||
import SettingsManager from "../setting/SettingsManager";
|
import SettingsManager from "../setting/SettingsManager";
|
||||||
import {constructDoubanTokenSettingsUI} from "../setting/BasicSettingsHelper";
|
import {constructDoubanTokenSettingsUI} from "../setting/LoginSettingsHelper";
|
||||||
import StringUtil from "../../utils/StringUtil";
|
import StringUtil from "../../utils/StringUtil";
|
||||||
import {Integer} from "schema-dts";
|
import {Integer} from "schema-dts";
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import {DoubanSettingTab} from "../setting/DoubanSettingTab";
|
import {DoubanSettingTab} from "../setting/DoubanSettingTab";
|
||||||
import {i18nHelper} from "../../lang/helper";
|
import {i18nHelper} from "../../lang/helper";
|
||||||
import SettingsManager from "../setting/SettingsManager";
|
import SettingsManager from "../setting/SettingsManager";
|
||||||
import {constructDoubanTokenSettingsUI, constructLoginSettingsUI} from "../setting/BasicSettingsHelper";
|
import {constructDoubanTokenSettingsUI, constructLoginSettingsUI} from "../setting/LoginSettingsHelper";
|
||||||
import {log} from "../../utils/Logutil";
|
import {log} from "../../utils/Logutil";
|
||||||
|
|
||||||
// Credits go to zhaohongxuan's Weread Plugin : https://github.com/zhaohongxuan/obsidian-weread-plugin
|
// Credits go to zhaohongxuan's Weread Plugin : https://github.com/zhaohongxuan/obsidian-weread-plugin
|
||||||
|
|||||||
@ -1,15 +1,21 @@
|
|||||||
import {
|
import {
|
||||||
App,
|
App,
|
||||||
ButtonComponent,
|
ButtonComponent, DropdownComponent,
|
||||||
Modal, SearchComponent, Setting,
|
Modal, SearchComponent, Setting, TextComponent, ValueComponent,
|
||||||
} from "obsidian";
|
} from "obsidian";
|
||||||
|
|
||||||
import DoubanPlugin from "../../main";
|
import DoubanPlugin from "../../main";
|
||||||
import {i18nHelper} from "src/org/wanxp/lang/helper";
|
import {i18nHelper} from "src/org/wanxp/lang/helper";
|
||||||
import HandleContext from "../data/model/HandleContext";
|
import HandleContext from "../data/model/HandleContext";
|
||||||
import {SyncType, SyncTypeRecords} from "../../constant/Constsant";
|
|
||||||
import {
|
import {
|
||||||
ALL,
|
DEFAULT_SETTINGS_ARRAY_INPUT_SIZE,
|
||||||
|
SupportType, SyncConditionType,
|
||||||
|
SyncConditionTypeRecords,
|
||||||
|
SyncType,
|
||||||
|
SyncTypeRecords
|
||||||
|
} from "../../constant/Constsant";
|
||||||
|
import {
|
||||||
|
ALL, DoubanSubjectState, DoubanSubjectStateRecords,
|
||||||
DoubanSubjectStateRecords_BOOK_SYNC,
|
DoubanSubjectStateRecords_BOOK_SYNC,
|
||||||
DoubanSubjectStateRecords_BROADCAST_SYNC,
|
DoubanSubjectStateRecords_BROADCAST_SYNC,
|
||||||
DoubanSubjectStateRecords_MOVIE_SYNC,
|
DoubanSubjectStateRecords_MOVIE_SYNC,
|
||||||
@ -25,6 +31,12 @@ import {createFileSelectionSetting} from "../setting/TemplateSettingHelper";
|
|||||||
import {FileSuggest} from "../setting/model/FileSuggest";
|
import {FileSuggest} from "../setting/model/FileSuggest";
|
||||||
import {getDefaultTemplateContent} from "../../constant/DefaultTemplateContent";
|
import {getDefaultTemplateContent} from "../../constant/DefaultTemplateContent";
|
||||||
import TimeUtil from "../../utils/TimeUtil";
|
import TimeUtil from "../../utils/TimeUtil";
|
||||||
|
import SettingsManager from "../setting/SettingsManager";
|
||||||
|
import {ArraySetting, DEFAULT_SETTINGS_ARRAY_NAME} from "../setting/model/ArraySetting";
|
||||||
|
import {arraySettingDisplay} from "../setting/ArrayDisplayTypeSettingsHelper";
|
||||||
|
import {DatePickComponent} from "./DatePickComponent";
|
||||||
|
import {NumberComponent} from "./NumberComponent";
|
||||||
|
import {log} from "../../utils/Logutil";
|
||||||
|
|
||||||
export class DoubanSyncModal extends Modal {
|
export class DoubanSyncModal extends Modal {
|
||||||
plugin: DoubanPlugin;
|
plugin: DoubanPlugin;
|
||||||
@ -96,7 +108,16 @@ export class DoubanSyncModal extends Modal {
|
|||||||
progress.innerHTML = `<p>
|
progress.innerHTML = `<p>
|
||||||
<label for="file">${i18nHelper.getMessage('110033')}</label>
|
<label for="file">${i18nHelper.getMessage('110033')}</label>
|
||||||
<progress class="obsidian_douban_sync_slider" max="${syncStatus.getTotal() == 0 ? 1:syncStatus.getTotal()}" value="${syncStatus.getHasHandle()}"> </progress> <span> ${syncStatus.getHasHandle()}/${syncStatus.getTotal()}:${i18nHelper.getMessage('110036')} </span>
|
<progress class="obsidian_douban_sync_slider" max="${syncStatus.getTotal() == 0 ? 1:syncStatus.getTotal()}" value="${syncStatus.getHasHandle()}"> </progress> <span> ${syncStatus.getHasHandle()}/${syncStatus.getTotal()}:${i18nHelper.getMessage('110036')} </span>
|
||||||
</p>`
|
</p>
|
||||||
|
<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);
|
backgroundButton.setDisabled(true);
|
||||||
stopButton.setButtonText(i18nHelper.getMessage('110036'))
|
stopButton.setButtonText(i18nHelper.getMessage('110036'))
|
||||||
return;
|
return;
|
||||||
@ -105,7 +126,16 @@ export class DoubanSyncModal extends Modal {
|
|||||||
<label for="file">${i18nHelper.getMessage('110033')}</label>
|
<label for="file">${i18nHelper.getMessage('110033')}</label>
|
||||||
<progress class="obsidian_douban_sync_slider" max="${syncStatus.getTotal() == 0 ? 1:syncStatus.getTotal()}" value="${syncStatus.getHasHandle()}"> </progress> <span> ${syncStatus.getTotal() == 0 ? i18nHelper.getMessage('110043') : syncStatus.getHasHandle() + '/' + syncStatus.getTotal()}
|
<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>
|
${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) {
|
private showSyncConfig(contentEl: HTMLElement) {
|
||||||
if (this.timer != null) {
|
if (this.timer != null) {
|
||||||
@ -122,6 +152,11 @@ ${syncStatus.getHandle() == 0? '...' : i18nHelper.getMessage('110042') + ':' + T
|
|||||||
attachmentPath: (settings.attachmentPath == '' || settings.attachmentPath == null) ? DEFAULT_SETTINGS.attachmentPath : settings.attachmentPath,
|
attachmentPath: (settings.attachmentPath == '' || settings.attachmentPath == null) ? DEFAULT_SETTINGS.attachmentPath : settings.attachmentPath,
|
||||||
templateFile: (settings.movieTemplateFile == '' || settings.movieTemplateFile == null) ? DEFAULT_SETTINGS.movieTemplateFile : settings.movieTemplateFile,
|
templateFile: (settings.movieTemplateFile == '' || settings.movieTemplateFile == null) ? DEFAULT_SETTINGS.movieTemplateFile : settings.movieTemplateFile,
|
||||||
incrementalUpdate: true,
|
incrementalUpdate: true,
|
||||||
|
syncConditionType: SyncConditionType.ALL,
|
||||||
|
syncConditionDateFromValue: TimeUtil.getLastMonth(),
|
||||||
|
syncConditionDateToValue: new Date(),
|
||||||
|
syncConditionCountFromValue: 1,
|
||||||
|
syncConditionCountToValue: 30
|
||||||
};
|
};
|
||||||
this.showConfigPan(contentEl.createDiv('config'), syncConfig, false);
|
this.showConfigPan(contentEl.createDiv('config'), syncConfig, false);
|
||||||
const controls = contentEl.createDiv("controls");
|
const controls = contentEl.createDiv("controls");
|
||||||
@ -133,6 +168,9 @@ ${syncStatus.getHandle() == 0? '...' : i18nHelper.getMessage('110042') + ':' + T
|
|||||||
const syncButton = new ButtonComponent(controls)
|
const syncButton = new ButtonComponent(controls)
|
||||||
.setButtonText(i18nHelper.getMessage('110007'))
|
.setButtonText(i18nHelper.getMessage('110007'))
|
||||||
.onClick(async () => {
|
.onClick(async () => {
|
||||||
|
if (!this.plugin.userComponent.isLogin()) {
|
||||||
|
await this.plugin.userComponent.login();
|
||||||
|
}
|
||||||
if(!await this.plugin.checkLogin(this.context)) {
|
if(!await this.plugin.checkLogin(this.context)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -160,10 +198,10 @@ ${syncStatus.getHandle() == 0? '...' : i18nHelper.getMessage('110042') + ':' + T
|
|||||||
private showConfigPan(contentEl: HTMLElement, config:SyncConfig, disable:boolean) {
|
private showConfigPan(contentEl: HTMLElement, config:SyncConfig, disable:boolean) {
|
||||||
new Setting(contentEl);
|
new Setting(contentEl);
|
||||||
this.showTypeDropdown(contentEl, config, disable);
|
this.showTypeDropdown(contentEl, config, disable);
|
||||||
|
this.showCondition(contentEl, config, disable);
|
||||||
this.showOutputFolderSelections(contentEl, config, disable);
|
// this.showOutputFolderSelections(contentEl, config, disable);
|
||||||
this.showOutiFleName(contentEl, config, disable);
|
// this.showOutiFleName(contentEl, config, disable);
|
||||||
this.showAttachmentsFileConfig(contentEl, config, disable);
|
// this.showAttachmentsFileConfig(contentEl, config, disable);
|
||||||
this.showUpdateAllConfig(contentEl, config, disable);
|
this.showUpdateAllConfig(contentEl, config, disable);
|
||||||
this.showForceUpdateConfig(contentEl, config, disable);
|
this.showForceUpdateConfig(contentEl, config, disable);
|
||||||
}
|
}
|
||||||
@ -217,7 +255,7 @@ ${syncStatus.getHandle() == 0? '...' : i18nHelper.getMessage('110042') + ':' + T
|
|||||||
});
|
});
|
||||||
}).setDisabled(disable);
|
}).setDisabled(disable);
|
||||||
this.openScopeDropdown(scopeSelections, config, disable);
|
this.openScopeDropdown(scopeSelections, config, disable);
|
||||||
this.showTemplateFileSelectionSetting(templateFile, config, disable);
|
// this.showTemplateFileSelectionSetting(templateFile, config, disable);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getDefaultTemplatePath(value: string) {
|
private getDefaultTemplatePath(value: string) {
|
||||||
@ -412,4 +450,128 @@ ${syncStatus.getHandle() == 0? '...' : i18nHelper.getMessage('110042') + ':' + T
|
|||||||
.setDisabled(disable);
|
.setDisabled(disable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private showCondition(contentEl: HTMLElement, config: SyncConfig, disable: boolean) {
|
||||||
|
showConditionItem(contentEl.createDiv("sync-douban-condition"), this.plugin.settingsManager, config, disable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showConditionItem(containerEl: HTMLElement, manager: SettingsManager, config: SyncConfig, disable: boolean) {
|
||||||
|
containerEl.empty();
|
||||||
|
const condition = new Setting(containerEl).setName(i18nHelper.getMessage('110070'))
|
||||||
|
|
||||||
|
const conditionDesc = condition.descEl.createDiv('sync-douban-condition-desc');
|
||||||
|
new DropdownComponent(conditionDesc).addOptions(SyncConditionTypeRecords)
|
||||||
|
.setValue(config.syncConditionType)
|
||||||
|
.onChange((value) => {
|
||||||
|
config.syncConditionType = value;
|
||||||
|
showConditionItem(containerEl, manager, config, disable);
|
||||||
|
}).setDisabled(disable);
|
||||||
|
showConditionItemInput(conditionDesc, config, disable);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showConditionItemInput(containerEl: HTMLElement, config: SyncConfig, disable: boolean) {
|
||||||
|
if (config.syncConditionType == SyncConditionType.CUSTOM_ITEM) {
|
||||||
|
showCustomInputCount(containerEl, config, disable);
|
||||||
|
}else if (config.syncConditionType == SyncConditionType.CUSTOM_TIME) {
|
||||||
|
showCustomInputTime(containerEl, config, disable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showCustomInputCount(containerEl: HTMLElement, config: SyncConfig, disable: boolean) {
|
||||||
|
containerEl.createEl('span', { text: ' ' })
|
||||||
|
containerEl.createEl('span', { text: i18nHelper.getMessage('110077') })
|
||||||
|
containerEl.createEl('span', { text: i18nHelper.getMessage('110078') })
|
||||||
|
const fromField = new TextComponent(containerEl);
|
||||||
|
fromField.setPlaceholder(i18nHelper.getMessage('110080'))
|
||||||
|
.setValue(config.syncConditionCountFromValue + '')
|
||||||
|
.onChange(async (value) => {
|
||||||
|
if (!value) {
|
||||||
|
config.syncConditionCountFromValue = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
config.syncConditionCountFromValue = parseInt(value);
|
||||||
|
}catch (e) {
|
||||||
|
log.notice(i18nHelper.getMessage('112080'))
|
||||||
|
}
|
||||||
|
}).setDisabled(disable);
|
||||||
|
let fromEl = fromField.inputEl;
|
||||||
|
fromEl.addClass('obsidian_douban_settings_input')
|
||||||
|
fromEl.style.width ='20%';
|
||||||
|
containerEl.appendChild(fromEl);
|
||||||
|
const lang = window.localStorage.getItem('language');
|
||||||
|
if (lang == 'zh') {
|
||||||
|
containerEl.createEl('span', {text: i18nHelper.getMessage('110073')})
|
||||||
|
}
|
||||||
|
|
||||||
|
containerEl.createEl('span', { text: i18nHelper.getMessage('110079') })
|
||||||
|
containerEl.createEl('span', { text: i18nHelper.getMessage('110078') })
|
||||||
|
const toField = new TextComponent(containerEl);
|
||||||
|
toField.setPlaceholder(i18nHelper.getMessage('110080'))
|
||||||
|
.setValue(config.syncConditionCountToValue + '')
|
||||||
|
.onChange(async (value) => {
|
||||||
|
if (!value) {
|
||||||
|
config.syncConditionCountToValue = 30;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
config.syncConditionCountToValue = parseInt(value);
|
||||||
|
}catch (e) {
|
||||||
|
log.notice(i18nHelper.getMessage('112080'))
|
||||||
|
}
|
||||||
|
}).setDisabled(disable);
|
||||||
|
let toEl = toField.inputEl;
|
||||||
|
toEl.addClass('obsidian_douban_settings_input')
|
||||||
|
toEl.style.width ='20%';
|
||||||
|
containerEl.appendChild(toEl);
|
||||||
|
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) {
|
||||||
|
containerEl.createEl('span', { text: i18nHelper.getMessage('110077') })
|
||||||
|
const fromDateField = new TextComponent(containerEl);
|
||||||
|
const fromDateEl = fromDateField.inputEl;
|
||||||
|
fromDateEl.type = 'date';
|
||||||
|
fromDateEl.value = config.syncConditionDateFromValue ? config.syncConditionDateFromValue.toISOString().substring(0, 10) : TimeUtil.getLastMonth().toISOString().substring(0, 10);
|
||||||
|
fromDateField.setPlaceholder(i18nHelper.getMessage('110075'))
|
||||||
|
.setValue(config.syncConditionDateFromValue ? config.syncConditionDateFromValue.toISOString().substring(0, 10) : TimeUtil.getLastMonth().toISOString().substring(0, 10))
|
||||||
|
.onChange(async (value) => {
|
||||||
|
if (!value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
config.syncConditionDateFromValue = new Date(value);
|
||||||
|
}catch (e) {
|
||||||
|
log.notice(i18nHelper.getMessage('110082'))
|
||||||
|
}
|
||||||
|
}).setDisabled(disable);
|
||||||
|
fromDateEl.addClass('obsidian_douban_settings_input')
|
||||||
|
containerEl.appendChild(fromDateEl);
|
||||||
|
|
||||||
|
containerEl.createEl('span', { text: i18nHelper.getMessage('110079') })
|
||||||
|
const toDateField = new TextComponent(containerEl);
|
||||||
|
let toDateEl = toDateField.inputEl;
|
||||||
|
toDateEl.type = 'date';
|
||||||
|
toDateEl.value = config.syncConditionDateToValue ? config.syncConditionDateToValue.toISOString().substring(0, 10) : new Date().toISOString().substring(0, 10);
|
||||||
|
toDateField.setPlaceholder(i18nHelper.getMessage('110075'))
|
||||||
|
.setValue(config.syncConditionDateToValue ? config.syncConditionDateToValue.toISOString().substring(0, 10) : new Date().toISOString().substring(0, 10))
|
||||||
|
.onChange(async (value) => {
|
||||||
|
if (!value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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
src/org/wanxp/douban/component/NumberComponent.ts
Normal file
26
src/org/wanxp/douban/component/NumberComponent.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/**
|
||||||
|
* 日期选择组件
|
||||||
|
* 继承自 TextComponent
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {TextComponent} from 'obsidian';
|
||||||
|
|
||||||
|
export class NumberComponent extends TextComponent {
|
||||||
|
constructor(container: HTMLElement, value: number = 0) {
|
||||||
|
super(container);
|
||||||
|
this.inputEl.type = 'date';
|
||||||
|
this.inputEl.value = value.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue(): string {
|
||||||
|
return this.inputEl.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
//当输入框输入的内容不是数字时,则回退到之前的值
|
||||||
|
// onChanged() {
|
||||||
|
// if (isNaN(Number(this.inputEl.value))) {
|
||||||
|
// this.inputEl.value = this.inputEl.value.slice(0, -1);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
@ -26,5 +26,6 @@ export default interface HandleContext {
|
|||||||
syncActive?:boolean;
|
syncActive?:boolean;
|
||||||
|
|
||||||
searchPage?:SearchPageInfo;
|
searchPage?:SearchPageInfo;
|
||||||
|
syncOffset?:number;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,21 +1,14 @@
|
|||||||
import {SearchPageInfo} from "./SearchPageInfo";
|
import { SearchPageInfo } from "./SearchPageInfo";
|
||||||
import {SupportType} from "../../../constant/Constsant";
|
import { SupportType } from "../../../constant/Constsant";
|
||||||
|
import {SearchPageTypeOf} from "./SearchPageTypeOf";
|
||||||
|
|
||||||
export class SearchPage extends SearchPageInfo{
|
export class SearchPage extends SearchPageTypeOf<any> {
|
||||||
|
|
||||||
private _list:any[];
|
public static empty(type: SupportType): SearchPage {
|
||||||
|
|
||||||
|
|
||||||
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 {
|
|
||||||
return new SearchPage(0, 0, 0, type, []);
|
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;
|
return this._total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public set total(total: number) {
|
||||||
|
this._total = total;
|
||||||
|
}
|
||||||
|
|
||||||
get pageSize(): number {
|
get pageSize(): number {
|
||||||
return this._pageSize;
|
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;
|
id:string;
|
||||||
url:string;
|
url:string;
|
||||||
title:string;
|
title:string;
|
||||||
|
updateDate: Date | null;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,31 +8,74 @@ import User from "../user/User";
|
|||||||
import {createFolderSelectionSetting} from "./TemplateSettingHelper";
|
import {createFolderSelectionSetting} from "./TemplateSettingHelper";
|
||||||
import { log } from "../../utils/Logutil";
|
import { log } from "../../utils/Logutil";
|
||||||
import {ConfirmDialogModal} from "../component/ConfirmDialogModal";
|
import {ConfirmDialogModal} from "../component/ConfirmDialogModal";
|
||||||
|
import {DoubanSearchModal} from "../data/search/DoubanSearchModal";
|
||||||
|
import {DoubanPluginSetting} from "./model/DoubanPluginSetting";
|
||||||
|
import TimeUtil from "../../utils/TimeUtil";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export function constructAdvancedUI(containerEl: HTMLElement, manager: SettingsManager) {
|
export function constructAdvancedUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
containerEl.createEl('h3', { text: i18nHelper.getMessage('1250') });
|
// containerEl.createEl('h3', { text: i18nHelper.getMessage('1250') });
|
||||||
containerEl.createEl('p', { text: i18nHelper.getMessage('1252') });
|
containerEl.createEl('p', { text: i18nHelper.getMessage('1252') });
|
||||||
const settings:Setting = new Setting(containerEl);
|
|
||||||
const advancedSettings = containerEl.createDiv('advanced-settings');
|
|
||||||
settings.setDesc(i18nHelper.getMessage('1251')).addExtraButton((extraButton) => {
|
|
||||||
extraButton
|
|
||||||
.setIcon('reset')
|
|
||||||
.setTooltip(i18nHelper.getMessage('121905'))
|
|
||||||
.onClick(async () => {
|
|
||||||
resetAdvanced(manager);
|
|
||||||
await manager.plugin.saveSettings();
|
|
||||||
showAdvancedSettings(advancedSettings, manager)
|
|
||||||
});
|
|
||||||
})
|
|
||||||
showAdvancedSettings(advancedSettings, manager);
|
|
||||||
|
|
||||||
|
// const settings:Setting = new Setting(containerEl);
|
||||||
|
const advancedSettings = containerEl.createDiv('advanced-settings');
|
||||||
|
// settings.setDesc(i18nHelper.getMessage('1251')).addExtraButton((extraButton) => {
|
||||||
|
// extraButton
|
||||||
|
// .setIcon('reset')
|
||||||
|
// .setTooltip(i18nHelper.getMessage('121905'))
|
||||||
|
// .onClick(async () => {
|
||||||
|
// resetAdvanced(manager);
|
||||||
|
// await manager.plugin.saveSettings();
|
||||||
|
// showAdvancedSettings(advancedSettings, manager)
|
||||||
|
// });
|
||||||
|
// })
|
||||||
|
showAdvancedSettings(advancedSettings, manager);
|
||||||
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
function showAdvancedSettings(containerEl: HTMLElement, manager: SettingsManager) {
|
function showAdvancedSettings(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
containerEl.empty();
|
containerEl.empty();
|
||||||
const promise:Promise<any> = new Promise<any>((resolve, reject) => {resolve(null)});
|
const promise:Promise<any> = new Promise<any>((resolve, reject) => {resolve(null)});
|
||||||
|
|
||||||
|
|
||||||
|
//导出
|
||||||
|
new Setting(containerEl)
|
||||||
|
.setName(i18nHelper.getMessage('125034'))
|
||||||
|
.setDesc(i18nHelper.getMessage('125035'))
|
||||||
|
.addButton((buttonComponent) => {
|
||||||
|
buttonComponent
|
||||||
|
.setIcon('folder')
|
||||||
|
.setButtonText(i18nHelper.getMessage('125047'))
|
||||||
|
.onClick(async (value) => {
|
||||||
|
const settings = manager.getSettings()
|
||||||
|
const settingsString = JSON.stringify(settings, null, 2);
|
||||||
|
const blob = new Blob([settingsString], { type: 'application/json' });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = `obsidian_douban_plugin_settings_${TimeUtil.formatDate(new Date(), 'yyyy-MM-dd_HH-mm-ss')}.json`;
|
||||||
|
a.click();
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
//导入
|
||||||
|
new Setting(containerEl)
|
||||||
|
.setName(i18nHelper.getMessage('125036'))
|
||||||
|
.setDesc(i18nHelper.getMessage('125037'))
|
||||||
|
.addButton((buttonComponent) => {
|
||||||
|
buttonComponent
|
||||||
|
.setIcon('document')
|
||||||
|
.setButtonText(i18nHelper.getMessage('125039'))
|
||||||
|
.onClick(async (value) => {
|
||||||
|
showConfirmDialog(i18nHelper.getMessage('125046'), promise.then(() => {
|
||||||
|
}), manager);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName(i18nHelper.getMessage('125001'))
|
.setName(i18nHelper.getMessage('125001'))
|
||||||
.setDesc(i18nHelper.getMessage('125002'))
|
.setDesc(i18nHelper.getMessage('125002'))
|
||||||
@ -79,6 +122,7 @@ function showAdvancedSettings(containerEl: HTMLElement, manager: SettingsManager
|
|||||||
}), manager)
|
}), manager)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName(i18nHelper.getMessage('125031'))
|
.setName(i18nHelper.getMessage('125031'))
|
||||||
.setDesc(i18nHelper.getMessage('125032'))
|
.setDesc(i18nHelper.getMessage('125032'))
|
||||||
@ -92,6 +136,7 @@ function showAdvancedSettings(containerEl: HTMLElement, manager: SettingsManager
|
|||||||
}), manager);
|
}), manager);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetAdvanced( manager: SettingsManager) {
|
function resetAdvanced( manager: SettingsManager) {
|
||||||
@ -100,7 +145,7 @@ function resetAdvanced( manager: SettingsManager) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function showConfirmDialog(message:string, promise:Promise<any>, manager: SettingsManager) {
|
function showConfirmDialog(message:string, promise:Promise<any>, manager: SettingsManager) {
|
||||||
new ConfirmDialogModal(manager.plugin.app, message, promise
|
new ConfirmDialogModal(manager.plugin, message, promise
|
||||||
.then( () => {
|
.then( () => {
|
||||||
manager.plugin.saveSettings();
|
manager.plugin.saveSettings();
|
||||||
})
|
})
|
||||||
|
|||||||
@ -4,14 +4,15 @@ import {Setting, TextComponent} from "obsidian";
|
|||||||
import {i18nHelper} from "../../lang/helper";
|
import {i18nHelper} from "../../lang/helper";
|
||||||
import {DEFAULT_SETTINGS} from "../../constant/DefaultSettings";
|
import {DEFAULT_SETTINGS} from "../../constant/DefaultSettings";
|
||||||
import {DEFAULT_SETTINGS_ARRAY_INPUT_SIZE} from "../../constant/Constsant";
|
import {DEFAULT_SETTINGS_ARRAY_INPUT_SIZE} from "../../constant/Constsant";
|
||||||
|
import DoubanPlugin from "../../main";
|
||||||
|
|
||||||
|
|
||||||
export function arraySettingDisplayUI(containerEl: HTMLElement, manager: SettingsManager) {
|
export function arraySettingDisplayUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
containerEl.createEl('h3', {text: i18nHelper.getMessage('120601')});
|
// containerEl.createEl('h3', {text: i18nHelper.getMessage('120601')});
|
||||||
arraySettingDisplay(containerEl.createDiv('array-settings'), manager, false);
|
arraySettingDisplay(containerEl.createDiv('array-settings'), manager, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function arraySettingDisplay(containerEl: HTMLElement, manager: SettingsManager, displayExtraListTypeFlag: boolean = false) {
|
export function arraySettingDisplay(containerEl: HTMLElement, manager: SettingsManager, displayExtraListTypeFlag: boolean = true) {
|
||||||
containerEl.empty();
|
containerEl.empty();
|
||||||
const arraySet = new Setting(containerEl)
|
const arraySet = new Setting(containerEl)
|
||||||
.setName(i18nHelper.getMessage('120601'))
|
.setName(i18nHelper.getMessage('120601'))
|
||||||
@ -25,27 +26,28 @@ export function arraySettingDisplay(containerEl: HTMLElement, manager: SettingsM
|
|||||||
arraySettingDisplay(containerEl, manager, true);
|
arraySettingDisplay(containerEl, manager, true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
if (displayExtraListTypeFlag) {
|
// if (displayExtraListTypeFlag) {
|
||||||
arraySettingDisplayItem(containerEl, manager, manager.getArraySetting(DEFAULT_SETTINGS_ARRAY_NAME));
|
new Setting(containerEl)
|
||||||
displayExtraListType(manager, containerEl);
|
arraySettingDisplayItem(containerEl, manager, manager.getArraySetting(DEFAULT_SETTINGS_ARRAY_NAME));
|
||||||
arraySet.addButton((button) => {
|
displayExtraListType(manager, containerEl);
|
||||||
button
|
// arraySet.addButton((button) => {
|
||||||
.setIcon('down-chevron-glyph')
|
// button
|
||||||
.setTooltip(i18nHelper.getMessage('120608'))
|
// .setIcon('down-chevron-glyph')
|
||||||
.onClick(async () => {
|
// .setTooltip(i18nHelper.getMessage('120608'))
|
||||||
arraySettingDisplay(containerEl, manager, false);
|
// .onClick(async () => {
|
||||||
});
|
// arraySettingDisplay(containerEl, manager, false);
|
||||||
});
|
// });
|
||||||
}else {
|
// });
|
||||||
arraySet.addButton((button) => {
|
// }else {
|
||||||
button
|
// arraySet.addButton((button) => {
|
||||||
.setIcon('right-chevron-glyph')
|
// button
|
||||||
.setTooltip(i18nHelper.getMessage('120608'))
|
// .setIcon('right-chevron-glyph')
|
||||||
.onClick(async () => {
|
// .setTooltip(i18nHelper.getMessage('120608'))
|
||||||
arraySettingDisplay(containerEl, manager, true);
|
// .onClick(async () => {
|
||||||
});
|
// arraySettingDisplay(containerEl, manager, true);
|
||||||
});
|
// });
|
||||||
}
|
// });
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
function arraySettingDisplayItem(containerEl: HTMLElement, manager: SettingsManager, arraySetting:ArraySetting) {
|
function arraySettingDisplayItem(containerEl: HTMLElement, manager: SettingsManager, arraySetting:ArraySetting) {
|
||||||
|
|||||||
@ -8,12 +8,11 @@ import User from "../user/User";
|
|||||||
import {createFolderSelectionSetting} from "./TemplateSettingHelper";
|
import {createFolderSelectionSetting} from "./TemplateSettingHelper";
|
||||||
import StringUtil from "../../utils/StringUtil";
|
import StringUtil from "../../utils/StringUtil";
|
||||||
import {log} from "../../utils/Logutil";
|
import {log} from "../../utils/Logutil";
|
||||||
|
import DoubanPlugin from "../../main";
|
||||||
|
|
||||||
export function constructBasicUI(containerEl: HTMLElement, manager: SettingsManager) {
|
export function constructBasicUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
containerEl.createEl('h3', { text: i18nHelper.getMessage('1210') });
|
// containerEl.createEl('h3', { text: i18nHelper.getMessage('1210') });
|
||||||
containerEl.createDiv('login-setting', async (loginSettingEl) => {
|
|
||||||
constructDoubanTokenSettingsUI(loginSettingEl, manager);
|
|
||||||
});
|
|
||||||
|
|
||||||
new Setting(containerEl).setName(i18nHelper.getMessage('120501')).then((setting) => {
|
new Setting(containerEl).setName(i18nHelper.getMessage('120501')).then((setting) => {
|
||||||
setting.addMomentFormat((mf) => {
|
setting.addMomentFormat((mf) => {
|
||||||
@ -101,163 +100,3 @@ export function constructBasicUI(containerEl: HTMLElement, manager: SettingsMana
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function constructDoubanTokenSettingsUI(containerEl: HTMLElement, manager: SettingsManager) {
|
|
||||||
containerEl.empty();
|
|
||||||
let login = manager.plugin.userComponent.isLogin();
|
|
||||||
manager.debug(`配置界面:展示豆瓣状态:${login?'已登录':'未登录'}`)
|
|
||||||
if (Platform.isDesktopApp) {
|
|
||||||
if(login) {
|
|
||||||
constructHasLoginSettingsUI(containerEl, manager);
|
|
||||||
}else {
|
|
||||||
constructLoginSettingsUI(containerEl, manager);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(login) {
|
|
||||||
showMobileLogout(containerEl, manager);
|
|
||||||
}else {
|
|
||||||
showMobileLogin(containerEl, manager);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function constructLoginSettingsUI(containerEl: HTMLElement, manager: SettingsManager) {
|
|
||||||
manager.debug(`配置界面:未登录-展示登录按钮`)
|
|
||||||
let loginSetting = containerEl.createDiv("login-button");
|
|
||||||
let loginCookie = containerEl.createDiv("login-button-cookie");
|
|
||||||
|
|
||||||
new Setting(loginSetting).setName(i18nHelper.getMessage('100131')).addButton((button) => {
|
|
||||||
return button
|
|
||||||
.setButtonText(i18nHelper.getMessage('100130'))
|
|
||||||
.onClick(async () => {
|
|
||||||
button.setDisabled(true);
|
|
||||||
manager.debug(`配置界面:点击登录按钮`)
|
|
||||||
const loginModel = new DoubanLoginModel(containerEl, manager);
|
|
||||||
await loginModel.doLogin();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
const loginCookieSetting:Setting = new Setting(loginSetting).setName(i18nHelper.getMessage('100133'));
|
|
||||||
// .setDesc(i18nHelper.getMessage('100134'))
|
|
||||||
loginCookieSetting.addButton((button) => {
|
|
||||||
loginCookieSetting.descEl.appendChild(
|
|
||||||
createFragment((frag) => {
|
|
||||||
frag.appendText(
|
|
||||||
i18nHelper.getMessage('100134')
|
|
||||||
);
|
|
||||||
frag.createEl(
|
|
||||||
'a',
|
|
||||||
{
|
|
||||||
text: i18nHelper.getMessage('100139'),
|
|
||||||
href: 'https://obsidian-douban.wanxuping.com/20_howtouse_25_setting_login_douban_cookie.html',
|
|
||||||
},
|
|
||||||
(a) => {
|
|
||||||
a.setAttr('target', '_blank');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
frag.appendText(i18nHelper.getMessage('100138'));
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
return button
|
|
||||||
.setButtonText(i18nHelper.getMessage('100135'))
|
|
||||||
.onClick(async () => {
|
|
||||||
button.setDisabled(true);
|
|
||||||
manager.debug(`配置界面:点击登录异常处理按钮`)
|
|
||||||
constructLoginCookieSettingsUI(loginCookie, containerEl, manager);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function constructLoginCookieSettingsUI(containerEl: HTMLElement, parentContainerEl: HTMLElement, manager: SettingsManager) {
|
|
||||||
manager.debug(`配置界面:登录异常处理按钮-展示Cookie输入框`)
|
|
||||||
new Setting(containerEl).setName(i18nHelper.getMessage('100136'))
|
|
||||||
.setClass("obsidian_douban_settings_cookie_login").addTextArea((text) => {
|
|
||||||
text.onChange(value => manager.updateCookieTemp(value));
|
|
||||||
return text;
|
|
||||||
}).addExtraButton((button) => {
|
|
||||||
return button
|
|
||||||
.setIcon('check')
|
|
||||||
.onClick(async () => {
|
|
||||||
manager.debug(`配置界面:确认输入Cookie`);
|
|
||||||
const user:User = await manager.plugin.userComponent.loginCookie(manager.getCookieTemp())
|
|
||||||
if (!user || !user.id) {
|
|
||||||
log.notice(i18nHelper.getMessage('100137'))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
constructDoubanTokenSettingsUI(parentContainerEl, manager);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.addExtraButton((button) => {
|
|
||||||
return button
|
|
||||||
.setIcon('x')
|
|
||||||
.onClick(async () => {
|
|
||||||
button.setDisabled(true);
|
|
||||||
manager.debug(`配置界面:取消输入Cookie`);
|
|
||||||
constructDoubanTokenSettingsUI(parentContainerEl, manager);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function constructHasLoginSettingsUI(containerEl: HTMLElement, manager: SettingsManager) {
|
|
||||||
const user: User = manager.plugin.userComponent.getUser();
|
|
||||||
let userDom = new DocumentFragment();
|
|
||||||
userDom.createDiv().innerHTML =
|
|
||||||
`${i18nHelper.getMessage('100120')}<br>
|
|
||||||
${i18nHelper.getMessage('100123')}: <a href="https://www.douban.com/people/${user.id}/">${user.id}</a><br>
|
|
||||||
${i18nHelper.getMessage('100124')}: ${user.name}<br>
|
|
||||||
${i18nHelper.getMessage('100125')}`;
|
|
||||||
manager.debug(`配置界面:展示豆瓣登录信息:id:${StringUtil.confuse(user.id)}, 用户名:${StringUtil.confuse(user.name)}`)
|
|
||||||
new Setting(containerEl)
|
|
||||||
.setName(i18nHelper.getMessage('100126'))
|
|
||||||
.setDesc(userDom)
|
|
||||||
.addButton((button) => {
|
|
||||||
return button
|
|
||||||
.setButtonText(i18nHelper.getMessage('100128'))
|
|
||||||
.setCta()
|
|
||||||
.onClick(async () => {
|
|
||||||
button.setDisabled(true);
|
|
||||||
manager.debug(`配置界面:点击退出登录按钮,准备退出登录`)
|
|
||||||
// manager.debug(`配置界面:登出界面退出登录请求检测成功,准备退出登录`)
|
|
||||||
manager.plugin.userComponent.logout();
|
|
||||||
manager.debug(`配置界面:退出登录成功`);
|
|
||||||
constructDoubanTokenSettingsUI(containerEl, manager);
|
|
||||||
|
|
||||||
// const loginModel = new DoubanLogoutModel(containerEl, manager);
|
|
||||||
// await loginModel.doLogout();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function showMobileLogin(containerEl: HTMLElement, manager: SettingsManager) {
|
|
||||||
new Setting(containerEl)
|
|
||||||
.setName(i18nHelper.getMessage('100126'))
|
|
||||||
.setDesc(i18nHelper.getMessage('100129'))
|
|
||||||
}
|
|
||||||
|
|
||||||
function showMobileLogout(containerEl: HTMLElement, manager: SettingsManager) {
|
|
||||||
const user: User = manager.plugin.userComponent.getUser();
|
|
||||||
let userDom = new DocumentFragment();
|
|
||||||
userDom.createDiv().innerHTML =
|
|
||||||
`${i18nHelper.getMessage('100120')}<br>
|
|
||||||
${i18nHelper.getMessage('100123')}: <a href="https://www.douban.com/people/${user.id}/">${user.id}</a><br>
|
|
||||||
${i18nHelper.getMessage('100124')}: ${user.name}<br>
|
|
||||||
${i18nHelper.getMessage('100125')}`;
|
|
||||||
new Setting(containerEl)
|
|
||||||
.setName(i18nHelper.getMessage('100126'))
|
|
||||||
.setDesc(userDom)
|
|
||||||
.addButton((button) => {
|
|
||||||
return button
|
|
||||||
.setButtonText(i18nHelper.getMessage('100128'))
|
|
||||||
.setCta()
|
|
||||||
.onClick(async () => {
|
|
||||||
button.setDisabled(true);
|
|
||||||
manager.updateSetting('loginCookiesContent', '');
|
|
||||||
manager.updateSetting('loginHeadersContent', '');
|
|
||||||
constructDoubanTokenSettingsUI(containerEl, manager);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@ -3,9 +3,10 @@ import SettingsManager from "./SettingsManager";
|
|||||||
import {CustomProperty} from "./model/CustomProperty";
|
import {CustomProperty} from "./model/CustomProperty";
|
||||||
import {ButtonComponent, DropdownComponent, ExtraButtonComponent, Setting, TextComponent} from "obsidian";
|
import {ButtonComponent, DropdownComponent, ExtraButtonComponent, Setting, TextComponent} from "obsidian";
|
||||||
import {SupportType} from "../../constant/Constsant";
|
import {SupportType} from "../../constant/Constsant";
|
||||||
|
import DoubanPlugin from "../../main";
|
||||||
|
|
||||||
export function constructCustomPropertySettingsUI(containerEl: HTMLElement, manager: SettingsManager) {
|
export function constructCustomPropertySettingsUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
containerEl.createEl('h3', { text: i18nHelper.getMessage('1240') });
|
// containerEl.createEl('h3', { text: i18nHelper.getMessage('1240') });
|
||||||
containerEl.createEl('p', { text: i18nHelper.getMessage('1242') });
|
containerEl.createEl('p', { text: i18nHelper.getMessage('1242') });
|
||||||
const customProperties = manager.plugin.settings.customProperties;
|
const customProperties = manager.plugin.settings.customProperties;
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
|
|||||||
@ -9,11 +9,15 @@ import { constructTemplateVariablesUI } from "./TemplateVariableSettingsHelper";
|
|||||||
import {constructCustomPropertySettingsUI } from "./CustomPropertySettingsHelper";
|
import {constructCustomPropertySettingsUI } from "./CustomPropertySettingsHelper";
|
||||||
import { constructAdvancedUI } from "./AdvancedSettingsHelper";
|
import { constructAdvancedUI } from "./AdvancedSettingsHelper";
|
||||||
import {arraySettingDisplay, arraySettingDisplayUI} from "./ArrayDisplayTypeSettingsHelper";
|
import {arraySettingDisplay, arraySettingDisplayUI} from "./ArrayDisplayTypeSettingsHelper";
|
||||||
|
import {i18nHelper} from "../../lang/helper";
|
||||||
|
import {constructLoginUI} from "./LoginSettingsHelper";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 部分逻辑参考以下项目
|
* 部分逻辑参考以下项目
|
||||||
* obsidian-kanban
|
* obsidian-kanban
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
export class DoubanSettingTab extends PluginSettingTab {
|
export class DoubanSettingTab extends PluginSettingTab {
|
||||||
plugin: DoubanPlugin;
|
plugin: DoubanPlugin;
|
||||||
settingsManager: SettingsManager;
|
settingsManager: SettingsManager;
|
||||||
@ -25,18 +29,51 @@ export class DoubanSettingTab extends PluginSettingTab {
|
|||||||
}
|
}
|
||||||
|
|
||||||
display(): void {
|
display(): void {
|
||||||
const {containerEl} = this;
|
const {containerEl} = this;
|
||||||
containerEl.empty();
|
containerEl.empty();
|
||||||
containerEl.createEl("h2", {text: 'Obsidian Douban'});
|
containerEl.createEl("h2", {text: 'Obsidian Douban'});
|
||||||
new Setting(containerEl);
|
|
||||||
constructBasicUI(containerEl, this.settingsManager);
|
|
||||||
constructTemplateUI(containerEl, this.settingsManager);
|
|
||||||
constructOutUI(containerEl, this.settingsManager);
|
|
||||||
arraySettingDisplayUI(containerEl, this.settingsManager);
|
|
||||||
constructCustomPropertySettingsUI(containerEl, this.settingsManager);
|
|
||||||
constructTemplateVariablesUI(containerEl, this.settingsManager);
|
|
||||||
constructAdvancedUI(containerEl, this.settingsManager);
|
|
||||||
|
|
||||||
|
// Create tab container
|
||||||
|
const tabContainer = containerEl.createEl("div", {cls: "obsidian_douban_settings_tab_container"});
|
||||||
|
const tabHeaders = containerEl.createEl("div", {cls: "obsidian_douban_settings_tab_headers"});
|
||||||
|
const tabContents = containerEl.createEl("div", {cls: "obsidian_douban_settings_tab_contents"});
|
||||||
|
|
||||||
|
// Create tabs
|
||||||
|
const tabs = [
|
||||||
|
{name: i18nHelper.getMessage('1210'), construct: constructBasicUI},
|
||||||
|
{name: i18nHelper.getMessage('1203'), construct: constructTemplateUI},
|
||||||
|
{name: i18nHelper.getMessage('1260'), construct: constructLoginUI},
|
||||||
|
{name: i18nHelper.getMessage('1220'), construct: constructOutUI},
|
||||||
|
{name: i18nHelper.getMessage('120601'), construct: arraySettingDisplayUI},
|
||||||
|
{name: i18nHelper.getMessage('1240'), construct: constructCustomPropertySettingsUI},
|
||||||
|
{name: i18nHelper.getMessage('1230'), construct: constructTemplateVariablesUI},
|
||||||
|
{name: i18nHelper.getMessage('1250'), construct: constructAdvancedUI}
|
||||||
|
];
|
||||||
|
|
||||||
|
tabs.forEach((tab, index) => {
|
||||||
|
const tabHeader = tabHeaders.createEl("div", {cls: "obsidian_douban_settings_tab_header", text: tab.name});
|
||||||
|
const tabContent = tabContents.createEl("div", {cls: "obsidian_douban_settings_tab_content"});
|
||||||
|
tab.construct(tabContent, this.settingsManager);
|
||||||
|
|
||||||
|
// Show the first tab by default
|
||||||
|
if (index === 0) {
|
||||||
|
tabHeader.addClass("active");
|
||||||
|
tabContent.addClass("active");
|
||||||
|
}
|
||||||
|
|
||||||
|
tabHeader.addEventListener("click", () => {
|
||||||
|
// Remove active class from all headers and contents
|
||||||
|
tabHeaders.querySelectorAll(".obsidian_douban_settings_tab_header").forEach(header => header.removeClass("active"));
|
||||||
|
tabContents.querySelectorAll(".obsidian_douban_settings_tab_content").forEach(content => content.removeClass("active"));
|
||||||
|
|
||||||
|
// Add active class to the clicked header and corresponding content
|
||||||
|
tabHeader.addClass("active");
|
||||||
|
tabContent.addClass("active");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tabContainer.appendChild(tabHeaders);
|
||||||
|
tabContainer.appendChild(tabContents);
|
||||||
}
|
}
|
||||||
|
|
||||||
hide(): void {
|
hide(): void {
|
||||||
|
|||||||
192
src/org/wanxp/douban/setting/LoginSettingsHelper.ts
Normal file
192
src/org/wanxp/douban/setting/LoginSettingsHelper.ts
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
import I18nHelper, {i18nHelper} from "../../lang/helper";
|
||||||
|
import {Platform, Setting} from "obsidian";
|
||||||
|
import SettingsManager from "./SettingsManager";
|
||||||
|
import DoubanLoginModel from "../component/DoubanLoginModel";
|
||||||
|
import User from "../user/User";
|
||||||
|
import StringUtil from "../../utils/StringUtil";
|
||||||
|
import {log} from "../../utils/Logutil";
|
||||||
|
|
||||||
|
export function constructLoginUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
|
// containerEl.createEl('h3', { text: i18nHelper.getMessage('1210') });
|
||||||
|
|
||||||
|
const userComponent = manager.plugin.userComponent;
|
||||||
|
if (userComponent.needLogin()) {
|
||||||
|
try {
|
||||||
|
userComponent.login()
|
||||||
|
.then(() => {
|
||||||
|
constructDoubanLoginSettingsUI(containerEl, manager);
|
||||||
|
});
|
||||||
|
}catch (e) {
|
||||||
|
log.debug(i18nHelper.getMessage('100101'));
|
||||||
|
constructDoubanLoginSettingsUI(containerEl, manager);
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
constructDoubanLoginSettingsUI(containerEl, manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export function constructDoubanLoginSettingsUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
|
containerEl.createDiv('login-setting', async (loginSettingEl) => {
|
||||||
|
constructDoubanTokenSettingsUI(loginSettingEl, manager);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function constructDoubanTokenSettingsUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
|
containerEl.empty();
|
||||||
|
let login = manager.plugin.userComponent.isLogin();
|
||||||
|
manager.debug(`配置界面:展示豆瓣状态:${login?'已登录':'未登录'}`)
|
||||||
|
if (Platform.isDesktopApp) {
|
||||||
|
if(login) {
|
||||||
|
constructHasLoginSettingsUI(containerEl, manager);
|
||||||
|
}else {
|
||||||
|
constructLoginSettingsUI(containerEl, manager);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(login) {
|
||||||
|
showMobileLogout(containerEl, manager);
|
||||||
|
}else {
|
||||||
|
showMobileLogin(containerEl, manager);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function constructLoginSettingsUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
|
manager.debug(`配置界面:未登录-展示登录按钮`)
|
||||||
|
let loginSetting = containerEl.createDiv("login-button");
|
||||||
|
let loginCookie = containerEl.createDiv("login-button-cookie");
|
||||||
|
|
||||||
|
new Setting(loginSetting).setName(i18nHelper.getMessage('100131')).addButton((button) => {
|
||||||
|
return button
|
||||||
|
.setButtonText(i18nHelper.getMessage('100130'))
|
||||||
|
.onClick(async () => {
|
||||||
|
button.setDisabled(true);
|
||||||
|
manager.debug(`配置界面:点击登录按钮`)
|
||||||
|
const loginModel = new DoubanLoginModel(containerEl, manager);
|
||||||
|
await loginModel.doLogin();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const loginCookieSetting:Setting = new Setting(loginSetting).setName(i18nHelper.getMessage('100133'));
|
||||||
|
// .setDesc(i18nHelper.getMessage('100134'))
|
||||||
|
loginCookieSetting.addButton((button) => {
|
||||||
|
loginCookieSetting.descEl.appendChild(
|
||||||
|
createFragment((frag) => {
|
||||||
|
frag.appendText(
|
||||||
|
i18nHelper.getMessage('100134')
|
||||||
|
);
|
||||||
|
frag.createEl(
|
||||||
|
'a',
|
||||||
|
{
|
||||||
|
text: i18nHelper.getMessage('100139'),
|
||||||
|
href: 'https://obsidian-douban.wanxuping.com/20_howtouse_25_setting_login_douban_cookie.html',
|
||||||
|
},
|
||||||
|
(a) => {
|
||||||
|
a.setAttr('target', '_blank');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
frag.appendText(i18nHelper.getMessage('100138'));
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
return button
|
||||||
|
.setButtonText(i18nHelper.getMessage('100135'))
|
||||||
|
.onClick(async () => {
|
||||||
|
button.setDisabled(true);
|
||||||
|
manager.debug(`配置界面:点击登录异常处理按钮`)
|
||||||
|
constructLoginCookieSettingsUI(loginCookie, containerEl, manager);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function constructLoginCookieSettingsUI(containerEl: HTMLElement, parentContainerEl: HTMLElement, manager: SettingsManager) {
|
||||||
|
manager.debug(`配置界面:登录异常处理按钮-展示Cookie输入框`)
|
||||||
|
new Setting(containerEl).setName(i18nHelper.getMessage('100136'))
|
||||||
|
.setClass("obsidian_douban_settings_cookie_login").addTextArea((text) => {
|
||||||
|
text.onChange(value => manager.updateCookieTemp(value));
|
||||||
|
return text;
|
||||||
|
}).addExtraButton((button) => {
|
||||||
|
return button
|
||||||
|
.setIcon('check')
|
||||||
|
.onClick(async () => {
|
||||||
|
manager.debug(`配置界面:确认输入Cookie`);
|
||||||
|
const user:User = await manager.plugin.userComponent.loginCookie(manager.getCookieTemp())
|
||||||
|
if (!user || !user.id) {
|
||||||
|
log.notice(i18nHelper.getMessage('100137'))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
constructDoubanTokenSettingsUI(parentContainerEl, manager);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.addExtraButton((button) => {
|
||||||
|
return button
|
||||||
|
.setIcon('x')
|
||||||
|
.onClick(async () => {
|
||||||
|
button.setDisabled(true);
|
||||||
|
manager.debug(`配置界面:取消输入Cookie`);
|
||||||
|
constructDoubanTokenSettingsUI(parentContainerEl, manager);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function constructHasLoginSettingsUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
|
const user: User = manager.plugin.userComponent.getUser();
|
||||||
|
let userDom = new DocumentFragment();
|
||||||
|
userDom.createDiv().innerHTML =
|
||||||
|
`${i18nHelper.getMessage('100120')}<br>
|
||||||
|
${i18nHelper.getMessage('100123')}: <a href="https://www.douban.com/people/${user.id}/">${user.id}</a><br>
|
||||||
|
${i18nHelper.getMessage('100124')}: ${user.name}<br>
|
||||||
|
${i18nHelper.getMessage('100125')}`;
|
||||||
|
manager.debug(`配置界面:展示豆瓣登录信息:id:${StringUtil.confuse(user.id)}, 用户名:${StringUtil.confuse(user.name)}`)
|
||||||
|
new Setting(containerEl)
|
||||||
|
.setName(i18nHelper.getMessage('100126'))
|
||||||
|
.setDesc(userDom)
|
||||||
|
.addButton((button) => {
|
||||||
|
return button
|
||||||
|
.setButtonText(i18nHelper.getMessage('100128'))
|
||||||
|
.setCta()
|
||||||
|
.onClick(async () => {
|
||||||
|
button.setDisabled(true);
|
||||||
|
manager.debug(`配置界面:点击退出登录按钮,准备退出登录`)
|
||||||
|
// manager.debug(`配置界面:登出界面退出登录请求检测成功,准备退出登录`)
|
||||||
|
manager.plugin.userComponent.logout();
|
||||||
|
manager.debug(`配置界面:退出登录成功`);
|
||||||
|
constructDoubanTokenSettingsUI(containerEl, manager);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function showMobileLogin(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
|
new Setting(containerEl)
|
||||||
|
.setName(i18nHelper.getMessage('100126'))
|
||||||
|
.setDesc(i18nHelper.getMessage('100129'))
|
||||||
|
}
|
||||||
|
|
||||||
|
function showMobileLogout(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
|
const user: User = manager.plugin.userComponent.getUser();
|
||||||
|
let userDom = new DocumentFragment();
|
||||||
|
userDom.createDiv().innerHTML =
|
||||||
|
`${i18nHelper.getMessage('100120')}<br>
|
||||||
|
${i18nHelper.getMessage('100123')}: <a href="https://www.douban.com/people/${user.id}/">${user.id}</a><br>
|
||||||
|
${i18nHelper.getMessage('100124')}: ${user.name}<br>
|
||||||
|
${i18nHelper.getMessage('100125')}`;
|
||||||
|
new Setting(containerEl)
|
||||||
|
.setName(i18nHelper.getMessage('100126'))
|
||||||
|
.setDesc(userDom)
|
||||||
|
.addButton((button) => {
|
||||||
|
return button
|
||||||
|
.setButtonText(i18nHelper.getMessage('100128'))
|
||||||
|
.setCta()
|
||||||
|
.onClick(async () => {
|
||||||
|
button.setDisabled(true);
|
||||||
|
manager.updateSetting('loginCookiesContent', '');
|
||||||
|
manager.updateSetting('loginHeadersContent', '');
|
||||||
|
constructDoubanTokenSettingsUI(containerEl, manager);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import {i18nHelper} from "../../lang/helper";
|
import {i18nHelper} from "../../lang/helper";
|
||||||
import {Setting, TextComponent, ToggleComponent} from "obsidian";
|
import {Setting, TextComponent, ToggleComponent} from "obsidian";
|
||||||
import {createFolderSelectionSetting} from "./TemplateSettingHelper";
|
import {createFolderSelectionSetting, createFolderSelectionSettingInput} from "./TemplateSettingHelper";
|
||||||
import {DEFAULT_SETTINGS} from "../../constant/DefaultSettings";
|
import {DEFAULT_SETTINGS} from "../../constant/DefaultSettings";
|
||||||
import {
|
import {
|
||||||
DEFAULT_SETTINGS_ARRAY_INPUT_SIZE, EXAMPLE_RATE, EXAMPLE_RATE_MAX,
|
DEFAULT_SETTINGS_ARRAY_INPUT_SIZE, EXAMPLE_RATE, EXAMPLE_RATE_MAX,
|
||||||
@ -14,6 +14,7 @@ import NumberUtil from "../../utils/NumberUtil";
|
|||||||
import {VariableUtil} from "../../utils/VariableUtil";
|
import {VariableUtil} from "../../utils/VariableUtil";
|
||||||
import {FileUtil} from "../../utils/FileUtil";
|
import {FileUtil} from "../../utils/FileUtil";
|
||||||
import {ScoreSetting} from "./model/ScoreSetting";
|
import {ScoreSetting} from "./model/ScoreSetting";
|
||||||
|
import DoubanPlugin from "../../main";
|
||||||
|
|
||||||
|
|
||||||
function showStarExample(containerEl: HTMLElement, manager: SettingsManager) {
|
function showStarExample(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
@ -111,16 +112,21 @@ function scoreSettingDisplay(containerEl: HTMLElement, manager: SettingsManager)
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function constructOutUI(containerEl: HTMLElement, manager: SettingsManager) {
|
export function constructOutUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
containerEl.createEl('h3', { text: i18nHelper.getMessage('1220') });
|
// containerEl.createEl('h3', { text: i18nHelper.getMessage('1220') });
|
||||||
|
|
||||||
new Setting(containerEl);
|
new Setting(containerEl);
|
||||||
const attachmentFileSetting = containerEl.createDiv({ cls: 'settings-item-attachment' });
|
const attachmentFileSetting = containerEl.createDiv({ cls: 'settings-item-attachment' });
|
||||||
constructAttachmentFileSettingsUI(attachmentFileSetting, manager);
|
constructAttachmentFileSettingsUI(attachmentFileSetting, manager);
|
||||||
|
|
||||||
const folder = new Setting(containerEl);
|
const folder = new Setting(containerEl);
|
||||||
|
const folderInput = new Setting(containerEl);
|
||||||
|
|
||||||
const outFolder = containerEl.createDiv({ cls: 'settings-item' });
|
const outFolder = containerEl.createDiv({ cls: 'settings-item' });
|
||||||
const filePathDisplayExample = containerEl.createDiv('filePath-display-example');
|
const filePathDisplayExample = containerEl.createDiv('filePath-display-example');
|
||||||
folder.then(createFolderSelectionSetting({name: '121501', desc: '121502', placeholder: '121503', key: 'dataFilePath', manager: manager}, filePathDisplayExample));
|
|
||||||
|
folder.then(createFolderSelectionSetting({containerEl: containerEl, name: '121501', desc: '121502', placeholder: null, key: null, manager: manager}, filePathDisplayExample));
|
||||||
|
folderInput.then(createFolderSelectionSettingInput({containerEl: containerEl, name: null, desc: null, placeholder: '121503', key: 'dataFilePath', manager: manager}, filePathDisplayExample));
|
||||||
|
|
||||||
constructOutputFileNameUI(outFolder, filePathDisplayExample, manager);
|
constructOutputFileNameUI(outFolder, filePathDisplayExample, manager);
|
||||||
|
|
||||||
|
|
||||||
@ -215,7 +221,10 @@ export function constructAttachmentFileSettingsUI(containerEl: HTMLElement, mana
|
|||||||
if (manager.plugin.settings.pictureBedFlag) {
|
if (manager.plugin.settings.pictureBedFlag) {
|
||||||
constructAttachmentFilePictureBedSettingsUI(containerEl, manager);
|
constructAttachmentFilePictureBedSettingsUI(containerEl, manager);
|
||||||
}else {
|
}else {
|
||||||
new Setting(containerEl).then(createFolderSelectionSetting({name: '121432', desc: '121433', placeholder: '121434', key: 'attachmentPath', manager: manager}));
|
new Setting(containerEl).then(createFolderSelectionSetting({containerEl: containerEl, name: '121432', desc: '121433', placeholder: null, key: null, manager: manager}));
|
||||||
|
new Setting(containerEl).then(createFolderSelectionSettingInput({containerEl: containerEl, name: null, desc: null, placeholder: '121434', key: 'attachmentPath', manager: manager}));
|
||||||
|
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
|
|||||||
@ -17,6 +17,8 @@ import {
|
|||||||
ArraySettingFieldName,
|
ArraySettingFieldName,
|
||||||
DEFAULT_SETTINGS_ARRAY_NAME
|
DEFAULT_SETTINGS_ARRAY_NAME
|
||||||
} from "./model/ArraySetting";
|
} from "./model/ArraySetting";
|
||||||
|
import {logger} from "bs-logger";
|
||||||
|
import {i18nHelper} from "../../lang/helper";
|
||||||
|
|
||||||
export default class SettingsManager {
|
export default class SettingsManager {
|
||||||
app: App;
|
app: App;
|
||||||
@ -228,4 +230,21 @@ export default class SettingsManager {
|
|||||||
clearSyncCache() {
|
clearSyncCache() {
|
||||||
this.settings.syncHandledDataArray = [];
|
this.settings.syncHandledDataArray = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async loadAndSaveSettings(config: object) {
|
||||||
|
this.validateSettings(config);
|
||||||
|
// @ts-ignore
|
||||||
|
this.settings = Object.assign({}, config);
|
||||||
|
await this.plugin.saveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
private validateSettings(config: object) {
|
||||||
|
if (!config) {
|
||||||
|
this.innerLogger.warn(i18nHelper.getMessage('125040'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getSettings() {
|
||||||
|
return this.settings;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,43 +7,50 @@ import {getDefaultTemplateContent} from "../../constant/DefaultTemplateContent";
|
|||||||
import {FolderSuggest} from "./model/FolderSuggest";
|
import {FolderSuggest} from "./model/FolderSuggest";
|
||||||
import SettingsManager from "./SettingsManager";
|
import SettingsManager from "./SettingsManager";
|
||||||
import {showFileExample} from "./OutputSettingsHelper";
|
import {showFileExample} from "./OutputSettingsHelper";
|
||||||
|
import {FileTreeSelectSuggest} from "./model/FileTreeSelectSuggest";
|
||||||
|
import DoubanPlugin from "../../main";
|
||||||
|
import {FolderTreeSelectSuggest} from "./model/FolderTreeSelectSuggest";
|
||||||
|
|
||||||
|
|
||||||
export function constructTemplateUI(containerEl: HTMLElement, manager: SettingsManager) {
|
export function constructTemplateUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
containerEl.createEl('h3', { text: i18nHelper.getMessage('1203') });
|
// containerEl.createEl('h3', { text: i18nHelper.getMessage('1203') });
|
||||||
containerEl.createEl('p', { text: i18nHelper.getMessage('1204') });
|
containerEl.createEl('p', { text: i18nHelper.getMessage('1204') });
|
||||||
new Setting(containerEl).setDesc(i18nHelper.getMessage('1205'))
|
new Setting(containerEl).setDesc(i18nHelper.getMessage('1205'))
|
||||||
|
|
||||||
new Setting(containerEl).then(createFileSelectionSetting({name: '120101', desc: '120102', placeholder: '121701', key: 'movieTemplateFile', manager: manager}));
|
new Setting(containerEl).then(createFileSelectionSetting({containerEl: containerEl, name: '120101', desc: '120102', placeholder: '121701', key: 'movieTemplateFile', manager: manager}));
|
||||||
new Setting(containerEl).then(createFileSelectionSetting({name: '120201', desc: '120202', placeholder: '121701', key: 'bookTemplateFile', manager: manager}));
|
new Setting(containerEl).then(createFileSelectionSetting({containerEl: containerEl, name: '120201', desc: '120202', placeholder: '121701', key: 'bookTemplateFile', manager: manager}));
|
||||||
new Setting(containerEl).then(createFileSelectionSetting({name: '120301', desc: '120302', placeholder: '121701', key: 'musicTemplateFile', manager: manager}));
|
new Setting(containerEl).then(createFileSelectionSetting({containerEl: containerEl, name: '120301', desc: '120302', placeholder: '121701', key: 'musicTemplateFile', manager: manager}));
|
||||||
new Setting(containerEl).then(createFileSelectionSetting({name: '120401', desc: '120402', placeholder: '121701', key: 'noteTemplateFile', manager: manager}));
|
new Setting(containerEl).then(createFileSelectionSetting({containerEl: containerEl, name: '120401', desc: '120402', placeholder: '121701', key: 'noteTemplateFile', manager: manager}));
|
||||||
new Setting(containerEl).then(createFileSelectionSetting({name: '121301', desc: '121302', placeholder: '121701', key: 'gameTemplateFile', manager: manager}));
|
new Setting(containerEl).then(createFileSelectionSetting({containerEl: containerEl, name: '121301', desc: '121302', placeholder: '121701', key: 'gameTemplateFile', manager: manager}));
|
||||||
new Setting(containerEl).then(createFileSelectionSetting({name: '121801', desc: '121802', placeholder: '121701', key: 'teleplayTemplateFile', manager: manager}));
|
new Setting(containerEl).then(createFileSelectionSetting({containerEl: containerEl, name: '121801', desc: '121802', placeholder: '121701', key: 'teleplayTemplateFile', manager: manager}));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createFileSelectionSetting({name, desc, placeholder, key, manager
|
export function createFileSelectionSetting({containerEl, name, desc, placeholder, key, manager
|
||||||
}: CreateTemplateSelectParams) {
|
}: CreateTemplateSelectParams) {
|
||||||
return (setting: Setting) => {
|
return (setting: Setting) => {
|
||||||
|
setting.controlEl.addClass('obsidian_douban_template_file_select');
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
setting.setName(i18nHelper.getMessage(name));
|
setting.setName(i18nHelper.getMessage(name));
|
||||||
// @ts-ignore
|
// settingDesc.setDesc(i18nHelper.getMessage(desc));
|
||||||
setting.setDesc(i18nHelper.getMessage(desc));
|
|
||||||
setting.addSearch(async (search: SearchComponent) => {
|
setting.addSearch(async (search: SearchComponent) => {
|
||||||
const [oldValue, defaultVal] = manager.getSettingWithDefault(key);
|
const [oldValue, defaultVal] = manager.getSettingWithDefault(key);
|
||||||
let v = defaultVal;
|
let v = defaultVal;
|
||||||
if (oldValue) {
|
if (oldValue) {
|
||||||
v = oldValue;
|
v = oldValue;
|
||||||
}
|
}
|
||||||
new FileSuggest(manager.app, search.inputEl);
|
const fileTreeSelectSuggest = new FileTreeSelectSuggest(manager.app, search.inputEl, manager, key);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
search.setValue(v);
|
search.setValue(v);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
search.setPlaceholder(i18nHelper.getMessage(placeholder));
|
search.setPlaceholder(i18nHelper.getMessage(placeholder));
|
||||||
search.onChange(async (value: string) => {
|
search.inputEl.addClass('obsidian_douban_template_file_select_input');
|
||||||
|
search.inputEl.style.width = '100%';
|
||||||
|
search.onChange(async (value: string) => {
|
||||||
manager.updateSetting(key, value);
|
manager.updateSetting(key, value);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
setting.addExtraButton((button) => {
|
setting.addExtraButton((button) => {
|
||||||
button
|
button
|
||||||
.setIcon('copy')
|
.setIcon('copy')
|
||||||
@ -74,13 +81,25 @@ export function createFolderSelectionSetting({
|
|||||||
setting.setName( i18nHelper.getMessage(name));
|
setting.setName( i18nHelper.getMessage(name));
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
setting.setDesc( i18nHelper.getMessage(desc));
|
setting.setDesc( i18nHelper.getMessage(desc));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export function createFolderSelectionSettingInput({
|
||||||
|
name, desc, placeholder, key, manager,
|
||||||
|
}: CreateTemplateSelectParams, filePathDisplayExample?:HTMLDivElement) {
|
||||||
|
return (setting: Setting) => {
|
||||||
|
setting.controlEl.addClass('obsidian_douban_template_file_select');
|
||||||
setting.addSearch(async (search: SearchComponent) => {
|
setting.addSearch(async (search: SearchComponent) => {
|
||||||
const [oldValue, defaultVal] = manager.getSettingWithDefault(key);
|
const [oldValue, defaultVal] = manager.getSettingWithDefault(key);
|
||||||
let v = defaultVal;
|
let v = defaultVal;
|
||||||
if (oldValue) {
|
if (oldValue) {
|
||||||
v = oldValue;
|
v = oldValue;
|
||||||
}
|
}
|
||||||
new FolderSuggest(manager.app, search.inputEl);
|
new FolderTreeSelectSuggest(manager.app, search.inputEl);
|
||||||
|
search.inputEl.addClass('obsidian_douban_template_file_select_input');
|
||||||
|
search.inputEl.style.width = '100%';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
search.setValue(v)
|
search.setValue(v)
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -95,5 +114,3 @@ export function createFolderSelectionSetting({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
import SettingsManager from "./SettingsManager";
|
import SettingsManager from "./SettingsManager";
|
||||||
import {i18nHelper} from "../../lang/helper";
|
import {i18nHelper} from "../../lang/helper";
|
||||||
import {Setting} from "obsidian";
|
import {Setting} from "obsidian";
|
||||||
|
import DoubanPlugin from "../../main";
|
||||||
|
|
||||||
export function constructTemplateVariablesUI(containerEl: HTMLElement, manager: SettingsManager) {
|
export function constructTemplateVariablesUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
containerEl.createEl('h3', { text: i18nHelper.getMessage('1230') });
|
// containerEl.createEl('h3', { text: i18nHelper.getMessage('1230') });
|
||||||
containerEl.createEl('p', { text: i18nHelper.getMessage('122003') });
|
containerEl.createEl('p', { text: i18nHelper.getMessage('122003') });
|
||||||
|
|
||||||
const basicVariablesTable = new DocumentFragment();
|
const basicVariablesTable = new DocumentFragment();
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { DoubanPluginSetting } from "./DoubanPluginSetting";
|
|||||||
|
|
||||||
export interface CreateTemplateSelectParams {
|
export interface CreateTemplateSelectParams {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
containerEl: HTMLElement,
|
||||||
name:string,
|
name:string,
|
||||||
desc:string,
|
desc:string,
|
||||||
placeholder:string,
|
placeholder:string,
|
||||||
|
|||||||
@ -36,6 +36,7 @@ export interface DoubanPluginSetting {
|
|||||||
pictureBedType: string;
|
pictureBedType: string;
|
||||||
pictureBedSetting: PictureBedSetting;
|
pictureBedSetting: PictureBedSetting;
|
||||||
syncHandledDataArray: SyncHandledData[],
|
syncHandledDataArray: SyncHandledData[],
|
||||||
|
// syncLastUpdateTime: Map<string, string>,
|
||||||
arraySettings: ArraySetting[],
|
arraySettings: ArraySetting[],
|
||||||
scoreSetting: ScoreSetting,
|
scoreSetting: ScoreSetting,
|
||||||
}
|
}
|
||||||
|
|||||||
90
src/org/wanxp/douban/setting/model/FileTreeSelectSuggest.ts
Normal file
90
src/org/wanxp/douban/setting/model/FileTreeSelectSuggest.ts
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
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[] = [];
|
||||||
|
|
||||||
|
if (inputStr.length == 0 || inputStr.trim().length == 0 || inputStr.trim() == '/') {
|
||||||
|
this.searchFiles(this.app.vault.getRoot(), "", files);
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
let parentSearchPath:string = null;
|
||||||
|
let currentName:string = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const testFile = this.app.vault.getAbstractFileByPath(inputStr.trim())
|
||||||
|
if (testFile) {
|
||||||
|
if (testFile instanceof TFile && testFile.name.endsWith(".md")) {
|
||||||
|
files.push(testFile);
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
if (testFile instanceof TFolder) {
|
||||||
|
parentSearchPath = inputStr.trim();
|
||||||
|
currentName = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}catch (e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
if (parentSearchPath == null) {
|
||||||
|
parentSearchPath = inputStr.lastIndexOf("/") > 0 ? inputStr.substring(0, inputStr.lastIndexOf("/")) : "/";
|
||||||
|
currentName = inputStr.lastIndexOf("/") > 0 ? inputStr.substring(inputStr.lastIndexOf("/") + 1) : inputStr;
|
||||||
|
currentName = currentName.trim();
|
||||||
|
}
|
||||||
|
if (currentName == null) {
|
||||||
|
currentName = "";
|
||||||
|
}
|
||||||
|
const root = this.app.vault.getAbstractFileByPath(parentSearchPath) as TFolder;
|
||||||
|
if (!root) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const name = currentName.toLowerCase();
|
||||||
|
if (root) {
|
||||||
|
this.searchFiles(root, name, files);
|
||||||
|
}
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
searchFiles(folder: TFolder, name: string, files: TAbstractFile[]): void {
|
||||||
|
folder.children.forEach((file: TAbstractFile) => {
|
||||||
|
if (file.name.toLowerCase().contains(name)) {
|
||||||
|
files.push(file);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSuggestion(file: TAbstractFile, el: HTMLElement): void {
|
||||||
|
el.setText(file.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
selectSuggestion(file: TAbstractFile): void {
|
||||||
|
this.inputEl.value = file.path;
|
||||||
|
this.parentPath = file.path;
|
||||||
|
// this.inputEl.addEventListener("change", () => {
|
||||||
|
// this.onInputChanged()
|
||||||
|
// })
|
||||||
|
if (file instanceof TFolder) {
|
||||||
|
this.inputEl.value += "/";
|
||||||
|
this.inputEl.trigger("input");
|
||||||
|
}else {
|
||||||
|
//@ts-ignore
|
||||||
|
this.manager.updateSetting(this.settingKey, file.path);
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,78 @@
|
|||||||
|
import {TAbstractFile, TFile, TFolder} from "obsidian";
|
||||||
|
import {TextInputSuggest} from "./TextInputSuggest";
|
||||||
|
|
||||||
|
export class FolderTreeSelectSuggest extends TextInputSuggest<TAbstractFile> {
|
||||||
|
parentPath: string = "/";
|
||||||
|
|
||||||
|
getSuggestions(inputStr: string): TAbstractFile[] {
|
||||||
|
const files: TAbstractFile[] = [];
|
||||||
|
|
||||||
|
if (inputStr.length == 0 || inputStr.trim().length == 0 || inputStr.trim() == '/') {
|
||||||
|
this.searchFiles(this.app.vault.getRoot(), "", files);
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
let parentSearchPath:string = null;
|
||||||
|
let currentName:string = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const testFile = this.app.vault.getAbstractFileByPath(inputStr.trim())
|
||||||
|
if (testFile) {
|
||||||
|
if (testFile instanceof TFile) {
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
if (testFile instanceof TFolder) {
|
||||||
|
parentSearchPath = inputStr.trim();
|
||||||
|
currentName = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}catch (e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
if (parentSearchPath == null) {
|
||||||
|
parentSearchPath = inputStr.lastIndexOf("/") > 0 ? inputStr.substring(0, inputStr.lastIndexOf("/")) : "/";
|
||||||
|
currentName = inputStr.lastIndexOf("/") > 0 ? inputStr.substring(inputStr.lastIndexOf("/") + 1) : inputStr;
|
||||||
|
currentName = currentName.trim();
|
||||||
|
}
|
||||||
|
if (currentName == null) {
|
||||||
|
currentName = "";
|
||||||
|
}
|
||||||
|
const root = this.app.vault.getAbstractFileByPath(parentSearchPath) as TFolder;
|
||||||
|
if (!root) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const name = currentName.toLowerCase();
|
||||||
|
if (root) {
|
||||||
|
this.searchFiles(root, name, files);
|
||||||
|
}
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
searchFiles(folder: TFolder, name: string, files: TAbstractFile[]): void {
|
||||||
|
folder.children.filter(f => f instanceof TFolder).forEach((file: TAbstractFile) => {
|
||||||
|
if (file.name.toLowerCase().contains(name)) {
|
||||||
|
files.push(file);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSuggestion(file: TAbstractFile, el: HTMLElement): void {
|
||||||
|
el.setText(file.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
selectSuggestion(file: TAbstractFile): void {
|
||||||
|
this.inputEl.value = file.path;
|
||||||
|
this.parentPath = file.path;
|
||||||
|
// this.inputEl.addEventListener("change", () => {
|
||||||
|
// this.onInputChanged()
|
||||||
|
// })
|
||||||
|
if (file instanceof TFolder) {
|
||||||
|
this.inputEl.value += "/";
|
||||||
|
this.inputEl.trigger("input");
|
||||||
|
}else {
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,25 +1,67 @@
|
|||||||
import DoubanPlugin from "../../../main";
|
import DoubanPlugin from "../../../main";
|
||||||
import {BasicConst, SubjectHandledStatus, SyncType} from "../../../constant/Constsant";
|
import {
|
||||||
import {DoubanSyncHandler} from "./DoubanSyncHandler";
|
BasicConst,
|
||||||
import {SyncConfig} from "../model/SyncConfig";
|
PAGE_SIZE,
|
||||||
|
SyncConditionType,
|
||||||
|
SyncType,
|
||||||
|
} from "../../../constant/Constsant";
|
||||||
|
import { DoubanSyncHandler } from "./DoubanSyncHandler";
|
||||||
|
import { SyncConfig } from "../model/SyncConfig";
|
||||||
import HandleContext from "../../data/model/HandleContext";
|
import HandleContext from "../../data/model/HandleContext";
|
||||||
import {SubjectListItem} from "../../data/model/SubjectListItem";
|
import { SubjectListItem } from "../../data/model/SubjectListItem";
|
||||||
import {sleepRange} from "../../../utils/TimeUtil";
|
import { sleepRange } from "../../../utils/TimeUtil";
|
||||||
import DoubanSubjectLoadHandler from "../../data/handler/DoubanSubjectLoadHandler";
|
import DoubanSubjectLoadHandler from "../../data/handler/DoubanSubjectLoadHandler";
|
||||||
import {DoubanListHandler} from "./list/DoubanListHandler";
|
import { DoubanListHandler } from "./list/DoubanListHandler";
|
||||||
import DoubanSubject from "../../data/model/DoubanSubject";
|
import DoubanSubject from "../../data/model/DoubanSubject";
|
||||||
import {log} from "../../../utils/Logutil";
|
import { log } from "../../../utils/Logutil";
|
||||||
import {i18nHelper} from "../../../lang/helper";
|
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 plugin: DoubanPlugin;
|
||||||
private doubanSubjectLoadHandler:DoubanSubjectLoadHandler<T>;
|
private doubanSubjectLoadHandler: DoubanSubjectLoadHandler<T>;
|
||||||
private doubanListHandlers:DoubanListHandler[];
|
private doubanListHandlers: DoubanListHandler[];
|
||||||
|
|
||||||
constructor(plugin: DoubanPlugin,
|
constructor(
|
||||||
doubanSubjectLoadHandler:DoubanSubjectLoadHandler<T>,
|
plugin: DoubanPlugin,
|
||||||
doubanListHandlers:DoubanListHandler[]) {
|
doubanSubjectLoadHandler: DoubanSubjectLoadHandler<T>,
|
||||||
|
doubanListHandlers: DoubanListHandler[],
|
||||||
|
) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.doubanSubjectLoadHandler = doubanSubjectLoadHandler;
|
this.doubanSubjectLoadHandler = doubanSubjectLoadHandler;
|
||||||
this.doubanListHandlers = doubanListHandlers;
|
this.doubanListHandlers = doubanListHandlers;
|
||||||
@ -31,61 +73,387 @@ export abstract class DoubanAbstractSyncHandler<T extends DoubanSubject> implem
|
|||||||
|
|
||||||
abstract getSyncType(): SyncType;
|
abstract getSyncType(): SyncType;
|
||||||
|
|
||||||
async sync(syncConfig: SyncConfig, context: HandleContext): Promise<void>{
|
async sync(syncConfig: SyncConfig, context: HandleContext): Promise<void> {
|
||||||
return Promise.resolve()
|
if (syncConfig.syncConditionType == SyncConditionType.CUSTOM_TIME) {
|
||||||
.then(() => this.getItems(syncConfig, context))
|
await this.syncByTimeLimit(syncConfig, context);
|
||||||
.then(items => this.removeExists(items , syncConfig, context))
|
} else if (syncConfig.syncConditionType == SyncConditionType.CUSTOM_ITEM) {
|
||||||
.then(items => this.handleItems(items, context));
|
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()) {
|
if (!context.plugin.statusHolder.syncing()) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
return items;
|
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) {
|
if (!items || items.length == 0) {
|
||||||
return ;
|
return;
|
||||||
}
|
}
|
||||||
const {syncStatus} = context.syncStatusHolder;
|
const { syncStatus } = context.syncStatusHolder;
|
||||||
syncStatus.totalNum(items.length);
|
syncStatus.totalNum(searchPage.total);
|
||||||
const needHandled:number = items.filter(item => syncStatus.shouldSync(item.id)).length;
|
const needHandled: number =
|
||||||
|
syncStatus.getTotal() - syncStatus.getHasHandle();
|
||||||
syncStatus.setNeedHandled(needHandled);
|
syncStatus.setNeedHandled(needHandled);
|
||||||
for (const item of items) {
|
for (const item of items) {
|
||||||
if (!context.plugin.statusHolder.syncing()) {
|
if (!context.plugin.statusHolder.syncing()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if(syncStatus.shouldSync(item.id)) {
|
if (syncStatus.shouldSync(item.id)) {
|
||||||
let subject: DoubanSubject = await this.doubanSubjectLoadHandler.handle(item.id, context);
|
let subject: DoubanSubject =
|
||||||
await sleepRange(BasicConst.CALL_DOUBAN_DELAY, BasicConst.CALL_DOUBAN_DELAY + BasicConst.CALL_DOUBAN_DELAY_RANGE);
|
await this.doubanSubjectLoadHandler.handle(
|
||||||
}else {
|
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);
|
syncStatus.unHandle(item.id, item.title);
|
||||||
}
|
}
|
||||||
}catch (e) {
|
} catch (e) {
|
||||||
log.notice(i18nHelper.getMessage('130120'))
|
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 { DoubanBookSyncHandler } from "./DoubanBookSyncHandler";
|
||||||
import {i18nHelper} from "../../../lang/helper";
|
import {i18nHelper} from "../../../lang/helper";
|
||||||
import {DoubanTeleplaySyncHandler} from "./DoubanTeleplaySyncHandler";
|
import {DoubanTeleplaySyncHandler} from "./DoubanTeleplaySyncHandler";
|
||||||
|
import {SyncConditionType} from "../../../constant/Constsant";
|
||||||
|
|
||||||
export default class SyncHandler {
|
export default class SyncHandler {
|
||||||
private app: App;
|
private app: App;
|
||||||
@ -18,6 +19,7 @@ export default class SyncHandler {
|
|||||||
private syncHandlers: DoubanSyncHandler[];
|
private syncHandlers: DoubanSyncHandler[];
|
||||||
private defaultSyncHandler: DoubanSyncHandler;
|
private defaultSyncHandler: DoubanSyncHandler;
|
||||||
|
|
||||||
|
|
||||||
constructor(app: App, plugin: DoubanPlugin, syncConfig: SyncConfig, context: HandleContext) {
|
constructor(app: App, plugin: DoubanPlugin, syncConfig: SyncConfig, context: HandleContext) {
|
||||||
this.app = app;
|
this.app = app;
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
@ -38,6 +40,10 @@ export default class SyncHandler {
|
|||||||
|
|
||||||
async sync() {
|
async sync() {
|
||||||
if (this.syncConfig && this.syncConfig.syncType && this.syncConfig.scope) {
|
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));
|
let syncHandler = this.syncHandlers.find(handler => handler.support(this.syncConfig.syncType));
|
||||||
if (syncHandler) {
|
if (syncHandler) {
|
||||||
await syncHandler.sync(this.syncConfig, this.context);
|
await syncHandler.sync(this.syncConfig, this.context);
|
||||||
@ -53,6 +59,25 @@ export default class SyncHandler {
|
|||||||
const {syncStatus} = syncStatusHolder;
|
const {syncStatus} = syncStatusHolder;
|
||||||
const {statusHandleMap} = syncStatus;
|
const {statusHandleMap} = syncStatus;
|
||||||
const {syncResultMap} = 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
|
let summary:string
|
||||||
= `${i18nHelper.getMessage('110053', i18nHelper.getMessage('110050'), i18nHelper.getMessage('110051'), i18nHelper.getMessage('110052'))}
|
= `${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')}`
|
const resultFileName = `${i18nHelper.getMessage('110038')}_${moment(new Date()).format('YYYYMMDDHHmmss')}`
|
||||||
await this.plugin.fileHandler.createNewNoteWithData(`${this.syncConfig.dataFilePath}/${resultFileName}`, result, true);
|
await this.plugin.fileHandler.createNewNoteWithData(`${this.syncConfig.dataFilePath}/${resultFileName}`, result, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 { request, RequestUrlParam } from "obsidian";
|
||||||
import {i18nHelper} from 'src/org/wanxp/lang/helper';
|
import { i18nHelper } from "src/org/wanxp/lang/helper";
|
||||||
import {log} from "src/org/wanxp/utils/Logutil";
|
import { log } from "src/org/wanxp/utils/Logutil";
|
||||||
import {CheerioAPI, load} from "cheerio";
|
import { CheerioAPI, load } from "cheerio";
|
||||||
import HandleContext from "../../../data/model/HandleContext";
|
import HandleContext from "../../../data/model/HandleContext";
|
||||||
import {doubanSubjectSyncListUrl} from "../../../../constant/Douban";
|
import { doubanSubjectSyncListUrl } from "../../../../constant/Douban";
|
||||||
import {BasicConst, PAGE_SIZE, SyncType, SyncTypeUrlDomain} from "../../../../constant/Constsant";
|
import {
|
||||||
import {SubjectListItem} from "../../../data/model/SubjectListItem";
|
BasicConst,
|
||||||
import {DoubanListHandler} from "./DoubanListHandler";
|
PAGE_SIZE,
|
||||||
import {SyncConfig} from "../../model/SyncConfig";
|
SyncType,
|
||||||
import { sleepRange} from "../../../../utils/TimeUtil";
|
SyncTypeUrlDomain,
|
||||||
import {ALL} from "../../../../constant/DoubanUserState";
|
} 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 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[]>{
|
const url: string = this.getUrl(context, context.syncOffset);
|
||||||
let all:SubjectListItem[] = [];
|
if (!context.plugin.statusHolder.syncing()) {
|
||||||
let pages:SubjectListItem[] = [];
|
return SearchPage.emptyWithNoType();
|
||||||
let start = 0;
|
}
|
||||||
do {
|
let subjectListItemSearchPageTypeOf = await this.getPageList(url, context);
|
||||||
await sleepRange(BasicConst.CALL_DOUBAN_DELAY,
|
if (subjectListItemSearchPageTypeOf) {
|
||||||
BasicConst.CALL_DOUBAN_DELAY + BasicConst.CALL_DOUBAN_DELAY_RANGE);
|
context.plugin.statusHolder.syncStatus.setAllTotal(subjectListItemSearchPageTypeOf.total)
|
||||||
const url:string = this.getUrl(context, start);
|
}
|
||||||
if (!context.plugin.statusHolder.syncing()) {
|
return subjectListItemSearchPageTypeOf;
|
||||||
return [];
|
|
||||||
}
|
|
||||||
pages = await this.getPageList(url, context);
|
|
||||||
if (pages) {
|
|
||||||
all = all.concat(pages);
|
|
||||||
}
|
|
||||||
start = start + PAGE_SIZE;
|
|
||||||
} while (pages && pages.length > 0)
|
|
||||||
return all;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
abstract getDoType(): string;
|
||||||
return doubanSubjectSyncListUrl(this.getSyncTypeDomain(), context.userComponent.getUserId(), this.getDoType(), start);
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract getDoType():string;
|
abstract getSyncType(): SyncType;
|
||||||
|
|
||||||
abstract getSyncType():SyncType;
|
getSyncTypeDomain(): string {
|
||||||
|
|
||||||
getSyncTypeDomain():string {
|
|
||||||
return SyncTypeUrlDomain.get(this.getSyncType());
|
return SyncTypeUrlDomain.get(this.getSyncType());
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPageList(url: string, context: HandleContext):Promise<SubjectListItem[]> {
|
async getPageList(
|
||||||
return DoubanHttpUtil.httpRequestGet(url, context.plugin.settingsManager.getHeaders(), context.plugin.settingsManager)
|
url: string,
|
||||||
|
context: HandleContext,
|
||||||
|
): Promise<SearchPageTypeOf<SubjectListItem>> {
|
||||||
|
return DoubanHttpUtil.httpRequestGet(
|
||||||
|
url,
|
||||||
|
context.plugin.settingsManager.getHeaders(),
|
||||||
|
context.plugin.settingsManager,
|
||||||
|
)
|
||||||
.then(load)
|
.then(load)
|
||||||
.then(data => this.parseSubjectFromHtml(data, context))
|
.then((data) => this.parseSubjectFromHtml(data, context))
|
||||||
.catch(e => log
|
.catch((e) =>
|
||||||
.error(
|
log.error(
|
||||||
i18nHelper.getMessage('130101')
|
i18nHelper
|
||||||
.replace('{0}', e.toString())
|
.getMessage("130101")
|
||||||
, e));
|
.replace("{0}", e.toString()),
|
||||||
;
|
e,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parseSubjectFromHtml(
|
||||||
|
dataHtml: CheerioAPI,
|
||||||
|
context: HandleContext,
|
||||||
|
): SearchPageTypeOf<SubjectListItem> {
|
||||||
parseSubjectFromHtml(dataHtml: CheerioAPI, context: HandleContext):SubjectListItem[] {
|
const items = dataHtml(".item-show")
|
||||||
return dataHtml('.item-show')
|
|
||||||
.get()
|
.get()
|
||||||
.map((i: any) => {
|
.map((i: any) => {
|
||||||
const item = dataHtml(i);
|
const item = dataHtml(i);
|
||||||
const linkValue:string = item.find('div.title > a').attr('href');
|
const linkValue: string = item
|
||||||
const titleValue:string = item.find('div.title > a').text().trim();
|
.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 idPattern = /(\d){5,10}/g;
|
||||||
let ececResult = idPattern.exec(linkValue);
|
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;
|
// 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 {
|
support(config: SyncConfig): boolean {
|
||||||
return this.getDoType() == config.scope || ALL == config.scope;
|
return this.getDoType() == config.scope || ALL == config.scope;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import HandleContext from "../../../data/model/HandleContext";
|
import HandleContext from "../../../data/model/HandleContext";
|
||||||
import {SubjectListItem} from "../../../data/model/SubjectListItem";
|
|
||||||
import {SyncConfig} from "../../model/SyncConfig";
|
import {SyncConfig} from "../../model/SyncConfig";
|
||||||
|
import {SearchPage} from "../../../data/model/SearchPage";
|
||||||
|
|
||||||
export interface DoubanListHandler {
|
export interface DoubanListHandler {
|
||||||
|
|
||||||
getAllPageList(context: HandleContext):Promise<SubjectListItem[]>;
|
getPageData(context: HandleContext):Promise<SearchPage>;
|
||||||
|
|
||||||
support(config:SyncConfig):boolean;
|
support(config:SyncConfig):boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,10 @@
|
|||||||
export interface SyncConfig {
|
export interface SyncConfig {
|
||||||
syncType: string,
|
syncType: string,
|
||||||
|
syncConditionType: string,
|
||||||
|
syncConditionCountFromValue: number,
|
||||||
|
syncConditionCountToValue: number,
|
||||||
|
syncConditionDateFromValue: Date,
|
||||||
|
syncConditionDateToValue: Date,
|
||||||
scope: string,
|
scope: string,
|
||||||
force: boolean,
|
force: boolean,
|
||||||
dataFilePath: string;
|
dataFilePath: string;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import {SyncItemStatus} from "../../../constant/Constsant";
|
import { SyncItemStatus } from "../../../constant/Constsant";
|
||||||
|
|
||||||
export interface SyncItemResult {
|
export interface SyncItemResult {
|
||||||
id:string,
|
id: string;
|
||||||
title:string,
|
title: string;
|
||||||
status:SyncItemStatus,
|
status: SyncItemStatus;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,18 @@
|
|||||||
import {SyncConfig} from "./SyncConfig";
|
import {SyncConfig} from "./SyncConfig";
|
||||||
import {SyncItemResult} from "./SyncItemResult";
|
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 {SyncHandledData} from "../../setting/model/SyncHandledData";
|
||||||
|
import {
|
||||||
|
DoubanSubjectState,
|
||||||
|
DoubanSubjectStateRecords,
|
||||||
|
DoubanSubjectStateRecords_SYNC
|
||||||
|
} from "../../../constant/DoubanUserState";
|
||||||
|
|
||||||
export default class SyncStatusHolder {
|
export default class SyncStatusHolder {
|
||||||
|
|
||||||
@ -12,15 +23,20 @@ export default class SyncStatusHolder {
|
|||||||
[SyncItemStatus.replace, 0],
|
[SyncItemStatus.replace, 0],
|
||||||
[SyncItemStatus.create, 0],
|
[SyncItemStatus.create, 0],
|
||||||
[SyncItemStatus.fail, 0],
|
[SyncItemStatus.fail, 0],
|
||||||
[SyncItemStatus.unHandle, 0],
|
[SyncItemStatus.failByDiffType, 0],
|
||||||
|
[SyncItemStatus.unHandle, 0],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
private key: string;
|
private key: string;
|
||||||
|
//不管处不处理的总数,比如会包含已经存在的,或者条件没覆盖的部分,比如过滤条件选择了1-2条,但总共其实有10条
|
||||||
|
private allTotal: number;
|
||||||
|
|
||||||
public syncConfig: SyncConfig;
|
public syncConfig: SyncConfig;
|
||||||
|
//处理的总数
|
||||||
private total:number;
|
private total:number;
|
||||||
private handle:number;
|
private handle:number;
|
||||||
private needHandled:number;
|
private needHandled:number;
|
||||||
|
private message:string = '';
|
||||||
|
|
||||||
constructor(syncConfig: SyncConfig) {
|
constructor(syncConfig: SyncConfig) {
|
||||||
this.syncConfig = syncConfig;
|
this.syncConfig = syncConfig;
|
||||||
@ -46,6 +62,16 @@ export default class SyncStatusHolder {
|
|||||||
return this.handle;
|
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);
|
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) {
|
private updateResult(id:string, title:string, status:SyncItemStatus) {
|
||||||
this.syncResultMap.set(id, {id: id,title:title,status:status});
|
this.syncResultMap.set(id, {id: id,title:title,status:status});
|
||||||
this.statusHandleMap.set(status, this.statusHandleMap.get(status) + 1);
|
this.statusHandleMap.set(status, this.statusHandleMap.get(status) + 1);
|
||||||
@ -161,4 +191,26 @@ export default class SyncStatusHolder {
|
|||||||
return false;
|
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 {
|
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) {
|
if (!locale) {
|
||||||
console.error('Error: obsidian douban locale not found', lang);
|
console.error('Error: obsidian douban locale not found', lang);
|
||||||
}
|
}
|
||||||
|
// @ts-ignore
|
||||||
let val:string = (locale && locale[str]) || en[str];
|
let val:string = (locale && locale[str]) || en[str];
|
||||||
if (params) {
|
if (params) {
|
||||||
for (let i:number = 0;i < params.length;i++) {
|
for (let i:number = 0;i < params.length;i++) {
|
||||||
val = val.replaceAll(`{${i}}`, params[i])
|
val = this.replaceAll(i, val, params[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return val;
|
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();
|
export const i18nHelper: I18nHelper = new I18nHelper();
|
||||||
|
|||||||
@ -23,33 +23,60 @@ export default {
|
|||||||
'110035': `FileName: (Tip:Support Variables And Path)`,
|
'110035': `FileName: (Tip:Support Variables And Path)`,
|
||||||
'110036': `Complete`,
|
'110036': `Complete`,
|
||||||
'110037': `
|
'110037': `
|
||||||
### Summary
|
### Condition
|
||||||
{0}
|
{0}
|
||||||
|
|
||||||
### Details
|
### Summary
|
||||||
{1}
|
{1}
|
||||||
|
|
||||||
|
### Details
|
||||||
|
{2}
|
||||||
|
|
||||||
---
|
---
|
||||||
PS: This file could be delete if you want to.
|
PS: This file could be delete if you want to.
|
||||||
`,
|
`,
|
||||||
'110038': `DoubanSyncResult`,
|
'110038': `DoubanSyncResult`,
|
||||||
'110039': `SyncNotSync:`,
|
'110039': `Incremental Sync:`,
|
||||||
'110040': `Only sync that haven't been synced yet. if not enabled, will sync all the subject'`,
|
'110040': `Only sync that haven't been synced yet. if not enabled, will sync all the subject'`,
|
||||||
'110041': `IncrementalSync`,
|
'110041': `IncrementalSync`,
|
||||||
'110042': `EstimateTime`,
|
'110042': `EstimateTime`,
|
||||||
'110043': `Loading Menu`,
|
'110043': `Loading Menu`,
|
||||||
|
'110044': `Custom Count Input End Must Bigger Than Start`,
|
||||||
|
'110045': `Custom Time Input End Must Bigger Than Start`,
|
||||||
|
|
||||||
'110050': `Type`,
|
'110050': `Type`,
|
||||||
'110051': `Number`,
|
'110051': `Number`,
|
||||||
'110052': `Description`,
|
'110052': `Description`,
|
||||||
'110152': `Confirm`,
|
'110152': `Confirm`,
|
||||||
|
'110055': `Enable`,
|
||||||
|
'110056': `Disable`,
|
||||||
|
|
||||||
|
'110070': `Sync Scope:`,
|
||||||
|
'110071': `All`,
|
||||||
|
'110072': `Recent Changes`,
|
||||||
|
'110075': `Last 30 Items`,
|
||||||
|
'110074': `Custom Time`,
|
||||||
|
'110076': `Custom Count`,
|
||||||
|
'110077': `From`,
|
||||||
|
'110078': `No.`,
|
||||||
|
'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]`,
|
'exists':`[exists]`,
|
||||||
'unHandle':`[unHandle]`,
|
'unHandle':`[unHandle]`,
|
||||||
'replace':`[replace]`,
|
'replace':`[replace]`,
|
||||||
'create':`[create]`,
|
'create':`[create]`,
|
||||||
'fail':`[fail]`,
|
'fail':`[fail]`,
|
||||||
|
'failByDiffType': `[fail by diff type]`,
|
||||||
'syncall':`[summary]`,
|
'syncall':`[summary]`,
|
||||||
'notsync':`[notsync]`,
|
'notsync':`[notsync]`,
|
||||||
|
|
||||||
@ -58,6 +85,7 @@ PS: This file could be delete if you want to.
|
|||||||
'replace_desc': `replace`,
|
'replace_desc': `replace`,
|
||||||
'create_desc': `create`,
|
'create_desc': `create`,
|
||||||
'fail_desc': `fail`,
|
'fail_desc': `fail`,
|
||||||
|
'failByDiffType_desc': `fail because of different type`,
|
||||||
'notsync_desc': `notsync`,
|
'notsync_desc': `notsync`,
|
||||||
'syncall_desc': `syncall`,
|
'syncall_desc': `syncall`,
|
||||||
|
|
||||||
@ -100,13 +128,14 @@ PS: This file could be delete if you want to.
|
|||||||
'100132': `Load Douban Login Page Failed`,
|
'100132': `Load Douban Login Page Failed`,
|
||||||
|
|
||||||
|
|
||||||
'1210': `Basic Setting`,
|
'1210': `Basic`,
|
||||||
'1203': `Template Setting`,
|
'1203': `Template`,
|
||||||
'1220': `Output Setting`,
|
'1220': `Output`,
|
||||||
'1230': `Usable Variables`,
|
'1230': `Description`,
|
||||||
'1204': `Set template file path. If keep empty, it will use the default template file to create file. All the usable variables at the end.👇`,
|
'1260': `Login`,
|
||||||
|
'1204': `Set template file path. The template file will be used when creating new notes . If keep empty, it will use the default template file to create file. All the usable variables at tab "Description" and "Custom Variables"`,
|
||||||
'1205': `🧡Tip: You can click the 'Copy' button to copy default template content, then create and paste to your own template file. After that, back to select the file. `,
|
'1205': `🧡Tip: You can click the 'Copy' button to copy default template content, then create and paste to your own template file. After that, back to select the file. `,
|
||||||
'1250': `Advanced Setting`,
|
'1250': `Advanced`,
|
||||||
'1252': `Some Debug or Other Settings`,
|
'1252': `Some Debug or Other Settings`,
|
||||||
'1251': `☢The Advanced Setting only could be changed after you know what you are doing`,
|
'1251': `☢The Advanced Setting only could be changed after you know what you are doing`,
|
||||||
|
|
||||||
@ -139,18 +168,18 @@ PS: This file could be delete if you want to.
|
|||||||
'121101': `Template File`,
|
'121101': `Template File`,
|
||||||
'121102': `This template will be used when creating new notes. If keep empty, it will use default template`,
|
'121102': `This template will be used when creating new notes. If keep empty, it will use default template`,
|
||||||
|
|
||||||
'120101': `Movie Template File`,
|
'120101': `Movie`,
|
||||||
'120102': `This template will be used when creating new notes for Movie from Obsidian-Douban.`,
|
'120102': `This template will be used when creating new notes for Movie from Obsidian-Douban.`,
|
||||||
'120103': `Available template variables are :`,
|
'120103': `Available template variables are :`,
|
||||||
'120104': `{{id}}, {{title}}, {{type}}, {{score}}, {{image}},`,
|
'120104': `{{id}}, {{title}}, {{type}}, {{score}}, {{image}},`,
|
||||||
'120105': `{{url}}, {{desc}}, {{datePublished}}, {{genre}}, `,
|
'120105': `{{url}}, {{desc}}, {{datePublished}}, {{genre}}, `,
|
||||||
'120106': `{{originalTitle}},{{director}}, {{author}},`,
|
'120106': `{{originalTitle}},{{director}}, {{author}},`,
|
||||||
'120107': ` {{actor}}`,
|
'120107': ` {{actor}}`,
|
||||||
'120110': `Movie Template File`,
|
'120110': `Movie`,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
'120201': `Book Template File`,
|
'120201': `Book`,
|
||||||
'120202': `This template will be used when creating new notes for Movie from Obsidian-Douban. `,
|
'120202': `This template will be used when creating new notes for Movie from Obsidian-Douban. `,
|
||||||
'120203': `Available Book template variables are :`,
|
'120203': `Available Book template variables are :`,
|
||||||
'120204': `{{id}}, {{title}}, {{type}}, {{score}}, {{image}},`,
|
'120204': `{{id}}, {{title}}, {{type}}, {{score}}, {{image}},`,
|
||||||
@ -159,7 +188,7 @@ PS: This file could be delete if you want to.
|
|||||||
'120207': `{{translator}}, {{isbn}}, {{price}}, {{totalPage}}`,
|
'120207': `{{translator}}, {{isbn}}, {{price}}, {{totalPage}}`,
|
||||||
'120208': `{{series}}, {{binding}}, {{menu}}`,
|
'120208': `{{series}}, {{binding}}, {{menu}}`,
|
||||||
|
|
||||||
'120301': `Music Template File`,
|
'120301': `Music`,
|
||||||
'120302': `This template will be used when creating new notes for Music from Obsidian-Douban.`,
|
'120302': `This template will be used when creating new notes for Music from Obsidian-Douban.`,
|
||||||
'120303': `Available Music template variables are :`,
|
'120303': `Available Music template variables are :`,
|
||||||
'120304': `{{id}}, {{title}}, {{type}}, {{score}}, {{image}},`,
|
'120304': `{{id}}, {{title}}, {{type}}, {{score}}, {{image}},`,
|
||||||
@ -167,7 +196,7 @@ PS: This file could be delete if you want to.
|
|||||||
'120306': `{{actor}}, {{medium}}, {{albumType}},`,
|
'120306': `{{actor}}, {{medium}}, {{albumType}},`,
|
||||||
'120307': `{{barcode}}, {{records}}`,
|
'120307': `{{barcode}}, {{records}}`,
|
||||||
|
|
||||||
'120401': `Article Template File`,
|
'120401': `Article`,
|
||||||
'120402': `This template will be used when creating new notes for Article from Obsidian-Douban.`,
|
'120402': `This template will be used when creating new notes for Article from Obsidian-Douban.`,
|
||||||
'120403': `Available Article template variables are :`,
|
'120403': `Available Article template variables are :`,
|
||||||
'120404': `{{id}}, {{title}}, {{type}}, {{image}},`,
|
'120404': `{{id}}, {{title}}, {{type}}, {{image}},`,
|
||||||
@ -175,14 +204,14 @@ PS: This file could be delete if you want to.
|
|||||||
'120406': `{{author}}, {{authorUrl}}, {{content}}`,
|
'120406': `{{author}}, {{authorUrl}}, {{content}}`,
|
||||||
'120407': `{{timePublished}}`,
|
'120407': `{{timePublished}}`,
|
||||||
|
|
||||||
'121301': `Game Template File`,
|
'121301': `Game`,
|
||||||
'121302': `This template will be used when creating new notes for Game from Obsidian-Douban.`,
|
'121302': `This template will be used when creating new notes for Game from Obsidian-Douban.`,
|
||||||
'121303': `Available Game template variables are :`,
|
'121303': `Available Game template variables are :`,
|
||||||
'121304': `{{id}}, {{title}}, {{type}}, {{score}}, {{image}},`,
|
'121304': `{{id}}, {{title}}, {{type}}, {{score}}, {{image}},`,
|
||||||
'121305': `{{url}}, {{desc}}, {{publisher}}, {{datePublished}}`,
|
'121305': `{{url}}, {{desc}}, {{publisher}}, {{datePublished}}`,
|
||||||
'121306': `{{genre}}, {{aliases}}, {{developer}}, {{platform}}`,
|
'121306': `{{genre}}, {{aliases}}, {{developer}}, {{platform}}`,
|
||||||
|
|
||||||
'121801': `Teleplay Template File`,
|
'121801': `Teleplay`,
|
||||||
'121802': `This template will be used when creating new notes for Teleplay from Obsidian-Douban.`,
|
'121802': `This template will be used when creating new notes for Teleplay from Obsidian-Douban.`,
|
||||||
|
|
||||||
'120501': `Date Format`,
|
'120501': `Date Format`,
|
||||||
@ -193,7 +222,7 @@ PS: This file could be delete if you want to.
|
|||||||
'120506': `For more syntax, refer to`,
|
'120506': `For more syntax, refer to`,
|
||||||
'120507': `Your current syntax looks like this`,
|
'120507': `Your current syntax looks like this`,
|
||||||
'120508': `format reference`,
|
'120508': `format reference`,
|
||||||
'120601': `Array Spilt String`,
|
'120601': `Array`,
|
||||||
'120602': `string to join between array type, start、end string for array, such as authors, actors.
|
'120602': `string to join between array type, start、end string for array, such as authors, actors.
|
||||||
support \n (enter)`,
|
support \n (enter)`,
|
||||||
'120701': `Douban Request Headers`,
|
'120701': `Douban Request Headers`,
|
||||||
@ -272,6 +301,21 @@ PS: This file could be delete if you want to.
|
|||||||
|
|
||||||
'125033': `Are you sure you want to perform this operation?`,
|
'125033': `Are you sure you want to perform this operation?`,
|
||||||
|
|
||||||
|
"125034": `Export Settings`,
|
||||||
|
"125035": `Export current plugin all settings to a local file, including all settings, sync records cache, and login status`,
|
||||||
|
"125047": `Choose Folder..`,
|
||||||
|
"125036": `Import Settings`,
|
||||||
|
"125037": `Import a previously backed up settings file, which will cover all current settings, sync records cache, and login status. For safety, it is recommended to backup the current settings before attempting to import`,
|
||||||
|
"125038": `Import Settings File`,
|
||||||
|
"125039": `Select File..`,
|
||||||
|
"125040": `Import`,
|
||||||
|
"125041": `Settings Import Successful`,
|
||||||
|
"125042": `Settings Import Failed`,
|
||||||
|
"125043": `Settings File Import Failed, please check if the file is correct`,
|
||||||
|
"125044": `Settings File Import Successful`,
|
||||||
|
"125045": `Settings File Import Successful, please reload the page`,
|
||||||
|
"125046": `Are you sure you import the settings file? Please make sure you have export settings before import config file. Note: Importing the settings file will **cover** all current settings, sync records cache, and login status`,
|
||||||
|
|
||||||
//error
|
//error
|
||||||
'130101': `Fetch Data Error, {0}`,
|
'130101': `Fetch Data Error, {0}`,
|
||||||
'140101': `Not support for current type. You can add Issues at Github:Wanxp/obsidian-douban`,
|
'140101': `Not support for current type. You can add Issues at Github:Wanxp/obsidian-douban`,
|
||||||
@ -282,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`,
|
'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`,
|
'130108': `Redirect times too much, please check your network or proxy`,
|
||||||
'130120': `An error occurred during Sync, but Sync will continue. Error item is {}`,
|
'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}'...`,
|
'140201': `[OB-Douban]: searching '{0}'...`,
|
||||||
'140202': `[OB-Douban]: result {0} rows`,
|
'140202': `[OB-Douban]: result {0} rows`,
|
||||||
|
|||||||
@ -17,19 +17,49 @@ export default {
|
|||||||
'110010': `后台运行`,
|
'110010': `后台运行`,
|
||||||
'110008': `已经存在同步任务: {0}-{1}, 结束之后再重试`,
|
'110008': `已经存在同步任务: {0}-{1}, 结束之后再重试`,
|
||||||
'500002': `同步状态`,
|
'500002': `同步状态`,
|
||||||
'110030': `类型:`,
|
'110030': `选择类型:`,
|
||||||
'110031': `替换同名文档:`,
|
'110031': `替换同名文档:`,
|
||||||
'110032': `范围:`,
|
'110032': `选择状态:`,
|
||||||
'110033': `进度:`,
|
'110033': `进度:`,
|
||||||
'110034': `输出文件夹:`,
|
'110034': `输出文件夹:`,
|
||||||
'110035': `文档名: (提示:支持参数化以及多级路径, 可用参数见配置界面)`,
|
'110035': `文档名: (提示:支持参数化以及多级路径, 可用参数见配置界面)`,
|
||||||
'110036': `完成`,
|
'110036': `完成`,
|
||||||
'110152': `确认`,
|
'110152': `确认`,
|
||||||
|
'110070': `同步范围:`,
|
||||||
|
'110071': `全部`,
|
||||||
|
'110072': `最新变动`,
|
||||||
|
'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': `
|
'110037': `
|
||||||
### 同步结果汇总
|
### 同步条件
|
||||||
{0}
|
{0}
|
||||||
|
|
||||||
|
### 同步结果汇总
|
||||||
|
{1}
|
||||||
|
|
||||||
### 同步结果明细
|
### 同步结果明细
|
||||||
{1}
|
{1}
|
||||||
|
|
||||||
@ -38,20 +68,26 @@ export default {
|
|||||||
`,
|
`,
|
||||||
'110038': `豆瓣同步结果`,
|
'110038': `豆瓣同步结果`,
|
||||||
'110039': `增量同步:`,
|
'110039': `增量同步:`,
|
||||||
'110040': `仅同步上面'笔记存放位置'目录中最近新增/同步失败/未同步的部分,不同步已同步的内容.若关闭则会全量同步.增量同步会更快,适合之前同步中途失败停止或最近有豆瓣新增了内容,全量同步适合修改了模板或修改了存放路径情况下进行.`,
|
'110040': `仅同步最近新增/同步失败/未同步的部分,增量适合之前同步中途失败停止或最近有豆瓣新增了内容,全量同步适合修改了模板或修改了存放路径情况下进行.`,
|
||||||
'110041': `使用增量`,
|
'110041': `使用增量`,
|
||||||
'110042': `预计处理时间`,
|
'110042': `预计处理时间`,
|
||||||
'110043': `正在获取需要同步的列表, 请稍后`,
|
'110043': `正在获取需要同步的列表, 请稍后`,
|
||||||
|
'110044': `自定义条数的录入结束数量不能比开始数量小`,
|
||||||
|
'110045': `自定义时间的录入结束时间不能比开始时间小`,
|
||||||
|
|
||||||
|
|
||||||
'110050': `类型`,
|
'110050': `类型`,
|
||||||
'110051': `数量`,
|
'110051': `数量`,
|
||||||
'110052': `说明`,
|
'110052': `说明`,
|
||||||
|
'110055': `开启`,
|
||||||
|
'110056': `关闭`,
|
||||||
|
|
||||||
'unHandle':`[已忽略]`,
|
'unHandle':`[已忽略]`,
|
||||||
'exists': `[未替换]`,
|
'exists': `[未替换]`,
|
||||||
'replace': `[已替换]`,
|
'replace': `[已替换]`,
|
||||||
'create': `[已创建]`,
|
'create': `[已创建]`,
|
||||||
'fail': `[已失败]`,
|
'fail': `[已失败]`,
|
||||||
|
'failByDiffType': `[类型不匹配]`,
|
||||||
'syncall': `[总数]`,
|
'syncall': `[总数]`,
|
||||||
'notsync': `[未进行]`,
|
'notsync': `[未进行]`,
|
||||||
|
|
||||||
@ -60,6 +96,7 @@ export default {
|
|||||||
'replace_desc': `已经存在的同名文档,这次已被替换`,
|
'replace_desc': `已经存在的同名文档,这次已被替换`,
|
||||||
'create_desc': `之前不存在的文档,这次直接新增`,
|
'create_desc': `之前不存在的文档,这次直接新增`,
|
||||||
'fail_desc': `处理过程钟出现错误,未能成功`,
|
'fail_desc': `处理过程钟出现错误,未能成功`,
|
||||||
|
'failByDiffType_desc': `失败,类型不匹配,比如想要同步的是电影,但是实际获取到的是电视剧`,
|
||||||
'notsync_desc': `因异常中断或提前终止导致还未处理`,
|
'notsync_desc': `因异常中断或提前终止导致还未处理`,
|
||||||
'syncall_desc': `您此次同步条件在豆瓣中的条目总数`,
|
'syncall_desc': `您此次同步条件在豆瓣中的条目总数`,
|
||||||
|
|
||||||
@ -102,17 +139,18 @@ export default {
|
|||||||
'120005': `所跳转的网页地址即是搜索地址,`,
|
'120005': `所跳转的网页地址即是搜索地址,`,
|
||||||
'120006': `将网页地址复制到当前输入框即可,`,
|
'120006': `将网页地址复制到当前输入框即可,`,
|
||||||
|
|
||||||
'1210': `基础配置`,
|
'1210': `基础`,
|
||||||
'1203': `模板配置`,
|
'1203': `模板`,
|
||||||
'1220': `输出配置`,
|
'1220': `输出`,
|
||||||
'1230': `可用参数`,
|
'1230': `字段`,
|
||||||
|
'1260': `登录`,
|
||||||
|
|
||||||
'1204': `配置对应类型的模板文件, 如果为空则使用默认模板. 模板可使用的参数列举在最下面.👇 `,
|
'1204': `配置对应类型的模板文件, 如果为空则使用默认模板. 模板可使用的参数在页签'字段'和'自定义字段'中查看`,
|
||||||
'1205': `🧡提示: 建议点击右侧'复制'默认模板按钮, 然后在新建的文件中粘贴修改模板, 最后回到此处选择对应模板. `,
|
'1205': `🧡提示: 建议点击右侧'复制'默认模板按钮, 然后在新建的文件中粘贴修改模板, 最后回到此处选择对应模板. `,
|
||||||
'1240': `自定义属性`,
|
'1240': `自定义字段`,
|
||||||
'1241': `自定义参数,值本身也支持使用参数,如myTitle:《{{title}}》。在模板中使用参数时请用'{{}}'包裹, 举例: 参数myType, 则使用时为{{myType}}. `,
|
'1241': `自定义参数,值本身也支持使用参数,如myTitle:《{{title}}》。在模板中使用参数时请用'{{}}'包裹, 举例: 参数myType, 则使用时为{{myType}}. `,
|
||||||
'1242': `添加自定义参数, 参数可用于模板中或者文件名中. `,
|
'1242': `添加自定义参数, 参数可用于模板中或者文件名中. `,
|
||||||
'1250': `高级设置`,
|
'1250': `高级`,
|
||||||
'1252': `一些运行时的高级配置,如开启debug模式`,
|
'1252': `一些运行时的高级配置,如开启debug模式`,
|
||||||
'1251': `☢高级设置只有当你知道修改此设置之后的影响才允许修改, 正常情况下请保持默认`,
|
'1251': `☢高级设置只有当你知道修改此设置之后的影响才允许修改, 正常情况下请保持默认`,
|
||||||
|
|
||||||
@ -130,6 +168,20 @@ export default {
|
|||||||
|
|
||||||
'125033': `确认要执行此操作吗?`,
|
'125033': `确认要执行此操作吗?`,
|
||||||
|
|
||||||
|
"125034": `导出配置`,
|
||||||
|
"125035": `导出当前插件的所有配置到一个本地文件中,包括所有设置、同步记录的缓存、登录状态`,
|
||||||
|
"125047": `选择路径..`,
|
||||||
|
"125036": `导入配置`,
|
||||||
|
"125037": `导入一个之前导出的配置文件,将会覆盖当前所有设置、同步记录的缓存、登录状态。为了安全起见,建议先导出当前配置再尝试导入`,
|
||||||
|
"125038": `导入配置文件`,
|
||||||
|
"125039": `选择文件..`,
|
||||||
|
"125040": `导入`,
|
||||||
|
"125041": `导入配置成功`,
|
||||||
|
"125042": `导入配置失败`,
|
||||||
|
"125043": `导入配置文件失败,请检查文件是否正确`,
|
||||||
|
"125044": `导入配置文件成功`,
|
||||||
|
"125045": `导入配置文件成功,请重新加载页面`,
|
||||||
|
"125046": `导入配置文件,注意先导出配置备份,然后才导入配置文件`,
|
||||||
|
|
||||||
'124101': `新增`,
|
'124101': `新增`,
|
||||||
'124108': `新增一个自定义参数`,
|
'124108': `新增一个自定义参数`,
|
||||||
@ -143,7 +195,7 @@ export default {
|
|||||||
'121101': `模板文件`,
|
'121101': `模板文件`,
|
||||||
'121102': `如果为空, 笔记将会会使用默认模板`,
|
'121102': `如果为空, 笔记将会会使用默认模板`,
|
||||||
|
|
||||||
'120101': `电影模板文件`,
|
'120101': `电影`,
|
||||||
'120102': `导入电影所使用的模板, 请输入并选择对应的文件路径`,
|
'120102': `导入电影所使用的模板, 请输入并选择对应的文件路径`,
|
||||||
'120103': `支持以下参数名称 :`,
|
'120103': `支持以下参数名称 :`,
|
||||||
'120104': `{{id}}, {{title}}, {{type}}, {{score}}, {{image}},`,
|
'120104': `{{id}}, {{title}}, {{type}}, {{score}}, {{image}},`,
|
||||||
@ -151,7 +203,7 @@ export default {
|
|||||||
'120106': `{{originalTitle}},{{director}}, {{author}},`,
|
'120106': `{{originalTitle}},{{director}}, {{author}},`,
|
||||||
'120107': ` {{actor}}`,
|
'120107': ` {{actor}}`,
|
||||||
|
|
||||||
'120201': `书籍模板文件`,
|
'120201': `书籍`,
|
||||||
'120202': `导入书籍所使用的模板, 请输入并选择对应的文件路径`,
|
'120202': `导入书籍所使用的模板, 请输入并选择对应的文件路径`,
|
||||||
'120203': `支持以下参数名称 :`,
|
'120203': `支持以下参数名称 :`,
|
||||||
'120204': `{{id}}, {{title}}, {{type}}, {{score}}, {{image}},`,
|
'120204': `{{id}}, {{title}}, {{type}}, {{score}}, {{image}},`,
|
||||||
@ -160,7 +212,7 @@ export default {
|
|||||||
'120207': `{{translator}}, {{isbn}}, {{price}}, {{totalPage}}`,
|
'120207': `{{translator}}, {{isbn}}, {{price}}, {{totalPage}}`,
|
||||||
'120208': `{{series}}, {{binding}}, {{menu}}`,
|
'120208': `{{series}}, {{binding}}, {{menu}}`,
|
||||||
|
|
||||||
'120301': `音乐模板文件`,
|
'120301': `音乐`,
|
||||||
'120302': `导入音乐所使用的模板, 请输入并选择对应的文件路径`,
|
'120302': `导入音乐所使用的模板, 请输入并选择对应的文件路径`,
|
||||||
'120303': `支持以下参数名称 :`,
|
'120303': `支持以下参数名称 :`,
|
||||||
'120304': `{{id}}, {{title}}, {{type}}, {{image}},`,
|
'120304': `{{id}}, {{title}}, {{type}}, {{image}},`,
|
||||||
@ -168,7 +220,7 @@ export default {
|
|||||||
'120306': `{{genre}}, {{actor}}, {{medium}}, {{albumType}},`,
|
'120306': `{{genre}}, {{actor}}, {{medium}}, {{albumType}},`,
|
||||||
'120307': `{{barcode}}, {{records}}`,
|
'120307': `{{barcode}}, {{records}}`,
|
||||||
|
|
||||||
'120401': `日记模板文件`,
|
'120401': `日记`,
|
||||||
'120402': `导入日记所使用的模板, 请输入并选择对应的文件路径`,
|
'120402': `导入日记所使用的模板, 请输入并选择对应的文件路径`,
|
||||||
'120403': `支持以下参数名称 :`,
|
'120403': `支持以下参数名称 :`,
|
||||||
'120404': `{{id}}, {{title}}, {{type}}, {{image}},`,
|
'120404': `{{id}}, {{title}}, {{type}}, {{image}},`,
|
||||||
@ -176,7 +228,7 @@ export default {
|
|||||||
'120406': `{{author}}, {{authorUrl}}, {{content}}`,
|
'120406': `{{author}}, {{authorUrl}}, {{content}}`,
|
||||||
'120407': `{{timePublished}}`,
|
'120407': `{{timePublished}}`,
|
||||||
|
|
||||||
'121301': `游戏模板文件`,
|
'121301': `游戏`,
|
||||||
'121302': `导入游戏所使用的模板, 请输入并选择对应的文件路径`,
|
'121302': `导入游戏所使用的模板, 请输入并选择对应的文件路径`,
|
||||||
'121303': `支持以下参数名称 :`,
|
'121303': `支持以下参数名称 :`,
|
||||||
'121304': `{{id}}, {{title}}, {{type}}, {{score}}, {{image}},`,
|
'121304': `{{id}}, {{title}}, {{type}}, {{score}}, {{image}},`,
|
||||||
@ -184,7 +236,7 @@ export default {
|
|||||||
'121306': `{{genre}}, {{aliases}}, {{developer}}, {{platform}}`,
|
'121306': `{{genre}}, {{aliases}}, {{developer}}, {{platform}}`,
|
||||||
|
|
||||||
|
|
||||||
'121801': `电视剧模板文件`,
|
'121801': `电视剧`,
|
||||||
'121802': `导入电视剧所使用的模板, 请输入并选择对应的文件路径`,
|
'121802': `导入电视剧所使用的模板, 请输入并选择对应的文件路径`,
|
||||||
|
|
||||||
|
|
||||||
@ -195,9 +247,9 @@ export default {
|
|||||||
'120506': `详细介绍请参考`,
|
'120506': `详细介绍请参考`,
|
||||||
'120507': `时间参数时间格式预览`,
|
'120507': `时间参数时间格式预览`,
|
||||||
'120508': `格式参考`,
|
'120508': `格式参考`,
|
||||||
'120601': `数组显示形式`,
|
'120601': `数组显示`,
|
||||||
'120602': `当模板中的变量存在数组, 则需要设定数组元素中的分割符号以及起始与结束符号, 比如演员列表,
|
'120602': `当模板中的变量存在数组, 则需要设定数组元素中的分割符号以及起始与结束符号, 比如演员列表,
|
||||||
支持转义字符\\n(回车)。并且同时支持多种方式输出内容,显示更多配置可点击右侧[>>]展开或点击[+]新增不同输出形式,且支持输出结果预览。`,
|
支持转义字符\\n(回车)。并且同时支持多种方式输出内容,点击[+]新增不同输出形式,预览效果在下方`,
|
||||||
'124109': `首:`,
|
'124109': `首:`,
|
||||||
'124110': `元素首:`,
|
'124110': `元素首:`,
|
||||||
'124111': `分隔符:`,
|
'124111': `分隔符:`,
|
||||||
@ -279,6 +331,7 @@ export default {
|
|||||||
'130106': `请尝试在Douban插件中登录后操作. 若还是无效果则尝试于12小时或24小时后再重试,或重置你的网络(如重新拨号或更换网络) `,
|
'130106': `请尝试在Douban插件中登录后操作. 若还是无效果则尝试于12小时或24小时后再重试,或重置你的网络(如重新拨号或更换网络) `,
|
||||||
'130107': `参数{0}中指定的数组输出类型{1}不存在,请前往配置进行设置`,
|
'130107': `参数{0}中指定的数组输出类型{1}不存在,请前往配置进行设置`,
|
||||||
'130120': `同步时发生错误,但同步将会继续。错误项目是 {}。`,
|
'130120': `同步时发生错误,但同步将会继续。错误项目是 {}。`,
|
||||||
|
'130121': `总数只有{0}, 选择的开始比总数还要大,将不会同步。`,
|
||||||
|
|
||||||
'140201': `[OB-Douban]: 开始搜索'{0}'...`,
|
'140201': `[OB-Douban]: 开始搜索'{0}'...`,
|
||||||
'140202': `[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) {
|
if (context.syncActive && extract.guessType && extract.guessType != extract.type) {
|
||||||
extract.handledStatus = SubjectHandledStatus.syncTypeDiffAbort;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
if (Action.Sync == context.action) {
|
if (Action.Sync == context.action) {
|
||||||
@ -224,16 +229,10 @@ export default class DoubanPlugin extends Plugin {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.settingsManager = new SettingsManager(app, this);
|
this.settingsManager = new SettingsManager(app, this);
|
||||||
this.fetchOnlineData(this.settingsManager);
|
// this.fetchOnlineData(this.settingsManager);
|
||||||
this.userComponent = new UserComponent(this.settingsManager);
|
this.userComponent = new UserComponent(this.settingsManager);
|
||||||
this.netFileHandler = new NetFileHandler(this.fileHandler);
|
this.netFileHandler = new NetFileHandler(this.fileHandler);
|
||||||
if (this.userComponent.needLogin()) {
|
|
||||||
try {
|
|
||||||
await this.userComponent.login();
|
|
||||||
}catch (e) {
|
|
||||||
log.debug(i18nHelper.getMessage('100101'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.settingTab = new DoubanSettingTab(this.app, this);
|
this.settingTab = new DoubanSettingTab(this.app, this);
|
||||||
this.addSettingTab(this.settingTab);
|
this.addSettingTab(this.settingTab);
|
||||||
this.statusHolder = new GlobalStatusHolder(this.app, this);
|
this.statusHolder = new GlobalStatusHolder(this.app, this);
|
||||||
@ -322,22 +321,5 @@ export default class DoubanPlugin extends Plugin {
|
|||||||
syncConfig.dataFileNamePath = syncConfig.dataFileNamePath ? syncConfig.dataFileNamePath : DEFAULT_SETTINGS.dataFileNamePath;
|
syncConfig.dataFileNamePath = syncConfig.dataFileNamePath ? syncConfig.dataFileNamePath : DEFAULT_SETTINGS.dataFileNamePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
private fetchOnlineData(settingsManager: SettingsManager) {
|
|
||||||
// const gistId: string = this.settings.onlineSettingsGistId??DEFAULT_SETTINGS.onlineSettingsGistId;
|
|
||||||
// const fileName: string = this.settings.onlineSettingsFileName??DEFAULT_SETTINGS.onlineSettingsFileName;
|
|
||||||
const gistId: string = DEFAULT_SETTINGS.onlineSettingsGistId;
|
|
||||||
const fileName: string = DEFAULT_SETTINGS.onlineSettingsFileName;
|
|
||||||
GithubUtil.getGistsData(gistId, fileName)
|
|
||||||
.then(data => {
|
|
||||||
this.onlineData = JSON.parse(data);
|
|
||||||
this.fillOnlineData(this.onlineData, settingsManager);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fillOnlineData(onlineData: DoubanPluginOnlineData, settingsManager: SettingsManager) {
|
|
||||||
if (onlineData.settings) {
|
|
||||||
settingsManager.onlineSettings = onlineData.settings;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -62,8 +62,38 @@ export default class TimeUtil {
|
|||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化日期
|
||||||
|
* 如:formatDate(new Date(), 'yyyy-MM-dd HH:mm:ss') => 2021-01-01 12:00:00
|
||||||
|
* @param date
|
||||||
|
* @param format
|
||||||
|
*/
|
||||||
|
public static formatDate(date:Date, format: string = 'yyyy-MM-dd HH:mm:ss'):string {
|
||||||
|
|
||||||
|
const year = date.getFullYear()
|
||||||
|
const month = date.getMonth() + 1
|
||||||
|
const day = date.getDate()
|
||||||
|
const hour = date.getHours()
|
||||||
|
const minute = date.getMinutes()
|
||||||
|
const second = date.getSeconds()
|
||||||
|
const formatMap: { [key: string]: any } = {
|
||||||
|
yyyy: year.toString(),
|
||||||
|
MM: month.toString().padStart(2, '0'),
|
||||||
|
dd: day.toString().padStart(2, '0'),
|
||||||
|
HH: hour.toString().padStart(2, '0'),
|
||||||
|
mm: minute.toString().padStart(2, '0'),
|
||||||
|
ss: second.toString().padStart(2, '0')
|
||||||
|
}
|
||||||
|
return format.replace(/yyyy|MM|dd|HH|mm|ss/g, (match) => formatMap[match])
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static getLastMonth() {
|
||||||
|
const date = new Date();
|
||||||
|
date.setMonth(date.getMonth() - 1);
|
||||||
|
return date;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
68
styles.css
68
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 {
|
.obsidian_douban_settings_area {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
@ -107,6 +119,62 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Add this CSS to your stylesheet */
|
||||||
|
.obsidian_douban_settings_tab_container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.obsidian_douban_settings_tab_headers {
|
||||||
|
display: flex;
|
||||||
|
/*border-bottom: 1px solid #ccc;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.obsidian_douban_settings_tab_header {
|
||||||
|
padding: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
/*border: 1px solid #ccc;*/
|
||||||
|
border-bottom: none;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.obsidian_douban_settings_tab_contents {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.obsidian_douban_settings_tab_content {
|
||||||
|
display: none;
|
||||||
|
padding: 10px;
|
||||||
|
/*border: 1px solid #ccc;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.obsidian_douban_settings_tab_header.active {
|
||||||
|
background-color: var(--plugin-primary-color);
|
||||||
|
font-weight: bold;
|
||||||
|
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: var(--plugin-primary-color);
|
||||||
|
display: block;
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid var(--plugin-secondary-color);
|
||||||
|
border-radius: 0 8px 8px 8px; /* Rounded corners for the bottom */
|
||||||
|
}
|
||||||
|
|
||||||
|
.obsidian_douban_template_file_select {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.setting-item-control.obsidian_douban_template_file_select > div.search-input-container {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -54,6 +54,7 @@
|
|||||||
"2.0.6": "0.12.0",
|
"2.0.6": "0.12.0",
|
||||||
"2.0.7": "0.12.0",
|
"2.0.7": "0.12.0",
|
||||||
"2.0.8": "0.12.0",
|
"2.0.8": "0.12.0",
|
||||||
"2.1.0": "0.12.0"
|
"2.1.0": "0.12.0",
|
||||||
|
"2.2.0": "0.12.0",
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user