add function: sync user movie info

This commit is contained in:
wanxp 2022-11-19 15:03:33 +08:00
parent ba5b9f2550
commit 0a39541b02
38 changed files with 817 additions and 218 deletions

53
main.ts

@ -1,4 +1,4 @@
import {Editor, Plugin} from "obsidian"; import {Editor, Notice, Plugin} from "obsidian";
import {DoubanFuzzySuggester} from "src/douban/data/search/DoubanSearchFuzzySuggestModal"; import {DoubanFuzzySuggester} from "src/douban/data/search/DoubanSearchFuzzySuggestModal";
import {DoubanSearchChooseItemHandler} from "src/douban/data/handler/DoubanSearchChooseItemHandler"; import {DoubanSearchChooseItemHandler} from "src/douban/data/handler/DoubanSearchChooseItemHandler";
@ -18,6 +18,9 @@ import {DEFAULT_SETTINGS} from "./src/constant/DefaultSettings";
import UserComponent from "@App/user/UserComponent"; import UserComponent from "@App/user/UserComponent";
import SettingsManager from "@App/setting/SettingsManager"; import SettingsManager from "@App/setting/SettingsManager";
import NetFileHandler from "./src/net/NetFileHandler"; import NetFileHandler from "./src/net/NetFileHandler";
import {DoubanSyncModal} from "@App/component/DoubanSyncModal";
import SyncHandler from "@App/sync/handler/SyncHandler";
import {SyncConfig} from "@App/sync/model/SyncConfig";
export default class DoubanPlugin extends Plugin { export default class DoubanPlugin extends Plugin {
public settings: DoubanPluginSetting; public settings: DoubanPluginSetting;
@ -69,7 +72,7 @@ export default class DoubanPlugin extends Plugin {
let filePath = this.settings.dataFilePath; let filePath = this.settings.dataFilePath;
filePath = filePath?filePath:DEFAULT_SETTINGS.dataFilePath; filePath = filePath?filePath:DEFAULT_SETTINGS.dataFilePath;
filePath = FileUtil.join(filePath, result.fileName); filePath = FileUtil.join(filePath, result.fileName);
this.fileHandler.createNewNoteWithData(filePath, result.content); this.fileHandler.createNewNoteWithData(filePath, result.content, context.showAfterCreate);
} }
async search(searchTerm: string, context: HandleContext) { async search(searchTerm: string, context: HandleContext) {
@ -103,6 +106,10 @@ export default class DoubanPlugin extends Plugin {
new DoubanSearchModal(this.app, this, context).open(); new DoubanSearchModal(this.app, this, context).open();
} }
async showSyncModal(context: HandleContext) {
new DoubanSyncModal(this.app, this, context).open();
}
async onload() { async onload() {
await this.loadSettings(); await this.loadSettings();
if (this.settings.statusBar) { if (this.settings.statusBar) {
@ -116,7 +123,8 @@ export default class DoubanPlugin extends Plugin {
this.getDoubanTextForCreateNewNote({mode: SearchHandleMode.FOR_CREATE, this.getDoubanTextForCreateNewNote({mode: SearchHandleMode.FOR_CREATE,
settings: this.settings, settings: this.settings,
userComponent: this.userComponent, userComponent: this.userComponent,
netFileHandler: this.netFileHandler}), netFileHandler: this.netFileHandler,
showAfterCreate:true}),
}); });
this.addCommand({ this.addCommand({
@ -141,6 +149,16 @@ export default class DoubanPlugin extends Plugin {
netFileHandler: this.netFileHandler}), netFileHandler: this.netFileHandler}),
}); });
this.addCommand({
id: "sync-douban-import-and-create-file",
name: i18nHelper.getMessage("110103"),
callback: () =>
this.showSyncModal({mode: SearchHandleMode.FOR_CREATE,
settings: this.settings,
userComponent: this.userComponent,
netFileHandler: this.netFileHandler}),
});
this.settingsManager = new SettingsManager(app, this); this.settingsManager = new SettingsManager(app, this);
this.userComponent = new UserComponent(this.settingsManager); this.userComponent = new UserComponent(this.settingsManager);
this.netFileHandler = new NetFileHandler(this.fileHandler); this.netFileHandler = new NetFileHandler(this.fileHandler);
@ -180,5 +198,34 @@ export default class DoubanPlugin extends Plugin {
} }
setTimeout(() => this.doubanStatusBar.empty(), BasicConst.CLEAN_STATUS_BAR_DELAY) setTimeout(() => this.doubanStatusBar.empty(), BasicConst.CLEAN_STATUS_BAR_DELAY)
} }
async sync(syncConfig: SyncConfig, context: HandleContext) {
try {
const result:boolean = await this.checkLogin(context);
if (!result) {
return;
}
new Notice(i18nHelper.getMessage('140301'));
this.showStatus('140203', syncConfig.syncType);
const syncHandler = new SyncHandler(this.app, this, syncConfig, context);
await syncHandler.sync();
new Notice(i18nHelper.getMessage('140302'));
} catch (e) {
log.error(i18nHelper.getMessage('140206').replace('{0}', e.message), e);
} finally {
this.clearStatusBarDelay();
}
}
private async checkLogin(context: HandleContext):Promise<boolean> {
if (!context.userComponent.needLogin()) {
await context.userComponent.loginByCookie();
}
if (!context.userComponent.isLogin()) {
new Notice(i18nHelper.getMessage('140303'));
return false;
}
return true;
}
} }

@ -6,6 +6,8 @@ import {i18nHelper} from "../lang/helper";
export const BasicConst = { export const BasicConst = {
YAML_FRONT_MATTER_SYMBOL: '---', YAML_FRONT_MATTER_SYMBOL: '---',
CLEAN_STATUS_BAR_DELAY: 5000, CLEAN_STATUS_BAR_DELAY: 5000,
CLEAN_STATUS_BAR_DELAY_RANGE: 2000,
} }
/** /**
@ -72,10 +74,25 @@ export const PersonNameModeRecords: { [key in PersonNameMode]: string } = {
} }
export enum SyncType { export enum SyncType {
MY_MOVIE= 'MY_MOVIE', movie= 'movie',
MY_BOOK= 'MY_BOOK', book= 'book',
BROADCAST= 'BROADCAST', broadcast= 'broadcast',
note= 'note',
music= 'music',
}
/**
*
*/
export const SyncTypeRecords: { [key in SyncType]: string } = {
[SyncType.movie]: i18nHelper.getMessage('504103'),
[SyncType.book]: i18nHelper.getMessage('504102'),
[SyncType.broadcast]: i18nHelper.getMessage('504104'),
[SyncType.note]: i18nHelper.getMessage('504105'),
[SyncType.music]: i18nHelper.getMessage('504105'),
} }
export const PAGE_SIZE:number = 15;

