diff --git a/src/org/wanxp/douban/ai/handler/DoubanTheaterAiLoadHandler.ts b/src/org/wanxp/douban/ai/handler/DoubanTheaterAiLoadHandler.ts index 3d04057..64f4283 100644 --- a/src/org/wanxp/douban/ai/handler/DoubanTheaterAiLoadHandler.ts +++ b/src/org/wanxp/douban/ai/handler/DoubanTheaterAiLoadHandler.ts @@ -33,24 +33,24 @@ export default class DoubanTheaterAiLoadHandler extends DoubanAbstractLoadHandle "director", DataValueType.array, extract.director, - extract.director.map(SchemaOrg.getPersonName).filter(c => c) + (extract.director || []).map(SchemaOrg.getPersonName).filter(c => c) )); variableMap.set("actor", new DataField( "actor", DataValueType.array, extract.actor, - extract.actor.map(SchemaOrg.getPersonName).filter(c => c) + (extract.actor || []).map(SchemaOrg.getPersonName).filter(c => c) )); variableMap.set("author", new DataField( "author", DataValueType.array, extract.author, - extract.author.map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, context)).filter(c => c) + (extract.author || []).map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, context)).filter(c => c) )); variableMap.set("aliases", new DataField("aliases", DataValueType.array, extract.aliases, - extract.aliases.map(a=>a + (extract.aliases || []).map(a=>a .trim() // .replace(TITLE_ALIASES_SPECIAL_CHAR_REG_G, '_') // //replase multiple _ to single _ diff --git a/src/org/wanxp/douban/component/DoubanSyncModal.ts b/src/org/wanxp/douban/component/DoubanSyncModal.ts index 16f00a7..b58fe94 100644 --- a/src/org/wanxp/douban/component/DoubanSyncModal.ts +++ b/src/org/wanxp/douban/component/DoubanSyncModal.ts @@ -169,9 +169,6 @@ ${syncStatus.getHandle() == 0? '...' : i18nHelper.getMessage('110042') + ':' + T const syncButton = new ButtonComponent(controls) .setButtonText(i18nHelper.getMessage('110007')) .onClick(async () => { - if (!this.plugin.userComponent.isLogin()) { - await this.plugin.userComponent.login(); - } if(!await this.plugin.checkLogin(this.context)) { return; } diff --git a/src/org/wanxp/douban/data/handler/DoubanAbstractLoadHandler.ts b/src/org/wanxp/douban/data/handler/DoubanAbstractLoadHandler.ts index 10e27a4..a4ac748 100644 --- a/src/org/wanxp/douban/data/handler/DoubanAbstractLoadHandler.ts +++ b/src/org/wanxp/douban/data/handler/DoubanAbstractLoadHandler.ts @@ -142,7 +142,7 @@ export default abstract class DoubanAbstractLoadHandler }else { context.syncStatusHolder?context.syncStatusHolder.syncStatus.handled(1):null; } - return e; + return undefined; }); @@ -608,12 +608,20 @@ export default abstract class DoubanAbstractLoadHandler handlePersonNameByMeta(html: CheerioAPI, movie: DoubanSubject, context: HandleContext, metaProperty:string, objectProperty:string) { + if (!movie) { + return; + } const metaProperties: string[] = html(`head > meta[property='${metaProperty}']`).get() .map((e) => { return html(e).attr('content'); }); // @ts-ignore - movie[objectProperty] + const currentArray = movie[objectProperty]; + if (!Array.isArray(currentArray)) { + return; + } + // @ts-ignore + currentArray // @ts-ignore .filter((p:Person) => p.name) // @ts-ignore diff --git a/src/org/wanxp/douban/data/handler/DoubanBookLoadHandler.ts b/src/org/wanxp/douban/data/handler/DoubanBookLoadHandler.ts index 899ba04..64e2a36 100644 --- a/src/org/wanxp/douban/data/handler/DoubanBookLoadHandler.ts +++ b/src/org/wanxp/douban/data/handler/DoubanBookLoadHandler.ts @@ -30,9 +30,9 @@ export default class DoubanBookLoadHandler extends DoubanAbstractLoadHandler, extract: DoubanBookSubject, context: HandleContext): void { variableMap.set(DoubanBookParameter.author, new DataField(DoubanBookParameter.author, - DataValueType.array, extract.author, extract.author.map(this.handleSpecialAuthorName))); + DataValueType.array, extract.author, (extract.author || []).map(this.handleSpecialAuthorName))); variableMap.set(DoubanBookParameter.translator, new DataField(DoubanBookParameter.translator, - DataValueType.array, extract.translator, extract.translator.map(this.handleSpecialAuthorName))); + DataValueType.array, extract.translator, (extract.translator || []).map(this.handleSpecialAuthorName))); } support(extract: DoubanSubject): boolean { diff --git a/src/org/wanxp/douban/data/handler/DoubanGameLoadHandler.ts b/src/org/wanxp/douban/data/handler/DoubanGameLoadHandler.ts index ca40aed..036d334 100644 --- a/src/org/wanxp/douban/data/handler/DoubanGameLoadHandler.ts +++ b/src/org/wanxp/douban/data/handler/DoubanGameLoadHandler.ts @@ -31,7 +31,7 @@ export default class DoubanGameLoadHandler extends DoubanAbstractLoadHandler, extract: DoubanGameSubject, context: HandleContext): void { // super.parseAliases(beforeContent, variableMap, extract, context); variableMap.set("aliases", new DataField("aliases", DataValueType.array, extract.aliases, - extract.aliases.map(a=>a + (extract.aliases || []).map(a=>a .trim() // .replace(TITLE_ALIASES_SPECIAL_CHAR_REG_G, '_') // //replase multiple _ to single _ diff --git a/src/org/wanxp/douban/data/handler/DoubanMovieLoadHandler.ts b/src/org/wanxp/douban/data/handler/DoubanMovieLoadHandler.ts index 1ff1ea0..908ca42 100644 --- a/src/org/wanxp/douban/data/handler/DoubanMovieLoadHandler.ts +++ b/src/org/wanxp/douban/data/handler/DoubanMovieLoadHandler.ts @@ -35,24 +35,24 @@ export default class DoubanMovieLoadHandler extends DoubanAbstractLoadHandler c) + (extract.director || []).map(SchemaOrg.getPersonName).filter(c => c) )); variableMap.set("actor", new DataField( "actor", DataValueType.array, extract.actor, - extract.actor.map(SchemaOrg.getPersonName).filter(c => c) + (extract.actor || []).map(SchemaOrg.getPersonName).filter(c => c) )); variableMap.set("author", new DataField( "author", DataValueType.array, extract.author, - extract.author.map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, context)).filter(c => c) + (extract.author || []).map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, context)).filter(c => c) )); variableMap.set("aliases", new DataField("aliases", DataValueType.array, extract.aliases, - extract.aliases.map(a=>a + (extract.aliases || []).map(a=>a .trim() // .replace(TITLE_ALIASES_SPECIAL_CHAR_REG_G, '_') // //replase multiple _ to single _ @@ -98,7 +98,7 @@ export default class DoubanMovieLoadHandler extends DoubanAbstractLoadHandler "application/ld+json" == html(scd).attr("type")) .map(i => { @@ -108,8 +108,8 @@ export default class DoubanMovieLoadHandler extends DoubanAbstractLoadHandler meta[property='og:title']").get(0)).attr("content") || ''; + const image = html(html("head > meta[property='og:image']").get(0)).attr("content") || ''; + const urlMeta = html(html("head > meta[property='og:url']").get(0)).attr("content") || ''; + const desc = html(html("head > meta[property='og:description']").get(0)).attr("content") || ''; + + // Extract ID from URL + const idPattern = /(\d){5,10}/g; + const idMatch = idPattern.exec(urlMeta); + const id = idMatch ? idMatch[0] : ''; + + // Extract score from HTML + const scoreText = html("#interest_sectl strong[property='v:average']").text(); + const score = scoreText ? parseFloat(scoreText) : undefined; + + movie = { + id, + title, + type: this.getSupportType(), + score, + originalTitle: title, + desc, + url: urlMeta || (id ? `https://movie.douban.com/subject/${id}/` : ''), + director: [], + author: [], + actor: [], + aggregateRating: undefined, + datePublished: undefined, + image, + imageUrl: image, + genre: [], + publisher: '', + aliases: [], + language: [], + country: [], + time: null, + IMDb: null, + }; + } + + this.handlePersonNameByMeta(html, movie, context, 'video:actor', 'actor'); + this.handlePersonNameByMeta(html, movie, context, 'video:director', 'director'); + + const desc: string = html("span[property='v:summary']").text(); if (desc) { movie.desc = desc; } @@ -156,7 +198,7 @@ export default class DoubanMovieLoadHandler extends DoubanAbstractLoadHandler v.trim()); - } else if(key.indexOf('片长') >= 0) { + } else if (key.indexOf('片长') >= 0) { value = html(info.next.next).text().trim() } else { value = html(info.next).text().trim(); @@ -164,11 +206,11 @@ export default class DoubanMovieLoadHandler extends DoubanAbstractLoadHandler, extract: DoubanTeleplaySubject, context: HandleContext): void { - variableMap.set("director", new DataField("director", DataValueType.array, extract.director,extract.director.map(SchemaOrg.getPersonName).filter(c => c))); + variableMap.set("director", new DataField("director", DataValueType.array, extract.director,(extract.director || []).map(SchemaOrg.getPersonName).filter(c => c))); variableMap.set("actor", new DataField( "actor", DataValueType.array, extract.actor, - extract.actor.map(SchemaOrg.getPersonName).filter(c => c) + (extract.actor || []).map(SchemaOrg.getPersonName).filter(c => c) )); variableMap.set("author", new DataField( "author", DataValueType.array, extract.author, - extract.author.map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, context)).filter(c => c) + (extract.author || []).map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, context)).filter(c => c) )); variableMap.set("aliases", new DataField("aliases", DataValueType.array, extract.aliases, - extract.aliases.map(a=>a + (extract.aliases || []).map(a=>a .trim() // .replace(TITLE_ALIASES_SPECIAL_CHAR_REG_G, '_') // //replase multiple _ to single _ @@ -84,7 +84,7 @@ export class DoubanTeleplayLoadHandler extends DoubanAbstractLoadHandler "application/ld+json" == html(scd).attr("type")) .map(i => { @@ -104,14 +104,14 @@ export class DoubanTeleplayLoadHandler extends DoubanAbstractLoadHandler meta[property='og:title']").get(0)).attr("content") || ''; + const image = html(html("head > meta[property='og:image']").get(0)).attr("content") || ''; + const urlMeta = html(html("head > meta[property='og:url']").get(0)).attr("content") || ''; + const desc = html(html("head > meta[property='og:description']").get(0)).attr("content") || ''; + + const idPattern = /(\d){5,10}/g; + const idMatch = idPattern.exec(urlMeta); + const id = idMatch ? idMatch[0] : ''; + + const scoreText = html("#interest_sectl strong[property='v:average']").text(); + const score = scoreText ? parseFloat(scoreText) : undefined; + + teleplay = { + id, + title, + type: this.getSupportType(), + score, + originalTitle: title, + desc, + url: urlMeta || (id ? `https://movie.douban.com/subject/${id}/` : ''), + director: [], + author: [], + actor: [], + aggregateRating: undefined, + datePublished: undefined, + image, + imageUrl: image, + genre: [], + publisher: '', + aliases: [], + language: [], + country: [], + episode: null, + time: null, + IMDb: null, + }; + } + this.handlePersonNameByMeta(html, teleplay, context, 'video:actor', 'actor'); this.handlePersonNameByMeta(html, teleplay, context, 'video:director', 'director'); const desc:string = html("span[property='v:summary']").text(); diff --git a/src/org/wanxp/douban/data/handler/DoubanTheaterLoadHandler.ts b/src/org/wanxp/douban/data/handler/DoubanTheaterLoadHandler.ts index a27f8bb..2f3a25c 100644 --- a/src/org/wanxp/douban/data/handler/DoubanTheaterLoadHandler.ts +++ b/src/org/wanxp/douban/data/handler/DoubanTheaterLoadHandler.ts @@ -33,28 +33,28 @@ export default class DoubanTheaterLoadHandler extends DoubanAbstractLoadHandler< "director", DataValueType.array, extract.director, - extract.director.map(SchemaOrg.getPersonName).filter(c => c) + (extract.director || []).map(SchemaOrg.getPersonName).filter(c => c) )); variableMap.set("actor", new DataField( "actor", DataValueType.array, extract.actor, - extract.actor.map(SchemaOrg.getPersonName).filter(c => c) + (extract.actor || []).map(SchemaOrg.getPersonName).filter(c => c) )); variableMap.set("author", new DataField( "author", DataValueType.array, extract.author, - extract.author.map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, context)).filter(c => c) + (extract.author || []).map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, context)).filter(c => c) )); variableMap.set("aliases", new DataField( "aliases", DataValueType.array, extract.aliases, - extract.aliases.map(a => a + (extract.aliases || []).map(a => a .trim() .replace(TITLE_ALIASES_SPECIAL_CHAR_REG_G, '_') //replace multiple _ to single _ diff --git a/src/org/wanxp/douban/data/search/parser/AllFirstPageSearchResultPageParser.ts b/src/org/wanxp/douban/data/search/parser/AllFirstPageSearchResultPageParser.ts index 2d9fd6e..2695130 100644 --- a/src/org/wanxp/douban/data/search/parser/AllFirstPageSearchResultPageParser.ts +++ b/src/org/wanxp/douban/data/search/parser/AllFirstPageSearchResultPageParser.ts @@ -3,8 +3,7 @@ import { } from "../../../../constant/Constsant"; import {SearchResultPageParserInterface} from "./SearchResultPageParserInterface"; import {SearchPage} from "../../model/SearchPage"; -import SearchParserHandlerV2 from "../SearchParserV2"; -import StringUtil from "../../../../utils/StringUtil"; +import SearchParserHandler from "../SearchParser"; import {log} from "../../../../utils/Logutil"; export class AllFirstPageSearchResultPageParser implements SearchResultPageParserInterface { @@ -12,22 +11,11 @@ export class AllFirstPageSearchResultPageParser implements SearchResultPageParse return pageNum == 1 && type == SupportType.all; } parse(source:string, type:SupportType, pageNum:number, pageSize:number):SearchPage { - if (!source || StringUtil.notJsonString(source)) { - //TODO 国际化 - log.notice("Obsidian-Douban:查询结果为空,无匹配结果,请尝试登录获取获取更多数据(已登录则忽略)"); - return SearchPage.empty(type); + log.debug("解析给多页面结果"); + if (!source) { + return new SearchPage(0, 0, 0, type, []); } - - const {subjects} = JSON.parse(source); - if (!subjects) { - return SearchPage.empty(type); - } - const {items} = subjects; - if (!items ||items.length == 0) { - return SearchPage.empty(type); - } - const doubanSearchResultSubjects = SearchParserHandlerV2.itemMapToSearchResult(items); - return new SearchPage(2000, pageNum, pageSize, type, doubanSearchResultSubjects); + return SearchParserHandler.parseSearchJson(source, type, pageNum); } diff --git a/src/org/wanxp/douban/data/search/parser/OtherAllPageSearchResultPageParser.ts b/src/org/wanxp/douban/data/search/parser/OtherAllPageSearchResultPageParser.ts index 4a6970a..1c276e6 100644 --- a/src/org/wanxp/douban/data/search/parser/OtherAllPageSearchResultPageParser.ts +++ b/src/org/wanxp/douban/data/search/parser/OtherAllPageSearchResultPageParser.ts @@ -2,7 +2,7 @@ import {SupportType} from "../../../../constant/Constsant"; import {SearchResultPageParserInterface} from "./SearchResultPageParserInterface"; import {log} from "../../../../utils/Logutil"; import {SearchPage} from "../../model/SearchPage"; -import SearchParserHandlerV2 from "../SearchParserV2"; +import SearchParserHandler from "../SearchParser"; export class OtherAllPageSearchResultPageParser implements SearchResultPageParserInterface { support(type:SupportType, pageNum:number):boolean { @@ -10,13 +10,10 @@ export class OtherAllPageSearchResultPageParser implements SearchResultPageParse } parse(source:string, type:SupportType, pageNum:number, pageSize:number):SearchPage { log.debug("解析给多页面结果"); - const {contents} = JSON.parse(source); - if (!contents) { + if (!source) { return new SearchPage(0, 0, 0, type, []); } - const data:{total:number, start:number, count:number, items:any[]} = contents; - const doubanSearchResultSubjects = SearchParserHandlerV2.itemMapToSearchResult(data.items); - return new SearchPage(data.total, pageNum, pageSize, type, doubanSearchResultSubjects); + return SearchParserHandler.parseSearchJson(source, type, pageNum); } } diff --git a/src/org/wanxp/douban/data/search/searcher/AllPageSearchPageFetcher.ts b/src/org/wanxp/douban/data/search/searcher/AllPageSearchPageFetcher.ts index 66dfe89..816cb66 100644 --- a/src/org/wanxp/douban/data/search/searcher/AllPageSearchPageFetcher.ts +++ b/src/org/wanxp/douban/data/search/searcher/AllPageSearchPageFetcher.ts @@ -2,8 +2,8 @@ import {AbstractSearchPageFetcher} from "./AbstractSearchPageFetcher"; import { SupportType } from "src/org/wanxp/constant/Constsant"; export class AllPageSearchPageFetcher extends AbstractSearchPageFetcher { - getUrl(keyword: string, pageNum: number, pageSize: number): string { - return `https://m.douban.com/rexxar/api/v2/search?q=${keyword}&start=${pageNum}&count=${pageSize}`; + getUrl(keyword: string, start: number, pageSize: number): string { + return `https://www.douban.com/j/search?q=${keyword}&start=${start}`; } support(type: SupportType): boolean { return type == SupportType.all; diff --git a/src/org/wanxp/douban/setting/LoginSettingsHelper.ts b/src/org/wanxp/douban/setting/LoginSettingsHelper.ts index c1a3405..768fa54 100644 --- a/src/org/wanxp/douban/setting/LoginSettingsHelper.ts +++ b/src/org/wanxp/douban/setting/LoginSettingsHelper.ts @@ -10,17 +10,17 @@ export function constructLoginUI(containerEl: HTMLElement, manager: SettingsMana // 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 { + if (userComponent.isLogin() && !userComponent.isVerified()) { + // Assumed login — verify to get user ID/name for settings display + userComponent.login() + .then(() => constructDoubanLoginSettingsUI(containerEl, manager)) + .catch(() => constructDoubanLoginSettingsUI(containerEl, manager)); + } else if (userComponent.needLogin()) { + // Has credentials but not yet logged in + userComponent.login() + .then(() => constructDoubanLoginSettingsUI(containerEl, manager)) + .catch(() => constructDoubanLoginSettingsUI(containerEl, manager)); + } else { constructDoubanLoginSettingsUI(containerEl, manager); } diff --git a/src/org/wanxp/douban/user/UserComponent.ts b/src/org/wanxp/douban/user/UserComponent.ts index 236f124..a79e6bb 100644 --- a/src/org/wanxp/douban/user/UserComponent.ts +++ b/src/org/wanxp/douban/user/UserComponent.ts @@ -15,6 +15,7 @@ import {DoubanHttpUtil} from "../../utils/DoubanHttpUtil"; export default class UserComponent { private settingsManager: SettingsManager; private user: User; + private verified: boolean = false; constructor(settingsManager: SettingsManager) { this.settingsManager = settingsManager; @@ -39,11 +40,26 @@ export default class UserComponent { this.user.login = false; } this.user = null; + this.verified = false; this.settingsManager.updateSetting('loginCookiesContent', ''); this.settingsManager.updateSetting('loginHeadersContent', ''); } + assumeLoggedIn(): void { + const headers: any = this.settingsManager.getSetting('loginHeadersContent'); + const cookies: any = this.settingsManager.getSetting('loginCookiesContent'); + if (headers || cookies) { + this.user = new User(); + this.user.login = true; + this.verified = false; + } + } + + isVerified(): boolean { + return this.verified; + } + needLogin() { @@ -68,6 +84,7 @@ export default class UserComponent { this.settingsManager.debug(`配置界面:loginCookie:豆瓣headers信息正常,${user&&user.id?'获取用户信息成功id:'+ StringUtil.confuse(user.id) + ',用户名:'+ StringUtil.confuse(user.name) :'获取用户信息失败'}`); }); if(this.user) { + this.verified = true; this.settingsManager.updateSetting('loginHeadersContent', JSON.stringify(headers)); } return this.user; @@ -139,6 +156,9 @@ export default class UserComponent { this.user = user; this.settingsManager.debug(`主界面:loginByCookie:豆瓣cookies信息正常,${user&&user.id?'获取用户信息成功id:'+ StringUtil.confuse(user.id) + ',用户名:'+ StringUtil.confuse(user.name) :'获取用户信息失败'}`); }); + if (this.user && this.user.id) { + this.verified = true; + } return this.user; } } diff --git a/src/org/wanxp/main.ts b/src/org/wanxp/main.ts index 3f8e9bf..88565b7 100644 --- a/src/org/wanxp/main.ts +++ b/src/org/wanxp/main.ts @@ -286,6 +286,7 @@ export default class DoubanPlugin extends Plugin { // this.fetchOnlineData(this.settingsManager); this.userComponent = new UserComponent(this.settingsManager); this.netFileHandler = new NetFileHandler(this.fileHandler); + this.userComponent.assumeLoggedIn(); this.settingTab = new DoubanSettingTab(this.app, this); this.addSettingTab(this.settingTab); @@ -355,11 +356,16 @@ export default class DoubanPlugin extends Plugin { async checkLogin(context: HandleContext):Promise { this.settingsManager.debug('主界面:同步时的登录状态检测'); - if (!context.userComponent.needLogin()) { - this.settingsManager.debug('主界面:同步时的登录状态检测完成: 无用户信息, 尝试获取用户信息'); - await context.userComponent.login(); + const uc = context.userComponent; + // If assumed-logged-in but not verified, verify now (sync needs real user ID) + if (uc.isLogin() && !uc.isVerified()) { + await uc.login(); } - if (!context.userComponent.isLogin()) { + // If has saved credentials but not logged in, try login + if (uc.needLogin()) { + await uc.login(); + } + if (!uc.isLogin()) { this.settingsManager.debug('主界面:同步时的登录状态检测完成: 尝试获取用户信息失败'); new Notice(i18nHelper.getMessage('140303')); return false;