mirror of
https://github.com/Wanxp/obsidian-douban.git
synced 2026-04-04 08:38:41 +08:00
feature: search next page
This commit is contained in:
parent
29db644ac1
commit
e19fbc648c
@ -1,4 +1,5 @@
|
||||
import {i18nHelper} from "../lang/helper";
|
||||
import DoubanSearchResultSubject from "../douban/data/model/DoubanSearchResultSubject";
|
||||
|
||||
/**
|
||||
* 常量池
|
||||
@ -162,6 +163,58 @@ export enum SyncItemStatus {
|
||||
fail= 'fail',
|
||||
unHandle='unHandle',
|
||||
}
|
||||
export enum NavigateType {
|
||||
previous = "previous",
|
||||
next = "next",
|
||||
|
||||
nextNeedLogin = "nextNeedLogin"
|
||||
}
|
||||
|
||||
export const DoubanSearchResultSubjectPreviousPage:DoubanSearchResultSubject = {
|
||||
cast: "",
|
||||
datePublished: undefined,
|
||||
desc: "",
|
||||
genre: [],
|
||||
id: "",
|
||||
image: "",
|
||||
publisher: "",
|
||||
score: 0,
|
||||
title: i18nHelper.getMessage("150102"),
|
||||
type: "navigate",
|
||||
url: NavigateType.previous
|
||||
}
|
||||
|
||||
export const DoubanSearchResultSubjectNextPage:DoubanSearchResultSubject = {
|
||||
cast: "",
|
||||
datePublished: undefined,
|
||||
desc: "",
|
||||
genre: [],
|
||||
id: "",
|
||||
image: "",
|
||||
publisher: "",
|
||||
score: 0,
|
||||
title: i18nHelper.getMessage("150103"),
|
||||
type: "navigate",
|
||||
url: NavigateType.next
|
||||
}
|
||||
|
||||
export const DoubanSearchResultSubjectNextPageNeedLogin:DoubanSearchResultSubject = {
|
||||
cast: "",
|
||||
datePublished: undefined,
|
||||
desc: "",
|
||||
genre: [],
|
||||
id: "",
|
||||
image: "",
|
||||
publisher: "",
|
||||
score: 0,
|
||||
title: i18nHelper.getMessage("150104"),
|
||||
type: "navigate",
|
||||
url: NavigateType.nextNeedLogin
|
||||
}
|
||||
|
||||
export const SEARCH_ITEM_PAGE_SIZE:number = 20;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -8,6 +8,8 @@ import SyncStatusHolder from "../../sync/model/SyncStatusHolder";
|
||||
import {SyncConfig} from "../../sync/model/SyncConfig";
|
||||
import DoubanSubject from "./DoubanSubject";
|
||||
import GlobalStatusHolder from "../../model/GlobalStatusHolder";
|
||||
import {SearchResultsPage} from "schema-dts";
|
||||
import {SearchPageInfo} from "./SearchPageInfo";
|
||||
|
||||
export default interface HandleContext {
|
||||
plugin:DoubanPlugin;
|
||||
@ -21,4 +23,6 @@ export default interface HandleContext {
|
||||
action:string;
|
||||
syncConfig?: SyncConfig;
|
||||
listItem?:DoubanSubject;
|
||||
|
||||
searchPage:SearchPageInfo;
|
||||
}
|
||||
|
||||
17
src/org/wanxp/douban/data/model/SearchPage.ts
Normal file
17
src/org/wanxp/douban/data/model/SearchPage.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import {SearchPageInfo} from "./SearchPageInfo";
|
||||
|
||||
export class SearchPage extends SearchPageInfo{
|
||||
|
||||
private _list:any[];
|
||||
|
||||
|
||||
constructor(total: number, pageNum: number, pageSize: number, hasNext: boolean, list: any[]) {
|
||||
super(total, pageNum, pageSize, hasNext);
|
||||
this._list = list;
|
||||
}
|
||||
|
||||
public get list() {
|
||||
return this._list;
|
||||
}
|
||||
|
||||
}
|
||||
58
src/org/wanxp/douban/data/model/SearchPageInfo.ts
Normal file
58
src/org/wanxp/douban/data/model/SearchPageInfo.ts
Normal file
@ -0,0 +1,58 @@
|
||||
export class SearchPageInfo {
|
||||
private _total: number;
|
||||
private _hasNext: boolean;
|
||||
private _pageSize: number;
|
||||
private _pageNum: number;
|
||||
|
||||
constructor(total: number, pageNum: number, pageSize: number, hasNext: boolean) {
|
||||
this._total = total;
|
||||
this._pageNum = pageNum;
|
||||
this._pageSize = pageSize;
|
||||
this._hasNext = hasNext;
|
||||
}
|
||||
|
||||
public nextPage(): SearchPageInfo {
|
||||
if (!this._hasNext) {
|
||||
return this;
|
||||
}
|
||||
if (((this._pageNum + 1) * this._pageSize) > this.total) {
|
||||
return this;
|
||||
}
|
||||
return new SearchPageInfo(this.total, this._pageNum + 1,
|
||||
this._pageSize, ((this._pageNum + 2) * this._pageSize) > this.total);
|
||||
}
|
||||
|
||||
public previousPage(): SearchPageInfo {
|
||||
if (this._pageNum == 0) {
|
||||
return this;
|
||||
}
|
||||
return new SearchPageInfo(this.total, this._pageNum - 1,
|
||||
this._pageSize, true);
|
||||
}
|
||||
|
||||
|
||||
public get hasNext() {
|
||||
return this._hasNext;
|
||||
}
|
||||
|
||||
public get hasPrevious() {
|
||||
return this._pageNum > 0;
|
||||
}
|
||||
|
||||
|
||||
public get start() {
|
||||
return this._pageNum * this._pageSize + 1;
|
||||
}
|
||||
|
||||
public get total() {
|
||||
return this._total;
|
||||
}
|
||||
|
||||
get pageSize(): number {
|
||||
return this._pageSize;
|
||||
}
|
||||
|
||||
get pageNum(): number {
|
||||
return this._pageNum;
|
||||
}
|
||||
}
|
||||
@ -1,10 +1,21 @@
|
||||
import {FuzzySuggestModal} from "obsidian";
|
||||
import {FuzzySuggestModal, request, RequestUrlParam} from "obsidian";
|
||||
|
||||
import DoubanPlugin from "../../../main";
|
||||
import DoubanSearchResultSubject from "../model/DoubanSearchResultSubject";
|
||||
import {log} from "src/org/wanxp/utils/Logutil";
|
||||
import {i18nHelper} from "../../../lang/helper";
|
||||
import HandleContext from "../model/HandleContext";
|
||||
import {init} from "cjs-module-lexer";
|
||||
import {
|
||||
DoubanSearchResultSubjectNextPage,
|
||||
DoubanSearchResultSubjectNextPageNeedLogin, DoubanSearchResultSubjectPreviousPage, NavigateType
|
||||
} from "../../../constant/Constsant";
|
||||
import {SearchPageInfo} from "../model/SearchPageInfo";
|
||||
import {flat} from "builtin-modules";
|
||||
import User from "../../user/User";
|
||||
import {load} from "cheerio";
|
||||
import Searcher from "./Search";
|
||||
import {SearchPage} from "../model/SearchPage";
|
||||
|
||||
export {DoubanFuzzySuggester}
|
||||
|
||||
@ -14,11 +25,13 @@ class DoubanFuzzySuggester extends FuzzySuggestModal<DoubanSearchResultSubject>
|
||||
private plugin: DoubanPlugin;
|
||||
private doubanSearchResultExtract: DoubanSearchResultSubject[];
|
||||
private context: HandleContext;
|
||||
private searchItem:string;
|
||||
|
||||
constructor(plugin: DoubanPlugin, context: HandleContext) {
|
||||
constructor(plugin: DoubanPlugin, context: HandleContext, searchItem:string) {
|
||||
super(app);
|
||||
this.plugin = plugin;
|
||||
this.context = context;
|
||||
this.searchItem = searchItem;
|
||||
this.setPlaceholder(i18nHelper.getMessage('150101'));
|
||||
}
|
||||
|
||||
@ -28,11 +41,24 @@ class DoubanFuzzySuggester extends FuzzySuggestModal<DoubanSearchResultSubject>
|
||||
}
|
||||
|
||||
getItemText(item: DoubanSearchResultSubject): string {
|
||||
if (this.isNavigate(item)) {
|
||||
return item.title;
|
||||
}
|
||||
let text: string = item.type + "/" + (item.score ? item.score : '-') + "/" + item.title + "/" + item.cast;
|
||||
return text;
|
||||
}
|
||||
|
||||
private isNavigate(item: DoubanSearchResultSubject) {
|
||||
return item.type == "navigate";
|
||||
}
|
||||
|
||||
onChooseItem(item: DoubanSearchResultSubject, evt: MouseEvent | KeyboardEvent): void {
|
||||
if(this.isNavigate(item)) {
|
||||
if (this.handleNavigate(item)) {
|
||||
this.start();
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.plugin.showStatus(i18nHelper.getMessage('140204', item.title));
|
||||
this.context.listItem = item;
|
||||
if (item) {
|
||||
@ -41,11 +67,58 @@ class DoubanFuzzySuggester extends FuzzySuggestModal<DoubanSearchResultSubject>
|
||||
this.plugin.doubanExtractHandler.handle(item, this.context);
|
||||
}
|
||||
|
||||
async handleNavigate(item: DoubanSearchResultSubject):Promise<boolean> {
|
||||
const {searchPage} = this.context;
|
||||
let currentPage:SearchPageInfo = searchPage;
|
||||
let result:boolean = false;
|
||||
switch (item.type) {
|
||||
case NavigateType.previous:
|
||||
currentPage = searchPage.previousPage();
|
||||
result = true;
|
||||
break;
|
||||
case NavigateType.next:
|
||||
currentPage = searchPage.nextPage();
|
||||
result = true;
|
||||
break;
|
||||
case NavigateType.nextNeedLogin:
|
||||
log.warn(i18nHelper.getMessage("140304"));
|
||||
break;
|
||||
}
|
||||
const searchPageResult:SearchPage = await Searcher.loadSearchItem(this.searchItem, currentPage.start, this.plugin.settings, this.plugin.settingsManager);
|
||||
this.updatePageResult(searchPageResult);
|
||||
this.context.searchPage = new SearchPageInfo(searchPageResult.total, currentPage.pageNum, searchPageResult.pageSize, searchPageResult.hasNext);
|
||||
return result;
|
||||
}
|
||||
|
||||
private updatePageResult(searchPageResult: SearchPage) {
|
||||
this.initItems(searchPageResult.list);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public showSearchList(doubanSearchResultExtractList: DoubanSearchResultSubject[]) {
|
||||
this.doubanSearchResultExtract = doubanSearchResultExtractList;
|
||||
this.initItems(doubanSearchResultExtractList);
|
||||
this.start();
|
||||
}
|
||||
|
||||
private initItems(doubanSearchResultExtractList: DoubanSearchResultSubject[]) {
|
||||
let doubanList: DoubanSearchResultSubject[] = doubanSearchResultExtractList;
|
||||
const {searchPage} = this.context;
|
||||
if (searchPage.hasNext) {
|
||||
if (this.plugin.userComponent.isLogin()) {
|
||||
doubanList.push(DoubanSearchResultSubjectNextPage)
|
||||
}else {
|
||||
doubanList.push(DoubanSearchResultSubjectNextPageNeedLogin)
|
||||
}
|
||||
}
|
||||
if (searchPage.hasPrevious) {
|
||||
doubanList.unshift(DoubanSearchResultSubjectPreviousPage);
|
||||
}
|
||||
this.doubanSearchResultExtract = doubanList;
|
||||
|
||||
}
|
||||
|
||||
public start(): void {
|
||||
try {
|
||||
this.open();
|
||||
|
||||
@ -8,6 +8,8 @@ import {load} from 'cheerio';
|
||||
import {DoubanPluginSetting} from "../../setting/model/DoubanPluginSetting";
|
||||
import {DEFAULT_SETTINGS} from "../../../constant/DefaultSettings";
|
||||
import SettingsManager from "../../setting/SettingsManager";
|
||||
import User from "../../user/User";
|
||||
import {SearchPage} from "../model/SearchPage";
|
||||
|
||||
export default class Searcher {
|
||||
static search(searchItem: string, doubanSettings: DoubanPluginSetting, settingsManager:SettingsManager): Promise<DoubanSearchResultSubject[]> {
|
||||
@ -40,4 +42,36 @@ export default class Searcher {
|
||||
;
|
||||
|
||||
};
|
||||
|
||||
static loadSearchItem(searchItem: string, start:number, doubanSettings: DoubanPluginSetting, settingsManager:SettingsManager): Promise<SearchPage> {
|
||||
const myHeaders:Record<string, string> = JSON.parse(doubanSettings.searchHeaders);
|
||||
if (doubanSettings.loginCookiesContent) {
|
||||
myHeaders.Cookie = doubanSettings.loginCookiesContent
|
||||
}
|
||||
log.debug("请求更多页面");
|
||||
let requestUrlParam: RequestUrlParam = {
|
||||
url: `https://www.douban.com/j/search?q=${searchItem}&start=${start}&subtype=item`,
|
||||
method: "GET",
|
||||
headers: myHeaders,
|
||||
throw: true
|
||||
};
|
||||
return requestUrl(requestUrlParam)
|
||||
.then(requestUrlResponse => {
|
||||
if (requestUrlResponse.status == 403) {
|
||||
throw new Error(i18nHelper.getMessage('130106'));
|
||||
}
|
||||
return requestUrlResponse.text;
|
||||
})
|
||||
.then(e=>SearchParserHandler.parseSearchJson(e, start))
|
||||
.catch(e => {
|
||||
if(e.toString().indexOf('403') > 0) {
|
||||
throw new Error(i18nHelper.getMessage('130106'));
|
||||
}else {
|
||||
throw log.error(i18nHelper.getMessage('130101').replace('{0}', e.toString()), e);
|
||||
}
|
||||
});
|
||||
;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
import {CheerioAPI} from "cheerio";
|
||||
import {CheerioAPI, load} from "cheerio";
|
||||
import DoubanSearchResultSubject from "../model/DoubanSearchResultSubject";
|
||||
import {SearchPage} from "../model/SearchPage";
|
||||
import {SEARCH_ITEM_PAGE_SIZE} from "../../../constant/Constsant";
|
||||
import {log} from "../../../utils/Logutil";
|
||||
|
||||
export default class SearchParserHandler {
|
||||
static parseSearch(dataHtml: CheerioAPI): DoubanSearchResultSubject[] {
|
||||
@ -33,4 +36,16 @@ export default class SearchParserHandler {
|
||||
return result;
|
||||
})
|
||||
};
|
||||
|
||||
static parseSearchJson(result: string, start:number): SearchPage {
|
||||
log.debug("解析给多页面结果");
|
||||
const data:{total:number, limit:number, more:boolean, items:string[]} = JSON.parse(result);
|
||||
const list:string[] = data.items;
|
||||
const resultList:DoubanSearchResultSubject[] = list
|
||||
.map(e => load(e))
|
||||
.map(e=>this.parseSearch(e))
|
||||
.map(e => e? e[0]:null);
|
||||
return new SearchPage(data.total, start / SEARCH_ITEM_PAGE_SIZE, data.limit, data.more, resultList);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@ -251,8 +251,13 @@ PS: This file could be delete if you want to.
|
||||
'140301': `Douban: Syncing[{0}]...`,
|
||||
'140303': `Douban: User Info Expire, Please login again`,
|
||||
'140302': `Douban: Sync complete`,
|
||||
'140304': `Douban: Need Login, Please login in Obsidian-Douban plugin`,
|
||||
|
||||
|
||||
'150101': `Choose an item...`,
|
||||
'150102': `[Previous Page]...`,
|
||||
'150103': `[Next Page]...`,
|
||||
'150104': `[Next Page (Please Login First)]...`,
|
||||
|
||||
|
||||
|
||||
|
||||
@ -253,9 +253,13 @@ export default {
|
||||
'140301': `Douban: 开始同步[{0}]...`,
|
||||
'140302': `Douban: 同步完成`,
|
||||
'140303': `Douban: 用户信息已过期,请至插件中重新登录`,
|
||||
'140304': `Douban: 此功能需要登录, 请先至插件中登录豆瓣`,
|
||||
|
||||
'150101': `选择一项内容...`,
|
||||
'121902': `重置为默认值`,
|
||||
'150102': `[上一页]...`,
|
||||
'150103': `[下一页]...`,
|
||||
'150104': `[下一页(插件中登录开启此功能)]...`,
|
||||
|
||||
//content
|
||||
'200101': `。`,
|
||||
|
||||
@ -22,6 +22,8 @@ import {DoubanSyncModal} from "./douban/component/DoubanSyncModal";
|
||||
import SyncHandler from "./douban/sync/handler/SyncHandler";
|
||||
import {SyncConfig} from "./douban/sync/model/SyncConfig";
|
||||
import GlobalStatusHolder from "./douban/model/GlobalStatusHolder";
|
||||
import DoubanSearchResultSubject from "./douban/data/model/DoubanSearchResultSubject";
|
||||
import {SearchPageInfo} from "./douban/data/model/SearchPageInfo";
|
||||
|
||||
export default class DoubanPlugin extends Plugin {
|
||||
public settings: DoubanPluginSetting;
|
||||
@ -111,8 +113,9 @@ export default class DoubanPlugin extends Plugin {
|
||||
async search(searchTerm: string, context: HandleContext) {
|
||||
try {
|
||||
this.showStatus(i18nHelper.getMessage('140201', searchTerm));
|
||||
const resultList = await Searcher.search(searchTerm, this.settings, context.plugin.settingsManager);
|
||||
const resultList:DoubanSearchResultSubject[] = await Searcher.search(searchTerm, this.settings, context.plugin.settingsManager);
|
||||
this.showStatus(i18nHelper.getMessage('140202', resultList.length.toString()));
|
||||
context.searchPage = new SearchPageInfo(0,0,20, true);
|
||||
new DoubanFuzzySuggester(this, context).showSearchList(resultList);
|
||||
} catch (e) {
|
||||
log.error(i18nHelper.getMessage('140206').replace('{0}', e.message), e);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user