@ -7,3 +7,6 @@ export const doubanHeaders = {
}; };
export const doubanSubjectSyncListUrl = function(subjectType:string, userId:string, doType:string, start:number):string {
return `https://${subjectType}.douban.com/people/${userId}/${doType}?start=${start}&sort=time&rating=all&filter=all&mode=list`;
}

@ -2,68 +2,60 @@ import {i18nHelper} from "../lang/helper";
import {SupportType} from "./Constsant"; import {SupportType} from "./Constsant";
export enum DoubanSubjectState { export enum DoubanSubjectState {
HAVE_NOT = 'HAVE_NOT', not = 'not',
WANTED = 'WANTED', wish = 'wish',
DOING = 'DOING', do = 'do',
DONE = 'DONE', collect = 'collect',
UNKNOWN = 'UNKNOWN',
} }
export const DoubanSubjectStateRecords_ALL: { [key in DoubanSubjectState]: string } = { export const DoubanSubjectStateRecords_ALL: { [key in DoubanSubjectState]: string } = {
[DoubanSubjectState.HAVE_NOT]: i18nHelper.getMessage('500101'), [DoubanSubjectState.not]: i18nHelper.getMessage('500101'),
[DoubanSubjectState.WANTED]: i18nHelper.getMessage('500102'), [DoubanSubjectState.wish]: i18nHelper.getMessage('500102'),
[DoubanSubjectState.DOING]: i18nHelper.getMessage('500103'), [DoubanSubjectState.do]: i18nHelper.getMessage('500103'),
[DoubanSubjectState.DONE]: i18nHelper.getMessage('500104'), [DoubanSubjectState.collect]: i18nHelper.getMessage('500104'),
[DoubanSubjectState.UNKNOWN]: i18nHelper.getMessage('500000'),
} }
export const DoubanSubjectStateRecords_MOVIE: { [key in DoubanSubjectState]: string } = { export const DoubanSubjectStateRecords_MOVIE: { [key in DoubanSubjectState]: string } = {
[DoubanSubjectState.HAVE_NOT]: i18nHelper.getMessage('500201'), [DoubanSubjectState.not]: i18nHelper.getMessage('500201'),
[DoubanSubjectState.WANTED]: i18nHelper.getMessage('500202'), [DoubanSubjectState.wish]: i18nHelper.getMessage('500202'),
[DoubanSubjectState.DOING]: i18nHelper.getMessage('500203'), [DoubanSubjectState.do]: i18nHelper.getMessage('500203'),
[DoubanSubjectState.DONE]: i18nHelper.getMessage('500204'), [DoubanSubjectState.collect]: i18nHelper.getMessage('500204'),
[DoubanSubjectState.UNKNOWN]: i18nHelper.getMessage('500000'),
} }
export const DoubanSubjectStateRecords_BOOK: { [key in DoubanSubjectState]: string } = { export const DoubanSubjectStateRecords_BOOK: { [key in DoubanSubjectState]: string } = {
[DoubanSubjectState.HAVE_NOT]: i18nHelper.getMessage('500301'), [DoubanSubjectState.not]: i18nHelper.getMessage('500301'),
[DoubanSubjectState.WANTED]: i18nHelper.getMessage('500302'), [DoubanSubjectState.wish]: i18nHelper.getMessage('500302'),
[DoubanSubjectState.DOING]: i18nHelper.getMessage('500303'), [DoubanSubjectState.do]: i18nHelper.getMessage('500303'),
[DoubanSubjectState.DONE]: i18nHelper.getMessage('500304'), [DoubanSubjectState.collect]: i18nHelper.getMessage('500304'),
[DoubanSubjectState.UNKNOWN]: i18nHelper.getMessage('500000'),
} }
export const DoubanSubjectStateRecords_MUSIC: { [key in DoubanSubjectState]: string } = { export const DoubanSubjectStateRecords_MUSIC: { [key in DoubanSubjectState]: string } = {
[DoubanSubjectState.HAVE_NOT]: i18nHelper.getMessage('500401'), [DoubanSubjectState.not]: i18nHelper.getMessage('500401'),
[DoubanSubjectState.WANTED]: i18nHelper.getMessage('500402'), [DoubanSubjectState.wish]: i18nHelper.getMessage('500402'),
[DoubanSubjectState.DOING]: i18nHelper.getMessage('500403'), [DoubanSubjectState.do]: i18nHelper.getMessage('500403'),
[DoubanSubjectState.DONE]: i18nHelper.getMessage('500404'), [DoubanSubjectState.collect]: i18nHelper.getMessage('500404'),
[DoubanSubjectState.UNKNOWN]: i18nHelper.getMessage('500000'),
} }
export const DoubanSubjectStateRecords_NOTE: { [key in DoubanSubjectState]: string } = { export const DoubanSubjectStateRecords_NOTE: { [key in DoubanSubjectState]: string } = {
[DoubanSubjectState.HAVE_NOT]: i18nHelper.getMessage('500501'), [DoubanSubjectState.not]: i18nHelper.getMessage('500501'),
[DoubanSubjectState.WANTED]: i18nHelper.getMessage('500502'), [DoubanSubjectState.wish]: i18nHelper.getMessage('500502'),
[DoubanSubjectState.DOING]: i18nHelper.getMessage('500503'), [DoubanSubjectState.do]: i18nHelper.getMessage('500503'),
[DoubanSubjectState.DONE]: i18nHelper.getMessage('500504'), [DoubanSubjectState.collect]: i18nHelper.getMessage('500504'),
[DoubanSubjectState.UNKNOWN]: i18nHelper.getMessage('500000'),
} }
export const DoubanSubjectStateRecords_GAME: { [key in DoubanSubjectState]: string } = { export const DoubanSubjectStateRecords_GAME: { [key in DoubanSubjectState]: string } = {
[DoubanSubjectState.HAVE_NOT]: i18nHelper.getMessage('500601'), [DoubanSubjectState.not]: i18nHelper.getMessage('500601'),
[DoubanSubjectState.WANTED]: i18nHelper.getMessage('500602'), [DoubanSubjectState.wish]: i18nHelper.getMessage('500602'),
[DoubanSubjectState.DOING]: i18nHelper.getMessage('500603'), [DoubanSubjectState.do]: i18nHelper.getMessage('500603'),
[DoubanSubjectState.DONE]: i18nHelper.getMessage('500604'), [DoubanSubjectState.collect]: i18nHelper.getMessage('500604'),
[DoubanSubjectState.UNKNOWN]: i18nHelper.getMessage('500000'),
} }
export const DoubanSubjectStateRecords_TELEPLAY: { [key in DoubanSubjectState]: string } = { export const DoubanSubjectStateRecords_TELEPLAY: { [key in DoubanSubjectState]: string } = {
[DoubanSubjectState.HAVE_NOT]: i18nHelper.getMessage('500701'), [DoubanSubjectState.not]: i18nHelper.getMessage('500701'),
[DoubanSubjectState.WANTED]: i18nHelper.getMessage('500702'), [DoubanSubjectState.wish]: i18nHelper.getMessage('500702'),
[DoubanSubjectState.DOING]: i18nHelper.getMessage('500703'), [DoubanSubjectState.do]: i18nHelper.getMessage('500703'),
[DoubanSubjectState.DONE]: i18nHelper.getMessage('500704'), [DoubanSubjectState.collect]: i18nHelper.getMessage('500704'),
[DoubanSubjectState.UNKNOWN]: i18nHelper.getMessage('500000'),
} }
export const DoubanSubjectStateRecords: { [key in SupportType]: Record<DoubanSubjectState, string> } = { export const DoubanSubjectStateRecords: { [key in SupportType]: Record<DoubanSubjectState, string> } = {
@ -76,3 +68,37 @@ export const DoubanSubjectStateRecords: { [key in SupportType]: Record<DoubanSub
[SupportType.TELEPLAY]:DoubanSubjectStateRecords_TELEPLAY, [SupportType.TELEPLAY]:DoubanSubjectStateRecords_TELEPLAY,
} }
export const ALL:string = 'ALL';
// @ts-ignore
export const DoubanSubjectStateRecords_MOVIE_SYNC: { [key in DoubanSubjectState]: string } = {
// @ts-ignore
[ALL]: i18nHelper.getMessage('500004'),
[DoubanSubjectState.wish]: i18nHelper.getMessage('500202'),
[DoubanSubjectState.do]: i18nHelper.getMessage('500203'),
[DoubanSubjectState.collect]: i18nHelper.getMessage('500204'),
}
// @ts-ignore
export const DoubanSubjectStateRecords_BOOK_SYNC: { [key in DoubanSubjectState]: string } = {
// @ts-ignore
[ALL]: i18nHelper.getMessage('500004'),
[DoubanSubjectState.wish]: i18nHelper.getMessage('500302'),
[DoubanSubjectState.do]: i18nHelper.getMessage('500303'),
[DoubanSubjectState.collect]: i18nHelper.getMessage('500304'),
}
export const DoubanSubjectStateRecords_BROADCAST_SYNC: { [key :string]: string } = {
[ALL]: i18nHelper.getMessage('500004'),
}
export const DoubanSubjectStateRecords_NOTE_SYNC: { [key :string]: string } = {
[ALL]: i18nHelper.getMessage('500004'),
}

@ -35,7 +35,7 @@ export default class DoubanLoginModel {
const session = this.modal.webContents.session; const session = this.modal.webContents.session;
const filter = { const filter = {
urls: ['https://www.douban.com/'] urls: ['https://www.douban.com/','https://accounts.douban.com/']
}; };
session.webRequest.onSendHeaders(filter, async (details:any) => { session.webRequest.onSendHeaders(filter, async (details:any) => {
const cookies = details.requestHeaders['Cookie']; const cookies = details.requestHeaders['Cookie'];

@ -1,57 +0,0 @@
import {App, DropdownComponent, Modal, TextComponent} from "obsidian";
import DoubanPlugin from "main";
import {i18nHelper} from "src/lang/helper";
import HandleContext from "@App/data/model/HandleContext";
export class DoubanSearchModal extends Modal {
searchTerm: string;
plugin: DoubanPlugin;
context: HandleContext
constructor(app: App, plugin: DoubanPlugin, context: HandleContext) {
super(app);
this.plugin = plugin;
this.context = context;
}
onOpen() {
let {contentEl} = this;
contentEl.createEl("h3", {text: i18nHelper.getMessage('500001')});
const inputs = contentEl.createDiv("inputs");
// const syncTypeDropdown = new DropdownComponent(contentEl)
// .addOptions();
const controls = contentEl.createDiv("controls");
const searchButton = controls.createEl("button", {
text: i18nHelper.getMessage('110004'),
cls: "mod-cta",
attr: {
autofocus: true,
},
});
searchButton.addClass("obsidian_douban_search_button");
searchButton.addEventListener("click", this.close.bind(this));
const cancelButton = controls.createEl("button", {text: i18nHelper.getMessage('110005')});
cancelButton.addEventListener("click", this.close.bind(this));
cancelButton.addClass("obsidian_douban_search_button");
}
async onClose() {
let {contentEl} = this;
contentEl.empty();
if (this.searchTerm) {
await this.plugin.search(this.searchTerm, this.context);
}
}
}

@ -0,0 +1,119 @@
import {
App,
ButtonComponent,
DropdownComponent,
Modal,
SliderComponent,
TextComponent,
ToggleComponent
} from "obsidian";
import DoubanPlugin from "main";
import {i18nHelper} from "src/lang/helper";
import HandleContext from "@App/data/model/HandleContext";
import {SyncType, SyncTypeRecords} from "../../constant/Constsant";
import {
ALL,
DoubanSubjectStateRecords_BOOK_SYNC, DoubanSubjectStateRecords_BROADCAST_SYNC,
DoubanSubjectStateRecords_MOVIE_SYNC, DoubanSubjectStateRecords_NOTE_SYNC
} from "../../constant/DoubanUserState";
import {SyncConfig} from "@App/sync/model/SyncConfig";
export class DoubanSyncModal extends Modal {
plugin: DoubanPlugin;
context: HandleContext
syncConfig: SyncConfig;
constructor(app: App, plugin: DoubanPlugin, context: HandleContext) {
super(app);
this.plugin = plugin;
this.context = context;
}
onOpen() {
let {contentEl} = this;
contentEl.createEl("h3", {text: i18nHelper.getMessage('500001')});
this.syncConfig = {syncType: 'movie', scope: 'collect', force: false};
const syncTypeDropdown = new DropdownComponent(contentEl);
const scopeSelections = contentEl.createDiv("scope-selection");
syncTypeDropdown.addOptions(SyncTypeRecords)
.setValue(SyncType.movie)
.onChange((value) => {
this.syncConfig.syncType = value;
this.openScopeDropdown(scopeSelections);
});
this.openScopeDropdown(scopeSelections);
new ToggleComponent(contentEl)
.setTooltip(i18nHelper.getMessage('500110'))
.setValue(false)
.onChange((value) => {
this.syncConfig.force = value;
});
const controls = contentEl.createDiv("controls");
// const syncButton = controls.createEl("button", {
// text: i18nHelper.getMessage('110007'),
// cls: "mod-cta",
// attr: {
// autofocus: true,
// },
// });
const syncButton = new ButtonComponent(controls)
.setButtonText(i18nHelper.getMessage('110007'))
.onClick(async () => {
this.close();
await this.plugin.sync(this.syncConfig, this.context);
})
const cancelButton = new ButtonComponent(controls)
.setButtonText(i18nHelper.getMessage('110005'))
.onClick(() => {
this.close();
});
cancelButton.setClass("obsidian_douban_search_button");
syncButton.setClass("obsidian_douban_search_button");
}
async onClose() {
let {contentEl} = this;
contentEl.empty();
}
private openScopeDropdown(contentEl:HTMLDivElement) {
switch (this.syncConfig.syncType) {
case SyncType.movie:
this.showScopeDropdown(contentEl, DoubanSubjectStateRecords_MOVIE_SYNC);
break;
case SyncType.book:
this.showScopeDropdown(contentEl, DoubanSubjectStateRecords_BOOK_SYNC);
break;
case SyncType.broadcast:
this.showScopeDropdown(contentEl, DoubanSubjectStateRecords_BROADCAST_SYNC);
break;
case SyncType.note:
this.showScopeDropdown(contentEl, DoubanSubjectStateRecords_NOTE_SYNC);
break;
}
}
private showScopeDropdown(contentEl:HTMLDivElement, scopeSelections: Record<string, string>) {
contentEl.empty();
const syncScopeTypeDropdown = new DropdownComponent(contentEl)
.addOptions(scopeSelections)
.setValue(ALL)
.onChange((value) => {
this.syncConfig.scope = value;
});
}
}

@ -112,7 +112,7 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
handleSpecialContent(value: any, textMode: TemplateTextMode = TemplateTextMode.NORMAL, context: HandleContext = null): string { handleSpecialContent(value: any, textMode: TemplateTextMode = TemplateTextMode.NORMAL, context: HandleContext = null): string {
let result; let result;
if (!value) { if (!value) {
return i18nHelper.getMessage('410101'); return '';
} }
if (value instanceof Array) { if (value instanceof Array) {
result = this.handleContentArray(value, context, textMode); result = this.handleContentArray(value, context, textMode);
@ -131,8 +131,8 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
abstract support(extract: DoubanSubject): boolean; abstract support(extract: DoubanSubject): boolean;
handle(url: string, context: HandleContext): void { handle(url: string, context: HandleContext): void {
let headers = JSON.parse(this.doubanPlugin.settings.searchHeaders); let headers = JSON.parse(context.settings.searchHeaders);
headers.Cookie = this.doubanPlugin.settings.loginCookiesContent; headers.Cookie = context.settings.loginCookiesContent;
const requestUrlParam: RequestUrlParam = { const requestUrlParam: RequestUrlParam = {
url: url, url: url,
method: "GET", method: "GET",
@ -254,7 +254,7 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
.replaceAll(DoubanUserParameter.MY_RATING, this.handleSpecialContent(userState.rate, textMode)) .replaceAll(DoubanUserParameter.MY_RATING, this.handleSpecialContent(userState.rate, textMode))
.replaceAll(DoubanUserParameter.MY_STATE, this.getUserStateName(userState.state)) .replaceAll(DoubanUserParameter.MY_STATE, this.getUserStateName(userState.state))
.replaceAll(DoubanUserParameter.MY_COMMENT, this.handleSpecialContent(userState.comment, textMode)) .replaceAll(DoubanUserParameter.MY_COMMENT, this.handleSpecialContent(userState.comment, textMode))
.replaceAll(DoubanUserParameter.MY_COLLECTION_DATE, moment(new Date()).format(context.settings.dateFormat)) .replaceAll(DoubanUserParameter.MY_COLLECTION_DATE, moment(userState.collectionDate).format(context.settings.dateFormat))
} }
/** /**
@ -360,16 +360,16 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
public static getUserState(stateWord:string):DoubanSubjectState { public static getUserState(stateWord:string):DoubanSubjectState {
let state:DoubanSubjectState; let state:DoubanSubjectState;
if(!stateWord) { if(!stateWord) {
return DoubanSubjectState.UNKNOWN; return null;
} }
if(stateWord.indexOf('想')>=0 ) { if(stateWord.indexOf('想')>=0 ) {
state = DoubanSubjectState.WANTED; state = DoubanSubjectState.wish;
}else if(stateWord.indexOf('在')>=0) { }else if(stateWord.indexOf('在')>=0) {
state = DoubanSubjectState.DOING; state = DoubanSubjectState.do;
}else if(stateWord.indexOf('过')>=0) { }else if(stateWord.indexOf('过')>=0) {
state = DoubanSubjectState.DONE; state = DoubanSubjectState.collect;
}else { }else {
state = DoubanSubjectState.HAVE_NOT; state = DoubanSubjectState.not;
} }
return state; return state;
@ -377,20 +377,20 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
private getUserStateName(state: DoubanSubjectState): string { private getUserStateName(state: DoubanSubjectState): string {
if (!state) { if (!state) {
return DoubanSubjectStateRecords.ALL.UNKNOWN; return '';
} }
let v = DoubanSubjectStateRecords[this.getSupportType()]; let v = DoubanSubjectStateRecords[this.getSupportType()];
switch (state) { switch (state) {
case DoubanSubjectState.WANTED: case DoubanSubjectState.wish:
return v.WANTED; return v.wish;
case DoubanSubjectState.DOING: case DoubanSubjectState.do:
return v.DOING; return v.do;
case DoubanSubjectState.DONE: case DoubanSubjectState.collect:
return v.DONE; return v.collect;
case DoubanSubjectState.HAVE_NOT: case DoubanSubjectState.not:
return v.HAVE_NOT; return v.not;
default: default:
return v.UNKNOWN; return '';
} }
} }

@ -10,4 +10,5 @@ export default interface HandleContext {
editor?:Editor; editor?:Editor;
userComponent: UserComponent; userComponent: UserComponent;
netFileHandler: NetFileHandler; netFileHandler: NetFileHandler;
showAfterCreate?:boolean;
} }

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

@ -0,0 +1,26 @@
import {CheerioAPI} from "cheerio";
import DoubanSyncSubject from "../model/DoubanSyncSubject";
import DoubanPlugin from "../../../../main";
import {SyncType} from "../../../constant/Constsant";
import {DoubanSyncHandler} from "@App/sync/handler/DoubanSyncHandler";
import { SyncConfig } from "../model/SyncConfig";
import HandleContext from "@App/data/model/HandleContext";
export abstract class DoubanAbstractSyncHandler implements DoubanSyncHandler{
private plugin: DoubanPlugin;
constructor(plugin: DoubanPlugin) {
this.plugin = plugin;
}
support(t: string): boolean {
return this.getSyncType() == t;
}
abstract sync(syncConfig: SyncConfig, context: HandleContext): Promise<void>;
abstract getSyncType(): SyncType;
}

@ -0,0 +1,19 @@
import {CheerioAPI} from "cheerio";
import {DoubanAbstractSyncHandler} from "./DoubanAbstractSyncHandler";
import DoubanBroadcastMovieSubject from "../model/DoubanBroadcastMoveSubject";
import DoubanPlugin from "../../../../main";
import {SyncType} from "../../../constant/Constsant";
import {SyncConfig} from "@App/sync/model/SyncConfig";
import HandleContext from "@App/data/model/HandleContext";
//TODO will support in future version
export class DoubanBookSyncHandler extends DoubanAbstractSyncHandler {
getSyncType(): SyncType {
return SyncType.book;
}
async sync(syncConfig: SyncConfig, context: HandleContext): Promise<void>{
return Promise.resolve();
}
}

@ -1,12 +0,0 @@
import {CheerioAPI} from "cheerio";
import DoubanBroadcastSubject from "../model/DoubanBroadcastSubject";
export abstract class DoubanBroadcastAbstractHandler<T extends DoubanBroadcastSubject> {
abstract support(t: string): boolean;
abstract transform(data: Element, source: CheerioAPI): T;
}

@ -1,16 +0,0 @@
import {CheerioAPI} from "cheerio";
import {DoubanBroadcastAbstractHandler} from "./DoubanBroadcastAbstractHandler";
import DoubanBroadcastMovieSubject from "../model/DoubanBroadcastMoveSubject";
//TODO will support in future version
export class DoubanBroadcastMovieHandler extends DoubanBroadcastAbstractHandler<DoubanBroadcastMovieSubject> {
support(t: string): boolean {
throw new Error("Method not implemented.");
}
transform(data: Element, source: CheerioAPI): DoubanBroadcastMovieSubject {
throw new Error("Method not implemented.");
}
}

@ -0,0 +1,25 @@
import {CheerioAPI} from "cheerio";
import {DoubanAbstractSyncHandler} from "./DoubanAbstractSyncHandler";
import DoubanBroadcastMovieSubject from "../model/DoubanBroadcastMoveSubject";
import DoubanPlugin from "../../../../main";
import {SyncType} from "../../../constant/Constsant";
import {SyncConfig} from "@App/sync/model/SyncConfig";
import HandleContext from "@App/data/model/HandleContext";
//TODO will support in future version
export class DoubanBroadcastSyncHandler extends DoubanAbstractSyncHandler {
getSyncType(): SyncType {
return SyncType.broadcast;
}
support(t: string): boolean {
throw new Error("Method not implemented.");
}
async sync(syncConfig: SyncConfig, context: HandleContext): Promise<void>{
return Promise.resolve();
}
}

@ -0,0 +1,59 @@
import {DoubanAbstractSyncHandler} from "./DoubanAbstractSyncHandler";
import {SyncType} from "../../../constant/Constsant";
import {SyncConfig} from "@App/sync/model/SyncConfig";
import HandleContext from "@App/data/model/HandleContext";
import DoubanSubjectLoadHandler from "@App/data/handler/DoubanSubjectLoadHandler";
import DoubanMovieLoadHandler from "@App/data/handler/DoubanMovieLoadHandler";
import DoubanMovieSubject from "@App/data/model/DoubanMovieSubject";
import DoubanPlugin from "../../../../main";
import {SubjectListItem} from "@App/data/model/SubjectListItem";
import DoubanMovieCollectListHandler from "@App/sync/handler/list/DoubanMovieCollectListHandler";
import {DoubanListHandler} from "@App/sync/handler/list/DoubanListHandler";
import DoubanMovieWishListHandler from "./list/DoubanMovieWishListHandler";
import DoubanMovieDoListHandler from "@App/sync/handler/list/DoubanMovieDoListHandler";
//TODO will support in future version
export class DoubanMovieSyncHandler extends DoubanAbstractSyncHandler {
private doubanSubjectLoadHandler:DoubanSubjectLoadHandler<DoubanMovieSubject>;
private doubanListHandlers:DoubanListHandler[];
constructor(plugin:DoubanPlugin) {
super(plugin);
this.doubanSubjectLoadHandler = new DoubanMovieLoadHandler(plugin);
this.doubanListHandlers = [
new DoubanMovieCollectListHandler(),
new DoubanMovieWishListHandler(),
new DoubanMovieDoListHandler(),
]
}
getSyncType(): SyncType {
return SyncType.movie;
}
async sync(syncConfig: SyncConfig, context: HandleContext): Promise<void>{
Promise.resolve()
.then(() => this.getItems(syncConfig, context))
.then(this.removeExists)
.then((items) => {
items.forEach(item => {
item.id
this.doubanSubjectLoadHandler.handle(item.url, context);
})
})
}
private async getItems(syncConfig:SyncConfig, context:HandleContext):Promise<SubjectListItem[]> {
return this.doubanListHandlers.find((h) => h.support(syncConfig)).getAllPageList(context);
}
private async removeExists(items:SubjectListItem[]):Promise<SubjectListItem[]> {
return items;
}
}

@ -0,0 +1,26 @@
import {CheerioAPI} from "cheerio";
import {DoubanAbstractSyncHandler} from "./DoubanAbstractSyncHandler";
import DoubanBroadcastMovieSubject from "../model/DoubanBroadcastMoveSubject";
import DoubanPlugin from "../../../../main";
import {SyncType} from "../../../constant/Constsant";
import {SyncConfig} from "@App/sync/model/SyncConfig";
import HandleContext from "@App/data/model/HandleContext";
//TODO will support in future version
export class DoubanMusicSyncHandler extends DoubanAbstractSyncHandler {
getSyncType(): SyncType {
return SyncType.music;
}
support(t: string): boolean {
throw new Error("Method not implemented.");
}
async sync(syncConfig: SyncConfig, context: HandleContext): Promise<void>{
return Promise.resolve();
}
}

@ -0,0 +1,26 @@
import {CheerioAPI} from "cheerio";
import {DoubanAbstractSyncHandler} from "./DoubanAbstractSyncHandler";
import DoubanBroadcastMovieSubject from "../model/DoubanBroadcastMoveSubject";
import DoubanPlugin from "../../../../main";
import {SyncType} from "../../../constant/Constsant";
import {SyncConfig} from "@App/sync/model/SyncConfig";
import HandleContext from "@App/data/model/HandleContext";
//TODO will support in future version
export class DoubanNoteSyncHandler extends DoubanAbstractSyncHandler {
getSyncType(): SyncType {
return SyncType.note;
}
support(t: string): boolean {
throw new Error("Method not implemented.");
}
async sync(syncConfig: SyncConfig, context: HandleContext): Promise<void>{
return Promise.resolve();
}
}

@ -0,0 +1,28 @@
import {CheerioAPI} from "cheerio";
import {DoubanAbstractSyncHandler} from "./DoubanAbstractSyncHandler";
import DoubanBroadcastMovieSubject from "../model/DoubanBroadcastMoveSubject";
import DoubanPlugin from "../../../../main";
import {SyncType} from "../../../constant/Constsant";
import {SyncConfig} from "@App/sync/model/SyncConfig";
import HandleContext from "@App/data/model/HandleContext";
//TODO will support in future version
export class DoubanOtherSyncHandler extends DoubanAbstractSyncHandler {
getSyncType(): SyncType {
throw new Error("暂不支持同步这类型的数据");
}
support(t: string): boolean {
throw new Error("Method not implemented.");
}
async sync(syncConfig: SyncConfig, context: HandleContext): Promise<void>{
return Promise.resolve();
}
}

@ -1,32 +0,0 @@
import {CheerioAPI} from "cheerio";
import {DoubanBroadcastAbstractHandler} from "./DoubanBroadcastAbstractHandler";
import {DoubanBroadcastMovieHandler} from "./DoubanBroadcastMovieHandler";
import DoubanBroadcastSubject from "../model/DoubanBroadcastSubject";
import DoubanPageBroadcastSubject from "../model/DoubanPageBroadcastSubject";
//TODO will support in future version
export class DoubanPageBroadcastTransformer {
private handlers: DoubanBroadcastAbstractHandler<DoubanBroadcastSubject>[];
constructor() {
this.handlers = [
new DoubanBroadcastMovieHandler(),
]
}
public transform(data: CheerioAPI): DoubanPageBroadcastSubject {
let doubanBroadcastSubjects: DoubanBroadcastSubject[] = data('.new-status .status-wrapper')
.get()
.map(i => this.transformElement(i, data));
return new DoubanPageBroadcastSubject();
}
public transformElement(element: any, source: CheerioAPI): DoubanBroadcastSubject {
let targetType: string = element.innerHTML;
return this.handlers.filter(h => h.support(targetType))[0].transform(element, source);
}
}

@ -0,0 +1,14 @@
import {CheerioAPI} from "cheerio";
import DoubanSyncSubject from "../model/DoubanSyncSubject";
import {SyncConfig} from "@App/sync/model/SyncConfig";
import HandleContext from "@App/data/model/HandleContext";
export interface DoubanSyncHandler {
support(t: string): boolean;
sync(syncConfig: SyncConfig, context: HandleContext):Promise<void> ;
}

@ -0,0 +1,58 @@
import HandleContext from "@App/data/model/HandleContext";
import {SyncConfig} from "@App/sync/model/SyncConfig";
import DoubanPlugin from "main";
import {App} from "obsidian";
import {DoubanSyncHandler} from "@App/sync/handler/DoubanSyncHandler";
import DoubanOtherLoadHandler from "@App/data/handler/DoubanOtherLoadHandler";
import DoubanMovieLoadHandler from "@App/data/handler/DoubanMovieLoadHandler";
import DoubanBookLoadHandler from "@App/data/handler/DoubanBookLoadHandler";
import {DoubanTeleplayLoadHandler} from "@App/data/handler/DoubanTeleplayLoadHandler";
import DoubanMusicLoadHandler from "@App/data/handler/DoubanMusicLoadHandler";
import DoubanNoteLoadHandler from "@App/data/handler/DoubanNoteLoadHandler";
import DoubanGameLoadHandler from "@App/data/handler/DoubanGameLoadHandler";
import { DoubanBroadcastSyncHandler } from "./DoubanBroadcastSyncHandler";
import {DoubanOtherSyncHandler} from "@App/sync/handler/DoubanOtherSyncHandler";
import { DoubanMovieSyncHandler } from "./DoubanMovieSyncHandler";
import { DoubanNoteSyncHandler } from "./DoubanNoteSyncHandler";
import { DoubanMusicSyncHandler } from "./DoubanMusicSyncHandler";
import { DoubanBookSyncHandler } from "./DoubanBookSyncHandler";
import DoubanSubjectLoadHandler from "@App/data/handler/DoubanSubjectLoadHandler";
import DoubanSubject from "@App/data/model/DoubanSubject";
import {DoubanAbstractSyncHandler} from "@App/sync/handler/DoubanAbstractSyncHandler";
export default class SyncHandler {
private app: App;
private plugin: DoubanPlugin;
private syncConfig: SyncConfig;
private context: HandleContext;
private syncHandlers: DoubanSyncHandler[];
private defaultSyncHandler: DoubanSyncHandler;
constructor(app: App, plugin: DoubanPlugin, syncConfig: SyncConfig, context: HandleContext) {
this.app = app;
this.plugin = plugin;
this.syncConfig = syncConfig;
this.context = context;
this.defaultSyncHandler = new DoubanOtherSyncHandler(plugin);
this.syncHandlers =
[
new DoubanMovieSyncHandler(plugin),
new DoubanBookSyncHandler(plugin),
new DoubanBroadcastSyncHandler(plugin),
new DoubanNoteSyncHandler(plugin),
new DoubanMusicSyncHandler(plugin),
this.defaultSyncHandler
];
}
async sync() {
if (this.syncConfig && this.syncConfig.syncType && this.syncConfig.scope) {
let syncHandler = this.syncHandlers.find(handler => handler.support(this.syncConfig.syncType));
if (syncHandler) {
await syncHandler.sync(this.syncConfig, this.context);
} else {
await this.defaultSyncHandler.sync(this.syncConfig, this.context);
}
}
}
}

@ -0,0 +1,87 @@
import {moment, request, RequestUrlParam, TFile} from "obsidian";
import {i18nHelper} from 'src/lang/helper';
import {log} from "src/utils/Logutil";
import {CheerioAPI, load} from "cheerio";
import HandleContext from "@App/data/model/HandleContext";
import {doubanSubjectSyncListUrl} from "../../../../constant/Douban";
import {BasicConst, PAGE_SIZE} from "../../../../constant/Constsant";
import DoubanSearchResultSubject from "@App/data/model/DoubanSearchResultSubject";
import {SubjectListItem} from "@App/data/model/SubjectListItem";
import {DoubanListHandler} from "@App/sync/handler/list/DoubanListHandler";
import {SyncConfig} from "@App/sync/model/SyncConfig";
import TimeUtil from "../../../../utils/TimeUtil";
export default abstract class DoubanAbstractListHandler implements DoubanListHandler{
async getAllPageList(context: HandleContext):Promise<SubjectListItem[]>{
let all:SubjectListItem[] = [];
let pages:SubjectListItem[] = [];
let start = 0;
do {
const url:string = this.getUrl(context, start);
pages = await TimeUtil.delayRange(() => this.getPageList(url, context),
BasicConst.CLEAN_STATUS_BAR_DELAY - BasicConst.CLEAN_STATUS_BAR_DELAY_RANGE,
BasicConst.CLEAN_STATUS_BAR_DELAY - BasicConst.CLEAN_STATUS_BAR_DELAY_RANGE);
if (pages) {
all = all.concat(pages);
}
start = start + PAGE_SIZE;
} while (pages)
return all;
}
async delay(ms: number) {
}
private getUrl(context: HandleContext, start:number) {
return doubanSubjectSyncListUrl(this.getSyncType(), context.userComponent.getUserId(), this.getDoType(), start);
}
abstract getDoType():string;
abstract getSyncType():string;
async getPageList(url: string, context: HandleContext):Promise<SubjectListItem[]> {
let headers = JSON.parse(context.settings.searchHeaders);
headers.Cookie = context.settings.loginCookiesContent;
const requestUrlParam: RequestUrlParam = {
url: url,
method: "GET",
headers: headers,
throw: true
};
return request(requestUrlParam)
.then(load)
.then(data => this.parseSubjectFromHtml(data, context))
.catch(e => log
.error(
i18nHelper.getMessage('130101')
.replace('{0}', e.toString())
, e));
;
}
parseSubjectFromHtml(dataHtml: CheerioAPI, context: HandleContext):SubjectListItem[] {
return dataHtml('.item-show')
.get()
.map((i: any) => {
const item = dataHtml(i);
const linkValue:string = item.find('div.title > a').attr('href');
let idPattern = /(\d){5,10}/g;
let ececResult = idPattern.exec(linkValue);
return ececResult?{id: ececResult[0], url: linkValue}:null;
// return linkValue;
})
}
support(config: SyncConfig): boolean {
return this.getDoType() == config.scope;
}
}

@ -0,0 +1,10 @@
import HandleContext from "@App/data/model/HandleContext";
import {SubjectListItem} from "@App/data/model/SubjectListItem";
import {SyncConfig} from "@App/sync/model/SyncConfig";
export interface DoubanListHandler {
getAllPageList(context: HandleContext):Promise<SubjectListItem[]>;
support(config:SyncConfig):boolean;
}

@ -0,0 +1,10 @@
import { DoubanSubjectState} from "src/constant/DoubanUserState";
import { DoubanMovieListHandler } from "./DoubanMovieListHandler";
export default class DoubanMovieCollectListHandler extends DoubanMovieListHandler{
getDoType(): string {
return DoubanSubjectState.collect;
}
}

@ -0,0 +1,10 @@
import { DoubanSubjectState} from "src/constant/DoubanUserState";
import { DoubanMovieListHandler } from "./DoubanMovieListHandler";
export default class DoubanMovieDoListHandler extends DoubanMovieListHandler{
getDoType(): string {
return DoubanSubjectState.do;
}
}

@ -0,0 +1,13 @@
import DoubanAbstractListHandler from "@App/sync/handler/list/DoubanAbstractListHandler";
import { SyncType} from "../../../../constant/Constsant";
export abstract class DoubanMovieListHandler extends DoubanAbstractListHandler {
getSyncType(): string {
return SyncType.movie;
}
abstract getDoType(): string;
}

@ -0,0 +1,10 @@
import { DoubanSubjectState} from "src/constant/DoubanUserState";
import { DoubanMovieListHandler } from "./DoubanMovieListHandler";
export default class DoubanMovieWishListHandler extends DoubanMovieListHandler{
getDoType(): string {
return DoubanSubjectState.wish;
}
}

@ -1,4 +1,4 @@
import DoubanBroadcastSubject from "./DoubanBroadcastSubject"; import DoubanSyncSubject from "./DoubanSyncSubject";
export default class DoubanBroadcastMovieSubject extends DoubanBroadcastSubject { export default class DoubanBroadcastMovieSubject extends DoubanSyncSubject {
} }

@ -0,0 +1,12 @@
export default class DoubanBroadcastSubject1 {
id: string;
type: string;
title: string;
desc: string;
url: string;
author: string;
authorUrl: string;
timePublished: Date;
image: string;
content: string;
}

@ -1,4 +1,4 @@
export default class DoubanBroadcastSubject { export default class DoubanSyncSubject {
id: string; id: string;
type: string; type: string;
title: string; title: string;

@ -0,0 +1,5 @@
export interface SyncConfig {
syncType: string,
scope: string,
force:boolean,
}

@ -23,6 +23,10 @@ export default class UserComponent {
return this.user; return this.user;
} }
getUserId() {
return this.user?this.user.id:null;
}
isLogin() { isLogin() {
return this.user && this.user.login; return this.user && this.user.login;

@ -112,7 +112,7 @@ export default class FileHandler {
* A new markdown file will be created at the given file path (`input`) * A new markdown file will be created at the given file path (`input`)
* in the specified parent folder (`this.folder`) * in the specified parent folder (`this.folder`)
*/ */
async createNewNoteWithData(originalFilePath: string, data:string): Promise<void> { async createNewNoteWithData(originalFilePath: string, data:string, showAfterCreate:boolean=false): Promise<void> {
const {vault} = this._app; const {vault} = this._app;
const {adapter} = vault; const {adapter} = vault;
const prependDirInput = FileUtil.join("", originalFilePath); const prependDirInput = FileUtil.join("", originalFilePath);
@ -131,8 +131,10 @@ export default class FileHandler {
} }
const File = await vault.create(filePath, data); const File = await vault.create(filePath, data);
// Create the file and open it in the active leaf // Create the file and open it in the active leaf
const leaf = this._app.workspace.splitLeafOrActive(); if (showAfterCreate) {
await leaf.openFile(File); const leaf = this._app.workspace.splitLeafOrActive();
await leaf.openFile(File);
}
} catch (error) { } catch (error) {
log.error(error.toString(), error); log.error(error.toString(), error);
} }

@ -10,6 +10,8 @@ export default {
'110101': 'search douban and create file', '110101': 'search douban and create file',
'110201': `{0} already exists`, '110201': `{0} already exists`,
'110202': `{0} template can not read`, '110202': `{0} template can not read`,
'110103': 'sync personal data from douban',
'110007': `Start Sync`,
@ -166,6 +168,9 @@ export default {
'140204': `[Obsidian Douban]: replace '{0}'`, '140204': `[Obsidian Douban]: replace '{0}'`,
'140205': `[Obsidian Douban]: complete '{0}'`, '140205': `[Obsidian Douban]: complete '{0}'`,
'140206': `[Obsidian Douban]: occur error '{0}'`, '140206': `[Obsidian Douban]: occur error '{0}'`,
'140301': `Douban: Syncing...`,
'140303': `Douban: User Info Expire, Please login again`,
'140302': `Douban: Sync complete`,
'150101': `Choose an item...`, '150101': `Choose an item...`,
@ -361,40 +366,43 @@ export default {
'500000': `UNKNOWN`, '500000': `UNKNOWN`,
'500101': `NOT`, '500101': `not`,
'500102': `WANTED`, '500102': `wish`,
'500103': `DOING`, '500103': `do`,
'500104': `DONE`, '500104': `collect`,
'500201': `NOT`, '500201': `not`,
'500202': `WANTED`, '500202': `wish`,
'500203': `DOING`, '500203': `do`,
'500204': `DONE`, '500204': `collect`,
'500301': `NOT`, '500301': `not`,
'500302': `WANTED`, '500302': `wish`,
'500303': `DOING`, '500303': `do`,
'500304': `DONE`, '500304': `collect`,
'500401': `NOT`, '500401': `not`,
'500402': `WANTED`, '500402': `wish`,
'500403': `DOING`, '500403': `do`,
'500404': `DONE`, '500404': `collect`,
'500501': `NOT`, '500501': `not`,
'500502': `WANTED`, '500502': `wish`,
'500503': `DOING`, '500503': `do`,
'500504': `DONE`, '500504': `collect`,
'500601': `NOT`, '500601': `not`,
'500602': `WANTED`, '500602': `wish`,
'500603': `DOING`, '500603': `do`,
'500604': `DONE`, '500604': `collect`,
'500701': `not`,
'500702': `wish`,
'500703': `do`,
'500704': `collect`,
'500004': `ALL`,
'500701': `NOT`,
'500702': `WANTED`,
'500703': `DOING`,
'500704': `DONE`,
'160225': `You can use those variables in your template after login. `, '160225': `You can use those variables in your template after login. `,
'160226': `The tags that I tag for subject`, '160226': `The tags that I tag for subject`,
@ -405,6 +413,13 @@ export default {
'500001': `Sync Config`, '500001': `Sync Config`,
'504102': `My Book`,
'504103': `My Movie`,
'504104': `My Broadcast`,
'504105': `My Note`,
'504106': `My Music`,
'500110': `Replace exists or not`,
'ALL': `all`, 'ALL': `all`,

@ -9,6 +9,9 @@ export default {
'110005': `取消`, '110005': `取消`,
'110006': `同步豆瓣广播至Obsidian`, '110006': `同步豆瓣广播至Obsidian`,
'110101': '搜索豆瓣并创建文档', '110101': '搜索豆瓣并创建文档',
'110103': '同步豆瓣个人记录',
'110007': `开始同步`,
'110201': `{0} 文件已经存在.`, '110201': `{0} 文件已经存在.`,
'110202': `{0} 模板文件无法读取`, '110202': `{0} 模板文件无法读取`,
@ -170,6 +173,11 @@ export default {
'140205': `[Obsidian Douban]: 处理完成'{0}'`, '140205': `[Obsidian Douban]: 处理完成'{0}'`,
'140206': `[Obsidian Douban]: 出现错误'{0}'`, '140206': `[Obsidian Douban]: 出现错误'{0}'`,
'140301': `Douban: 开始同步...`,
'140302': `Douban: 同步完成`,
'140303': `Douban: 用户信息已过期,请至插件中重新登录`,
'150101': `选择一项内容...`, '150101': `选择一项内容...`,
'121902': `重置为默认值`, '121902': `重置为默认值`,
@ -418,6 +426,10 @@ export default {
'500703': `在看`, '500703': `在看`,
'500704': `看过`, '500704': `看过`,
'500004': `所有`,
'500110': `强制更新所有, 如果未启用则只增量更新新增的部分`,
'160225': `以下参数登录后方可在模板中使用, 使用时请用'{{}}'包裹, 举例: 参数myTags, 则使用时为{{myTags}}`, '160225': `以下参数登录后方可在模板中使用, 使用时请用'{{}}'包裹, 举例: 参数myTags, 则使用时为{{myTags}}`,
'160226': `我标记的标签`, '160226': `我标记的标签`,
@ -427,7 +439,10 @@ export default {
'160230': `我的评论/标记的日期`, '160230': `我的评论/标记的日期`,
'500001': `同步设置`, '500001': `同步设置`,
'504102': `我的书籍`,
'504103': `我的电影`,
'504104': `我的广播`,
'504105': `我的日记`,
'ALL': `全部类型`, 'ALL': `全部类型`,
'MOVIE': `电影`, 'MOVIE': `电影`,

12
src/utils/NumberUtil.ts Normal file

@ -0,0 +1,12 @@
export default class NumberUtil {
/**
*
* @Min
* @Max
*/
public static getRandomNum(min:number, max:number):number {
const range = max - min;
const rand = Math.random();
return (min + Math.round(rand * range));
}
}

13
src/utils/TimeUtil.ts Normal file

@ -0,0 +1,13 @@
import NumberUtil from "./NumberUtil";
export default class TimeUtil {
public static async delay(callback: Function, ms: number):Promise<any> {
return await new Promise(resolve => setTimeout(() => callback, ms));
}
public static async delayRange(callback: Function, msMin: number, msMax:number):Promise<any> {
return await new Promise(resolve => setTimeout(() => callback, NumberUtil.getRandomNum(msMin, msMax)));
}
}