mirror of
https://github.com/Wanxp/obsidian-douban.git
synced 2026-04-05 01:28:46 +08:00
1. fix sync movie fetch wrong type
2. fix can not get the comment of book or movie
This commit is contained in:
parent
21eea367cf
commit
5c345efa1d
@ -1,6 +1,7 @@
|
||||
import {i18nHelper} from "../lang/helper";
|
||||
import DoubanSearchResultSubject from "../douban/data/model/DoubanSearchResultSubject";
|
||||
import StringUtil from "../utils/StringUtil";
|
||||
import {DoubanPluginOnlineSettings} from "../douban/setting/model/DoubanPluginOnlineSettings";
|
||||
|
||||
/**
|
||||
* 常量池
|
||||
@ -39,19 +40,19 @@ export const BasicConst = {
|
||||
* 预估程序处理时间长度
|
||||
* @private
|
||||
*/
|
||||
export const ESTIMATE_TIME_PER:number = 2000;
|
||||
export const ESTIMATE_TIME_PER: number = 2000;
|
||||
|
||||
/**
|
||||
* 预估每次请求+处理时间长度(慢速模式)
|
||||
* @private
|
||||
*/
|
||||
export const ESTIMATE_TIME_PER_WITH_REQUEST_SLOW:number = ESTIMATE_TIME_PER + BasicConst.CALL_DOUBAN_DELAY_SLOW + BasicConst.CALL_DOUBAN_DELAY_RANGE_SLOW / 2;
|
||||
export const ESTIMATE_TIME_PER_WITH_REQUEST_SLOW: number = ESTIMATE_TIME_PER + BasicConst.CALL_DOUBAN_DELAY_SLOW + BasicConst.CALL_DOUBAN_DELAY_RANGE_SLOW / 2;
|
||||
|
||||
/**
|
||||
* 预估每次请求+处理时间长度(正常模式)
|
||||
* @private
|
||||
*/
|
||||
export const ESTIMATE_TIME_PER_WITH_REQUEST:number = ESTIMATE_TIME_PER + BasicConst.CALL_DOUBAN_DELAY + BasicConst.CALL_DOUBAN_DELAY_RANGE / 2;
|
||||
export const ESTIMATE_TIME_PER_WITH_REQUEST: number = ESTIMATE_TIME_PER + BasicConst.CALL_DOUBAN_DELAY + BasicConst.CALL_DOUBAN_DELAY_RANGE / 2;
|
||||
|
||||
/**
|
||||
* 模板类型
|
||||
@ -89,7 +90,7 @@ export enum PersonNameMode {
|
||||
*
|
||||
*/
|
||||
export enum TemplateKey {
|
||||
movieTemplateFile= 'movieTemplateFile',
|
||||
movieTemplateFile = 'movieTemplateFile',
|
||||
bookTemplateFile = 'bookTemplateFile',
|
||||
musicTemplateFile = 'musicTemplateFile',
|
||||
noteTemplateFile = 'noteTemplateFile',
|
||||
@ -98,14 +99,81 @@ export enum TemplateKey {
|
||||
}
|
||||
|
||||
export enum SupportType {
|
||||
ALL = "ALL",
|
||||
MOVIE = 'MOVIE',
|
||||
BOOK = 'BOOK',
|
||||
MUSIC = 'MUSIC',
|
||||
NOTE = 'NOTE',
|
||||
GAME = 'GAME',
|
||||
TELEPLAY = 'TELEPLAY',
|
||||
THEATER = 'THEATER',
|
||||
ALL = "All",
|
||||
MOVIE = 'movie',
|
||||
BOOK = 'book',
|
||||
MUSIC = 'music',
|
||||
NOTE = 'note',
|
||||
GAME = 'game',
|
||||
TELEPLAY = 'teleplay',
|
||||
THEATER = 'theater',
|
||||
}
|
||||
|
||||
export enum PropertyName {
|
||||
//base
|
||||
id = "id",
|
||||
title = "title",
|
||||
type = "type",
|
||||
score = "score",
|
||||
image = "image",
|
||||
imageUrl = "imageUrl",
|
||||
url = "url",
|
||||
desc = "desc",
|
||||
publisher = "publisher",
|
||||
datePublished = "datePublished",
|
||||
genre = "genre",
|
||||
|
||||
//user
|
||||
tags = "tags",
|
||||
rate = "rate",
|
||||
state = "state",
|
||||
collectionDate = "collectionDate",
|
||||
comment = "comment",
|
||||
|
||||
|
||||
//book
|
||||
author = "author",
|
||||
translator = "translator",
|
||||
isbn = "isbn",
|
||||
originalTitle = "originalTitle",
|
||||
subTitle = "subTitle",
|
||||
totalPage = "totalPage",
|
||||
series = "series",
|
||||
menu = "menu",
|
||||
price = "price",
|
||||
binding = "binding",
|
||||
producer = "producer",
|
||||
|
||||
//movie
|
||||
director = "director",
|
||||
actor = "actor",
|
||||
aggregateRating = "aggregateRating",
|
||||
aliases = "aliases",
|
||||
country = "country",
|
||||
language = "language",
|
||||
time = "time",
|
||||
IMDb = "IMDb",
|
||||
|
||||
//music
|
||||
albumType = "albumType",
|
||||
medium = "medium",
|
||||
records = "records",
|
||||
barcode = "barcode",
|
||||
|
||||
//game
|
||||
platform = "platform",
|
||||
developer = "developer",
|
||||
|
||||
|
||||
//teleplay
|
||||
episode = "episode",
|
||||
|
||||
//theater
|
||||
|
||||
|
||||
//note
|
||||
authorUrl = "authorUrl",
|
||||
content = "content",
|
||||
}
|
||||
|
||||
/**
|
||||
@ -118,11 +186,11 @@ export const PersonNameModeRecords: { [key in PersonNameMode]: string } = {
|
||||
}
|
||||
|
||||
export enum SyncType {
|
||||
movie= 'movie',
|
||||
book= 'book',
|
||||
broadcast= 'broadcast',
|
||||
note= 'note',
|
||||
music= 'music',
|
||||
movie = 'movie',
|
||||
book = 'book',
|
||||
broadcast = 'broadcast',
|
||||
note = 'note',
|
||||
music = 'music',
|
||||
}
|
||||
|
||||
/**
|
||||
@ -140,31 +208,31 @@ export const SyncTypeRecords: { [key in SyncType]: string } = {
|
||||
/**
|
||||
* 同步豆瓣每页的大小
|
||||
*/
|
||||
export const PAGE_SIZE:number = 30;
|
||||
export const PAGE_SIZE: number = 30;
|
||||
|
||||
/**
|
||||
* 多少条后同步速率变慢,防止403
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 动作
|
||||
*/
|
||||
export enum Action {
|
||||
SearchAndReplace='SearchAndReplace',
|
||||
SearchAndCrate='SearchAndCrate',
|
||||
Sync='Sync',
|
||||
SearchEditorAndReplace='SearchEditorAndReplace'
|
||||
SearchAndReplace = 'SearchAndReplace',
|
||||
SearchAndCrate = 'SearchAndCrate',
|
||||
Sync = 'Sync',
|
||||
SearchEditorAndReplace = 'SearchEditorAndReplace'
|
||||
}
|
||||
|
||||
export enum SyncItemStatus {
|
||||
exists= 'exists',
|
||||
replace= 'replace',
|
||||
create= 'create',
|
||||
fail= 'fail',
|
||||
unHandle='unHandle',
|
||||
exists = 'exists',
|
||||
replace = 'replace',
|
||||
create = 'create',
|
||||
fail = 'fail',
|
||||
unHandle = 'unHandle',
|
||||
}
|
||||
|
||||
export enum NavigateType {
|
||||
previous = "previous",
|
||||
next = "next",
|
||||
@ -172,7 +240,7 @@ export enum NavigateType {
|
||||
nextNeedLogin = "nextNeedLogin"
|
||||
}
|
||||
|
||||
export const DoubanSearchResultSubjectPreviousPage:DoubanSearchResultSubject = {
|
||||
export const DoubanSearchResultSubjectPreviousPage: DoubanSearchResultSubject = {
|
||||
cast: "",
|
||||
datePublished: undefined,
|
||||
desc: "",
|
||||
@ -187,7 +255,7 @@ export const DoubanSearchResultSubjectPreviousPage:DoubanSearchResultSubject = {
|
||||
url: NavigateType.previous
|
||||
}
|
||||
|
||||
export const DoubanSearchResultSubjectNextPage:DoubanSearchResultSubject = {
|
||||
export const DoubanSearchResultSubjectNextPage: DoubanSearchResultSubject = {
|
||||
cast: "",
|
||||
datePublished: undefined,
|
||||
desc: "",
|
||||
@ -202,7 +270,7 @@ export const DoubanSearchResultSubjectNextPage:DoubanSearchResultSubject = {
|
||||
url: NavigateType.next
|
||||
}
|
||||
|
||||
export const DoubanSearchResultSubjectNextPageNeedLogin:DoubanSearchResultSubject = {
|
||||
export const DoubanSearchResultSubjectNextPageNeedLogin: DoubanSearchResultSubject = {
|
||||
cast: "",
|
||||
datePublished: undefined,
|
||||
desc: "",
|
||||
@ -217,13 +285,13 @@ export const DoubanSearchResultSubjectNextPageNeedLogin:DoubanSearchResultSubjec
|
||||
url: NavigateType.nextNeedLogin
|
||||
}
|
||||
|
||||
export const SEARCH_ITEM_PAGE_SIZE:number = 20;
|
||||
export const SEARCH_ITEM_PAGE_SIZE: number = 20;
|
||||
|
||||
/**
|
||||
* 豆瓣默认请求头
|
||||
* @type {string}
|
||||
**/
|
||||
export const DEFAULT_DOUBAN_HEADERS = StringUtil.parseHeaders(`
|
||||
export const DEFAULT_DOUBAN_HEADERS = StringUtil.parseHeaders(`
|
||||
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
|
||||
Accept-Language: zh-CN,zh;q=0.9
|
||||
Cache-Control: max-age=0
|
||||
@ -240,6 +308,36 @@ sec-ch-ua-mobile: ?0
|
||||
sec-ch-ua-platform: "Windows"
|
||||
`)
|
||||
|
||||
/**
|
||||
* 属性设置
|
||||
*/
|
||||
export const ONLINE_SETTING_DEFAULT: DoubanPluginOnlineSettings = {
|
||||
properties: [
|
||||
{
|
||||
type: SupportType.BOOK,
|
||||
name: PropertyName.comment,
|
||||
selectors: ['#interest_sect_level > div > span:nth-child(7)'
|
||||
]
|
||||
},
|
||||
{
|
||||
type: SupportType.MOVIE,
|
||||
name: PropertyName.comment,
|
||||
selectors: ['#interest_sect_level > div > span:nth-child(8)',
|
||||
'#interest_sect_level > div > span:nth-child(7)',
|
||||
'#interest_sect_level > div > span:nth-child(9)'
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理状态
|
||||
*/
|
||||
export enum SubjectHandledStatus {
|
||||
init = 'init',
|
||||
saved = 'saved',
|
||||
syncTypeDiffAbort = 'syncTypeDiffAbort',
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -2,6 +2,8 @@ import {DoubanPluginSetting} from "../douban/setting/model/DoubanPluginSetting";
|
||||
import {PersonNameMode, SupportType} from "./Constsant";
|
||||
|
||||
export const DEFAULT_SETTINGS: DoubanPluginSetting = {
|
||||
onlineSettingsFileName: "obsidian_douban_plugin_online_settings.json",
|
||||
onlineSettingsGistId: "35693f9ece9bd6abba98f94e81afde19",
|
||||
movieTemplateFile: ``,
|
||||
bookTemplateFile: ``,
|
||||
musicTemplateFile: ``,
|
||||
@ -30,5 +32,5 @@ export const DEFAULT_SETTINGS: DoubanPluginSetting = {
|
||||
cacheImage: true,
|
||||
cacheHighQuantityImage: true,
|
||||
attachmentPath: 'assets',
|
||||
syncHandledDataArray: [],
|
||||
syncHandledDataArray: []
|
||||
}
|
||||
|
||||
@ -114,6 +114,35 @@ export const DoubanSubjectStateRecords_MUSIC_SYNC: { [key in DoubanSubjectState]
|
||||
[DoubanSubjectState.collect]: i18nHelper.getMessage('500404'),
|
||||
}
|
||||
|
||||
export const DoubanSubjectStateRecords_KEY_WORD_TYPE: Map<string, SupportType> = new Map<string, SupportType> (
|
||||
[['我看过这部电视剧', SupportType.TELEPLAY],
|
||||
['我最近看过这部电视剧', SupportType.TELEPLAY],
|
||||
['我想看这部电视剧', SupportType.TELEPLAY],
|
||||
['我在看这部电视剧', SupportType.TELEPLAY],
|
||||
['我最近在看这部电视剧', SupportType.TELEPLAY],
|
||||
|
||||
['我最近看过这部电影', SupportType.MOVIE],
|
||||
['我看过这部电影', SupportType.MOVIE],
|
||||
['我想看这部电影', SupportType.MOVIE],
|
||||
|
||||
['我读过这本书', SupportType.BOOK],
|
||||
['我想读这本书', SupportType.BOOK],
|
||||
['我在读这本书', SupportType.BOOK],
|
||||
['我最近在读这本书', SupportType.BOOK],
|
||||
|
||||
['我最近听过这张唱片', SupportType.MUSIC],
|
||||
['我听过这张唱片', SupportType.MUSIC],
|
||||
['我想听这张唱片', SupportType.MUSIC],
|
||||
['我在听这张唱片', SupportType.MUSIC],
|
||||
['我最近在听这张唱片', SupportType.MUSIC],
|
||||
|
||||
['我最近玩过这个游戏', SupportType.GAME],
|
||||
['我玩过这个游戏', SupportType.GAME],
|
||||
['我想玩这个游戏', SupportType.GAME],
|
||||
['我在玩这个游戏', SupportType.GAME],
|
||||
['我最近在玩这个游戏', SupportType.GAME],]
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -150,6 +150,7 @@ ${syncStatus.getHandle() == 0? '...' : i18nHelper.getMessage('110042') + ':' + T
|
||||
private updateContextByConfig(syncConfig: SyncConfig) {
|
||||
const { context} = this;
|
||||
context.syncConfig = syncConfig;
|
||||
context.syncActive = true;
|
||||
}
|
||||
|
||||
private showConfigPan(contentEl: HTMLElement, config:SyncConfig, disable:boolean) {
|
||||
|
||||
@ -8,7 +8,7 @@ import {CheerioAPI, load} from "cheerio";
|
||||
import YamlUtil from "../../../utils/YamlUtil";
|
||||
import {
|
||||
BasicConst,
|
||||
PersonNameMode,
|
||||
PersonNameMode, PropertyName,
|
||||
SearchHandleMode,
|
||||
SupportType,
|
||||
TemplateKey,
|
||||
@ -20,12 +20,17 @@ import {getDefaultTemplateContent} from "../../../constant/DefaultTemplateConten
|
||||
import StringUtil from "../../../utils/StringUtil";
|
||||
import {DEFAULT_SETTINGS} from "../../../constant/DefaultSettings";
|
||||
import {DoubanUserParameter, UserStateSubject} from "../model/UserStateSubject";
|
||||
import {DoubanSubjectState, DoubanSubjectStateRecords} from "../../../constant/DoubanUserState";
|
||||
import {
|
||||
DoubanSubjectState,
|
||||
DoubanSubjectStateRecords,
|
||||
DoubanSubjectStateRecords_KEY_WORD_TYPE
|
||||
} from "../../../constant/DoubanUserState";
|
||||
import DoubanLoginModel from "../../component/DoubanLoginModel";
|
||||
import DoubanHumanCheckModel from "../../component/DoubanHumanCheckModel";
|
||||
import DoubanMovieSubject from "../model/DoubanMovieSubject";
|
||||
import {Person} from "schema-dts";
|
||||
import HttpUtil from "../../../utils/HttpUtil";
|
||||
import HtmlUtil from "../../../utils/HtmlUtil";
|
||||
|
||||
export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject> implements DoubanSubjectLoadHandler<T> {
|
||||
|
||||
@ -139,15 +144,20 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
|
||||
|
||||
abstract support(extract: DoubanSubject): boolean;
|
||||
|
||||
async handle(url: string, context: HandleContext): Promise<void> {
|
||||
async handle(url: string, context: HandleContext): Promise<T> {
|
||||
context.plugin.settingsManager.debug(`开始请求地址:${url}`)
|
||||
context.plugin.settingsManager.debug(`(注意:请勿向任何人透露你的Cookie,此处若需要截图请**打码**)请求header:${context.settings.loginHeadersContent}`)
|
||||
await HttpUtil.httpRequestGet(url, context.plugin.settingsManager.getHeaders(), context.plugin.settingsManager)
|
||||
return await HttpUtil.httpRequestGet(url, context.plugin.settingsManager.getHeaders(), context.plugin.settingsManager)
|
||||
.then(load)
|
||||
.then(data => this.analysisUserState(data, context))
|
||||
.then(({data, userState}) => {
|
||||
let guessType = this.getSupportType();
|
||||
if (context.syncActive) {
|
||||
guessType = this.getGuessType(data);
|
||||
}
|
||||
let sub = this.parseSubjectFromHtml(data, context);
|
||||
sub.userState = userState;
|
||||
sub.guessType = guessType;
|
||||
return sub;
|
||||
})
|
||||
.then(content => this.toEditor(context, content))
|
||||
@ -160,11 +170,31 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
|
||||
}else {
|
||||
context.syncStatusHolder?context.syncStatusHolder.syncStatus.handled(1):null;
|
||||
}
|
||||
return e;
|
||||
});
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过判断 data中是否包含关键字符串 “我看过的电视剧” 判断是不是 movie
|
||||
* @param data
|
||||
* @private
|
||||
*/
|
||||
private getGuessType(data: CheerioAPI):SupportType {
|
||||
if (data) {
|
||||
let text = data.html();
|
||||
if (text) {
|
||||
for (let [key, value] of DoubanSubjectStateRecords_KEY_WORD_TYPE) {
|
||||
if (text.indexOf(key) >= 0) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
abstract parseSubjectFromHtml(data: CheerioAPI, context: HandleContext): T | undefined;
|
||||
|
||||
@ -501,4 +531,8 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
protected getPropertyValue(html: CheerioAPI, name: PropertyName): string {
|
||||
return HtmlUtil.getHtmlText(html, this.doubanPlugin.settingsManager.getSelector(this.getSupportType(), name));
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ import DoubanAbstractLoadHandler from "./DoubanAbstractLoadHandler";
|
||||
import DoubanBookSubject, {DoubanBookParameter} from "../model/DoubanBookSubject";
|
||||
import DoubanPlugin from "../../../main";
|
||||
import DoubanSubject from "../model/DoubanSubject";
|
||||
import {SupportType, TemplateTextMode} from "../../../constant/Constsant";
|
||||
import {PropertyName, SupportType, TemplateTextMode} from "../../../constant/Constsant";
|
||||
import HandleContext from "../model/HandleContext";
|
||||
import StringUtil from "../../../utils/StringUtil";
|
||||
import {UserStateSubject} from "../model/UserStateSubject";
|
||||
@ -57,7 +57,7 @@ export default class DoubanBookLoadHandler extends DoubanAbstractLoadHandler<Dou
|
||||
let stateWord = html('div#interest_sect_level > div.a_stars > span.mr10').text().trim();
|
||||
let collectionDateStr = html('div#interest_sect_level > div.a_stars > span.mr10').next().text().trim();
|
||||
let userState1 = DoubanAbstractLoadHandler.getUserState(stateWord);
|
||||
let component = html('span#rating').next().next().next().text().trim();
|
||||
let comment = this.getComment(html);
|
||||
|
||||
|
||||
const userState: UserStateSubject = {
|
||||
@ -65,7 +65,7 @@ export default class DoubanBookLoadHandler extends DoubanAbstractLoadHandler<Dou
|
||||
rate: rate?Number(rate):null,
|
||||
state: userState1,
|
||||
collectionDate: collectionDateStr?moment(collectionDateStr, 'YYYY-MM-DD').toDate():null,
|
||||
comment: component
|
||||
comment: comment
|
||||
}
|
||||
return {data: html, userState: userState};
|
||||
}
|
||||
@ -124,7 +124,7 @@ export default class DoubanBookLoadHandler extends DoubanAbstractLoadHandler<Dou
|
||||
menu: menu,
|
||||
price: valueMap.has('price') ? Number(valueMap.get('price').replace('元', '')) : null,
|
||||
id: id,
|
||||
type: "Book",
|
||||
type: this.getSupportType(),
|
||||
title: title,
|
||||
desc: desc,
|
||||
url: url,
|
||||
@ -135,10 +135,21 @@ export default class DoubanBookLoadHandler extends DoubanAbstractLoadHandler<Dou
|
||||
return result;
|
||||
}
|
||||
|
||||
private getComment(html: CheerioAPI) {
|
||||
let comment = html('span#rating').next().next().next().text().trim();
|
||||
if (comment) {
|
||||
return comment;
|
||||
}
|
||||
return this.getPropertyValue(html, PropertyName.comment);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
const BookKeyValueMap: Map<string, string> = new Map(
|
||||
[['作者', 'author'],
|
||||
['出版社:', 'publisher'],
|
||||
|
||||
@ -89,7 +89,7 @@ export default class DoubanGameLoadHandler extends DoubanAbstractLoadHandler<Dou
|
||||
|
||||
const result: DoubanGameSubject = {
|
||||
id: id,
|
||||
type: "Game",
|
||||
type: this.getSupportType(),
|
||||
title: title,
|
||||
desc: desc,
|
||||
url: url,
|
||||
|
||||
@ -6,11 +6,10 @@ import DoubanSubject from '../model/DoubanSubject';
|
||||
import DoubanMovieSubject from '../model/DoubanMovieSubject';
|
||||
import StringUtil from "../../../utils/StringUtil";
|
||||
import HandleContext from "../model/HandleContext";
|
||||
import {PersonNameMode, SupportType, TemplateKey} from "../../../constant/Constsant";
|
||||
import {PersonNameMode, PropertyName, SupportType, TemplateKey} from "../../../constant/Constsant";
|
||||
import {UserStateSubject} from "../model/UserStateSubject";
|
||||
import {moment} from "obsidian";
|
||||
import YamlUtil, {SPECIAL_CHAR_REG, TITLE_ALIASES_SPECIAL_CHAR_REG_G} from "../../../utils/YamlUtil";
|
||||
import { Person } from 'schema-dts';
|
||||
|
||||
export default class DoubanMovieLoadHandler extends DoubanAbstractLoadHandler<DoubanMovieSubject> {
|
||||
|
||||
@ -52,7 +51,7 @@ export default class DoubanMovieLoadHandler extends DoubanAbstractLoadHandler<Do
|
||||
let stateWord = html('div#interest_sect_level > div.a_stars > span.mr10').text().trim();
|
||||
let collectionDateStr = html('div#interest_sect_level > div.a_stars > span.mr10 > span.collection_date').text().trim();
|
||||
let userState1 = DoubanAbstractLoadHandler.getUserState(stateWord);
|
||||
let component = html('div#interest_sect_level > div.a_stars > span.color_gray').next().next().text().trim();
|
||||
let component = this.getComment(html, context);
|
||||
|
||||
|
||||
const userState: UserStateSubject = {
|
||||
@ -66,6 +65,14 @@ export default class DoubanMovieLoadHandler extends DoubanAbstractLoadHandler<Do
|
||||
}
|
||||
|
||||
|
||||
private getComment(html: CheerioAPI, context: HandleContext) {
|
||||
let component = html('div#interest_sect_level > div.a_stars > span.color_gray').next().next().text().trim();
|
||||
if (component) {
|
||||
return component;
|
||||
}
|
||||
return this.getPropertyValue(html, PropertyName.comment);
|
||||
}
|
||||
|
||||
parseSubjectFromHtml(html: CheerioAPI, context: HandleContext): DoubanMovieSubject {
|
||||
const movie:DoubanMovieSubject = html('script')
|
||||
.get()
|
||||
@ -83,7 +90,7 @@ export default class DoubanMovieLoadHandler extends DoubanAbstractLoadHandler<Do
|
||||
const result: DoubanMovieSubject = {
|
||||
id: id ? id[0] : '',
|
||||
title: title,
|
||||
type: 'Movie',
|
||||
type: this.getSupportType(),
|
||||
score: obj.aggregateRating ? obj.aggregateRating.ratingValue : undefined,
|
||||
originalTitle: originalTitle,
|
||||
desc: obj.description,
|
||||
|
||||
@ -92,7 +92,7 @@ export default class DoubanMusicLoadHandler extends DoubanAbstractLoadHandler<Do
|
||||
score: Number(score),
|
||||
records: valueMap.has('records') ? Number(valueMap.get('records')) : null,
|
||||
id: id ? id[0] : "",
|
||||
type: "Music",
|
||||
type: this.getSupportType(),
|
||||
title: title,
|
||||
desc: desc,
|
||||
url: url,
|
||||
|
||||
@ -57,7 +57,7 @@ export default class DoubanNoteLoadHandler extends DoubanAbstractLoadHandler<Dou
|
||||
datePublished: timePublished ? new Date(timePublished) : undefined,
|
||||
content: content ? html2markdown(content.toString()) : "",
|
||||
id: id ? id[0] : "",
|
||||
type: "Article",
|
||||
type: this.getSupportType(),
|
||||
title: title,
|
||||
desc: desc,
|
||||
url: url,
|
||||
|
||||
@ -8,7 +8,7 @@ export default interface DoubanSubjectLoadHandler<T extends DoubanSubject> {
|
||||
|
||||
support(extract: DoubanSubject): boolean;
|
||||
|
||||
handle(url: string, context: HandleContext): void;
|
||||
handle(url: string, context: HandleContext): Promise<T>;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -83,7 +83,7 @@ export class DoubanTeleplayLoadHandler extends DoubanAbstractLoadHandler<DoubanT
|
||||
|
||||
const result: DoubanTeleplaySubject = {
|
||||
id: id ? id[0] : '',
|
||||
type: 'Teleplay',
|
||||
type: this.getSupportType(),
|
||||
title: title,
|
||||
originalTitle: originalTitle,
|
||||
desc: obj.description,
|
||||
|
||||
@ -83,7 +83,7 @@ export default class DoubanTheaterLoadHandler extends DoubanAbstractLoadHandler<
|
||||
const result: DoubanMovieSubject = {
|
||||
id: id ? id[0] : '',
|
||||
title: title,
|
||||
type: 'Theater',
|
||||
type: this.getSupportType(),
|
||||
score: obj.aggregateRating ? obj.aggregateRating.ratingValue : undefined,
|
||||
originalTitle: originalTitle,
|
||||
desc: obj.description,
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import {UserStateSubject} from "./UserStateSubject";
|
||||
import {SubjectHandledStatus} from "../../../constant/Constsant";
|
||||
|
||||
export default class DoubanSubject {
|
||||
id: string;
|
||||
@ -13,6 +14,8 @@ export default class DoubanSubject {
|
||||
datePublished: Date;
|
||||
genre: string[];
|
||||
userState?: UserStateSubject;
|
||||
guessType?: string;
|
||||
handledStatus?: SubjectHandledStatus = SubjectHandledStatus.init;
|
||||
}
|
||||
|
||||
const ParameterMap: Map<string, string> = new Map([
|
||||
|
||||
@ -23,6 +23,7 @@ export default interface HandleContext {
|
||||
action:string;
|
||||
syncConfig?: SyncConfig;
|
||||
listItem?:DoubanSubject;
|
||||
syncActive?:boolean;
|
||||
|
||||
searchPage?:SearchPageInfo;
|
||||
|
||||
|
||||
@ -4,7 +4,11 @@ import DoubanPlugin from "../../main";
|
||||
import Logger from "../../utils/Logutil";
|
||||
import { DoubanPluginSetting } from "./model/DoubanPluginSetting";
|
||||
import StringUtil from "../../utils/StringUtil";
|
||||
import {DEFAULT_DOUBAN_HEADERS} from "../../constant/Constsant";
|
||||
import {DEFAULT_DOUBAN_HEADERS, ONLINE_SETTING_DEFAULT, SupportType} from "../../constant/Constsant";
|
||||
import GithubUtil from "../../utils/GithubUtil";
|
||||
import {DoubanPluginOnlineData} from "./model/DoubanPluginOnlineData";
|
||||
import {DoubanPluginOnlineSettings} from "./model/DoubanPluginOnlineSettings";
|
||||
import {DoubanPluginSubjectProperty} from "./model/DoubanPluginSubjectProperty";
|
||||
|
||||
export default class SettingsManager {
|
||||
app: App;
|
||||
@ -12,8 +16,8 @@ export default class SettingsManager {
|
||||
settings: DoubanPluginSetting;
|
||||
cleanupFns: Array<() => void> = [];
|
||||
innerLogger: Logger = new Logger();
|
||||
|
||||
cookieTemp:string;
|
||||
onlineSettings: DoubanPluginOnlineSettings;
|
||||
|
||||
constructor(app: App, plugin: DoubanPlugin) {
|
||||
this.app = app;
|
||||
@ -21,6 +25,8 @@ export default class SettingsManager {
|
||||
this.settings = plugin.settings;
|
||||
}
|
||||
|
||||
|
||||
|
||||
getSettingWithDefault(key: keyof DoubanPluginSetting) {
|
||||
|
||||
return [this.settings[key], DEFAULT_SETTINGS[key]];
|
||||
@ -75,4 +81,14 @@ export default class SettingsManager {
|
||||
return this.cookieTemp;
|
||||
}
|
||||
|
||||
getSelector(itemType: SupportType, propertyName: string):string[] {
|
||||
if (this.onlineSettings && this.onlineSettings.properties) {
|
||||
const doubanPluginSubjectProperty:DoubanPluginSubjectProperty = this.onlineSettings.properties.find(subjectProperty => subjectProperty.type === itemType && subjectProperty.name === propertyName);
|
||||
if(doubanPluginSubjectProperty) {
|
||||
return doubanPluginSubjectProperty.selectors;
|
||||
}
|
||||
}
|
||||
return ONLINE_SETTING_DEFAULT.properties.find(subjectProperty => subjectProperty.type === itemType && subjectProperty.name === propertyName).selectors;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
import {DoubanPluginSubjectProperty} from "./DoubanPluginSubjectProperty";
|
||||
import {DoubanPluginOnlineSettings} from "./DoubanPluginOnlineSettings";
|
||||
|
||||
export interface DoubanPluginOnlineData {
|
||||
settings: DoubanPluginOnlineSettings;
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
import {DoubanPluginSubjectProperty} from "./DoubanPluginSubjectProperty";
|
||||
|
||||
export interface DoubanPluginOnlineSettings {
|
||||
properties: DoubanPluginSubjectProperty[];
|
||||
}
|
||||
@ -2,6 +2,8 @@ import {CustomProperty} from "./CustomProperty";
|
||||
import {SyncHandledData} from "./SyncHandledData";
|
||||
|
||||
export interface DoubanPluginSetting {
|
||||
onlineSettingsFileName: string;
|
||||
onlineSettingsGistId: string;
|
||||
movieTemplateFile: string,
|
||||
bookTemplateFile: string,
|
||||
musicTemplateFile: string,
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
export interface DoubanPluginSubjectProperty {
|
||||
type: string;
|
||||
name: string;
|
||||
selectors: string[];
|
||||
}
|
||||
@ -1,9 +1,7 @@
|
||||
import {CheerioAPI} from "cheerio";
|
||||
import DoubanSyncSubject from "../model/DoubanSyncSubject";
|
||||
import DoubanPlugin from "../../../main";
|
||||
import {BasicConst, SyncType} from "../../../constant/Constsant";
|
||||
import {BasicConst, SubjectHandledStatus, SyncType} from "../../../constant/Constsant";
|
||||
import {DoubanSyncHandler} from "./DoubanSyncHandler";
|
||||
import { SyncConfig } from "../model/SyncConfig";
|
||||
import {SyncConfig} from "../model/SyncConfig";
|
||||
import HandleContext from "../../data/model/HandleContext";
|
||||
import {SubjectListItem} from "../../data/model/SubjectListItem";
|
||||
import {sleepRange} from "../../../utils/TimeUtil";
|
||||
@ -74,7 +72,7 @@ export abstract class DoubanAbstractSyncHandler<T extends DoubanSubject> implem
|
||||
return;
|
||||
}
|
||||
if(syncStatus.shouldSync(item.id)) {
|
||||
await this.doubanSubjectLoadHandler.handle(item.url, context);
|
||||
let subject: DoubanSubject = await this.doubanSubjectLoadHandler.handle(item.url, context);
|
||||
await sleepRange(BasicConst.CALL_DOUBAN_DELAY, BasicConst.CALL_DOUBAN_DELAY + BasicConst.CALL_DOUBAN_DELAY_RANGE);
|
||||
}else {
|
||||
syncStatus.unHandle(item.id, item.title);
|
||||
|
||||
@ -234,6 +234,7 @@ PS: This file could be delete if you want to.
|
||||
//error
|
||||
'130101': `Fetch Data Error, {0}`,
|
||||
'140101': `Not support for current type. You can add Issues at Github:Wanxp/obsidian-douban`,
|
||||
'140102': `subject type is different, will not sync this, chosen sync type is {0} but this {1} subject type is {2}`,
|
||||
'130105': `Can not use Douban this time, Please try again after 12 hour or 24 hour. Or you can reset your connection `,
|
||||
'130106': `Can not use Douban this time, Please try Login In Douban Plugin. If not working please again after 12 hour or 24 hour. Or you can reset your connection `,
|
||||
|
||||
|
||||
@ -235,6 +235,7 @@ export default {
|
||||
'130102': `Obsidian Douban插件错误提示:`,
|
||||
'130103': `Obsidian Douban插件异常提示:`,
|
||||
'140101': `当前版本暂不支持该类型导入,请升级Obsidian Douban或至github提交issuess获取帮助`,
|
||||
'140102': `同步的对象和选择对象不一致,将不会同步, 现在选择同步的类型:{0},但是获取[{1}]的类型:{2}`,
|
||||
'130105': `由于多次频繁请求数据,豆瓣当前暂时不可用. 请于12小时或24小时后再重试,或重置你的网络(如重新拨号或更换网络) `,
|
||||
'130106': `请尝试在Douban插件中登录后操作. 若还是无效果则尝试于12小时或24小时后再重试,或重置你的网络(如重新拨号或更换网络) `,
|
||||
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import {Action, BasicConst, SearchHandleMode, SyncTypeRecords} from "./constant/Constsant";
|
||||
import {Action, BasicConst, SearchHandleMode, SubjectHandledStatus, SyncTypeRecords} from "./constant/Constsant";
|
||||
import {Editor, Notice, Plugin} from "obsidian";
|
||||
|
||||
import {DEFAULT_SETTINGS} from "./constant/DefaultSettings";
|
||||
import {DoubanFuzzySuggester} from "./douban/data/search/DoubanSearchFuzzySuggestModal";
|
||||
import { DoubanPluginSetting } from "./douban/setting/model/DoubanPluginSetting";
|
||||
import {DoubanPluginSetting} from "./douban/setting/model/DoubanPluginSetting";
|
||||
import {DoubanSearchChooseItemHandler} from "./douban/data/handler/DoubanSearchChooseItemHandler";
|
||||
import {DoubanSearchModal} from "./douban/data/search/DoubanSearchModal";
|
||||
import DoubanSearchResultSubject from "./douban/data/model/DoubanSearchResultSubject";
|
||||
@ -24,6 +24,8 @@ import SyncHandler from "./douban/sync/handler/SyncHandler";
|
||||
import UserComponent from "./douban/user/UserComponent";
|
||||
import {i18nHelper} from './lang/helper';
|
||||
import {log} from "src/org/wanxp/utils/Logutil";
|
||||
import GithubUtil from "./utils/GithubUtil";
|
||||
import {DoubanPluginOnlineData} from "./douban/setting/model/DoubanPluginOnlineData";
|
||||
|
||||
export default class DoubanPlugin extends Plugin {
|
||||
public settings: DoubanPluginSetting;
|
||||
@ -34,6 +36,7 @@ export default class DoubanPlugin extends Plugin {
|
||||
public settingsManager: SettingsManager;
|
||||
public netFileHandler: NetFileHandler;
|
||||
public statusHolder: GlobalStatusHolder;
|
||||
public onlineData: DoubanPluginOnlineData;
|
||||
|
||||
|
||||
async putToObsidian(context: HandleContext, extract: DoubanSubject) {
|
||||
@ -44,6 +47,11 @@ export default class DoubanPlugin extends Plugin {
|
||||
log.warn(i18nHelper.getMessage('140101'));
|
||||
return;
|
||||
}
|
||||
if (context.syncActive && extract.guessType && extract.guessType != extract.type) {
|
||||
extract.handledStatus = SubjectHandledStatus.syncTypeDiffAbort;
|
||||
console.log(i18nHelper.getMessage('140102', extract.type, extract.title, extract.guessType));
|
||||
return;
|
||||
}
|
||||
if (Action.Sync == context.action) {
|
||||
this.showStatus(i18nHelper.getMessage('140207', syncStatus.getHasHandle(), syncStatus.getTotal(), extract.title));
|
||||
}else {
|
||||
@ -52,6 +60,7 @@ export default class DoubanPlugin extends Plugin {
|
||||
const result = await this.doubanExtractHandler.parseText(extract, context)
|
||||
if (result) {
|
||||
await this.putContentToObsidian(context, result);
|
||||
extract.handledStatus = SubjectHandledStatus.saved;
|
||||
}
|
||||
if (Action.Sync == context.action) {
|
||||
this.showStatus(i18nHelper.getMessage('140208', syncStatus.getHasHandle(), syncStatus.getTotal(), extract.title));
|
||||
@ -205,6 +214,7 @@ export default class DoubanPlugin extends Plugin {
|
||||
});
|
||||
|
||||
this.settingsManager = new SettingsManager(app, this);
|
||||
this.fetchOnlineData(this.settingsManager);
|
||||
this.userComponent = new UserComponent(this.settingsManager);
|
||||
this.netFileHandler = new NetFileHandler(this.fileHandler);
|
||||
if (this.userComponent.needLogin()) {
|
||||
@ -276,7 +286,8 @@ export default class DoubanPlugin extends Plugin {
|
||||
} finally {
|
||||
await context.plugin.statusHolder.completeSync();
|
||||
this.clearStatusBarDelay();
|
||||
}
|
||||
context.syncActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
async checkLogin(context: HandleContext):Promise<boolean> {
|
||||
@ -300,5 +311,23 @@ export default class DoubanPlugin extends Plugin {
|
||||
syncConfig.attachmentPath = syncConfig.attachmentPath ? syncConfig.attachmentPath : DEFAULT_SETTINGS.attachmentPath;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
19
src/org/wanxp/utils/GithubUtil.ts
Normal file
19
src/org/wanxp/utils/GithubUtil.ts
Normal file
@ -0,0 +1,19 @@
|
||||
export default class GithubUtil {
|
||||
|
||||
/**
|
||||
* get gists content as object
|
||||
* @param gistId
|
||||
* @param fileName
|
||||
*/
|
||||
public static async getGistsData(gistId:string, fileName:string): Promise<string> {
|
||||
const gistUrl = `https://api.github.com/gists/${gistId}`
|
||||
return fetch(gistUrl)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const files = Object.keys(data.files);
|
||||
const file = files[0];
|
||||
return data.files[file].content;
|
||||
})
|
||||
.catch(error => console.error(error));
|
||||
}
|
||||
}
|
||||
26
src/org/wanxp/utils/HtmlUtil.ts
Normal file
26
src/org/wanxp/utils/HtmlUtil.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import {CheerioAPI} from "cheerio";
|
||||
|
||||
export default class HtmlUtil {
|
||||
|
||||
/**
|
||||
* 获取html text内容
|
||||
* @param html
|
||||
* @param selector
|
||||
*/
|
||||
public static getHtmlText(html: CheerioAPI, selector: string | string[]): string {
|
||||
if (typeof selector == 'string') {
|
||||
return html(selector).text().trim();
|
||||
}else {
|
||||
let s = '', text = '';
|
||||
for (s of selector) {
|
||||
text = this.getHtmlText(html, s);
|
||||
if (text) {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -23,7 +23,7 @@ export default class HttpUtil {
|
||||
let options = {
|
||||
headers: headersInner
|
||||
}
|
||||
|
||||
settingsManager.debug(`Obsidian-Douban:从网络获取网页开始:\nurl:${url}\nheaders:${JSON.stringify(headers)}`);
|
||||
return new Promise((resolve, rejects) => {
|
||||
https.get(url, { ...options }, function (response: any) {
|
||||
let chunks: any = [],
|
||||
@ -39,6 +39,9 @@ export default class HttpUtil {
|
||||
response.on("end", function () {
|
||||
let data = Buffer.concat(chunks, size)
|
||||
let html = data.toString()
|
||||
if (settingsManager) {
|
||||
settingsManager.debug(`Obsidian-Douban:从网络获取网页完成:\nhtml:\n${html}`);
|
||||
}
|
||||
resolve(html)
|
||||
})
|
||||
})
|
||||
@ -55,7 +58,9 @@ export default class HttpUtil {
|
||||
let options = {
|
||||
headers: headers
|
||||
}
|
||||
|
||||
if (settingsManager) {
|
||||
settingsManager.debug(`Obsidian-Douban:从网络获取文件开始:\n${url}`);
|
||||
}
|
||||
return new Promise((resolve, rejects) => {
|
||||
https.get(url, { ...options }, function (response: any) {
|
||||
let chunks: any = [],
|
||||
@ -70,6 +75,9 @@ export default class HttpUtil {
|
||||
|
||||
response.on("end", function () {
|
||||
let data = Buffer.concat(chunks, size)
|
||||
if (settingsManager) {
|
||||
settingsManager.debug(`Obsidian-Douban:从网络获取文件完成:\n${url}`);
|
||||
}
|
||||
resolve(data)
|
||||
})
|
||||
})
|
||||
|
||||
Loading…
Reference in New Issue
Block a user