Skip to content

Commit

Permalink
搜索页面->根据全部有效书源搜索书籍
Browse files Browse the repository at this point in the history
搜索页面->根据全部有效书源搜索书籍
  • Loading branch information
MaoXiaoone committed Aug 20, 2024
1 parent 114bda9 commit fa5b280
Show file tree
Hide file tree
Showing 22 changed files with 1,019 additions and 156 deletions.
2 changes: 1 addition & 1 deletion commons/colorLibrary/BuildProfile.ets
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
export const HAR_VERSION = '1.0.0';
export const BUILD_MODE_NAME = 'debug';
export const DEBUG = true;
export const TARGET_NAME = 'Legado';
export const TARGET_NAME = 'default';

/**
* BuildProfile Class is used only for compatibility purposes.
Expand Down
13 changes: 13 additions & 0 deletions entry/src/main/ets/common/constants/AppPattern.ets
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* @author 2008
* @datetime 2024/8/15 13:36
* @className: AppPattern
*/
export default class AppPattern {
static readonly paramPattern: RegExp = /(?<!\{\{)[ ,]\s*(?=\{)/g;
static readonly pattern: RegExp = /\s*,\s*(?=\{)/g;
static readonly pagePattern:RegExp = /<(.*)>/;
static readonly jsPattern: RegExp = /<js>(.*?)<\/js>|@js:(.*)/i;
static readonly EXP_PATTERN: RegExp = /\{\{([^\}]*?)\}\}/g;
static readonly imgPattern: RegExp = /<img[^>]*src="([^"]*(?:"[^>]+\\})?)"[^>]*>/g;
}
59 changes: 59 additions & 0 deletions entry/src/main/ets/common/model/SearchConfig.ets
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* @author 2008
* @datetime 2024/8/15 0:06
* @className: SearchConfig
*/
export class SearchConfig {
path: string;
method: string;
body: string;
charset: string;
url: string;
webView:boolean;

constructor(path: string, method: string, body: string, charset: string, url: string, webView:boolean) {
this.path = path;
this.method = method.toUpperCase(); // 确保方法为大写
this.body = body;
this.charset = charset??'UTF-8';
this.url = url;
this.webView = webView
}

// 替换 body 中的关键字
setKeyword(keyword: string): void {
this.body = this.body.replace('{{key}}', encodeURIComponent(keyword));
}
}

interface SearchConfigData {
method: string;
body?: string;
charset?: string;
url: string;
webView?:boolean;
}

export function parseSearchString(searchString: string): SearchConfig {
// 拆分字符串,获取路径与配置
const splitIndex = searchString.indexOf(',');
const path = searchString.substring(0, splitIndex).trim();
const configString = searchString.substring(splitIndex + 1).trim();

// 对 JSON 配置进行清理和格式化
const cleanConfigString = configString
.replace(/(\w+)\s*:/g, '"$1":') // 给键加上引号
.replace(/'/g, '"'); // 将单引号替换为双引号

// 解析 JSON 配置
const config: SearchConfigData = JSON.parse(cleanConfigString);

return new SearchConfig(
path,
config.method??'GET',
config.body??'',
config.charset??'UTF-8',
config.url??'',
config.webView??false
);
}
80 changes: 80 additions & 0 deletions entry/src/main/ets/common/model/XmlAnalysis.ets
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { SearchRule } from '../../database/entities/rule';
import { SearchBook } from '../../database/entities/SearchBook';
import { BookSource } from '../../database/entities/BookSource';
import { ExploreQuery } from '../../database/types/BookSourceType';
import axios, { AxiosError, AxiosResponse } from '@ohos/axios';
import { isNetworkUrl } from '../utils/utils';


export interface IXmlAnalysis {
baseUrl: string //搜索地址
body:string //请求内容
bookSource:BookSource//书源
variable?:string
searchUrl:string
}
interface dataRule{
body:string
rule:SearchRule
searchUrl:string
}
export class XmlAnalysisData {
baseUrl: string = '' //搜索地址
body:string = ''//请求内容
bookSource?:BookSource//书源
variable?:string
searchUrl:string = ''
constructor(xmlDate?: IXmlAnalysis) {
this.baseUrl = xmlDate?.baseUrl || ''
this.body = xmlDate?.body || ''
this.bookSource = xmlDate?.bookSource
this.variable = xmlDate?.variable
this.searchUrl = xmlDate?.searchUrl || ''
}
}
export class XmlAnalysis {
xmlDate:XmlAnalysisData = new XmlAnalysisData()
url:string = ''
source?:SearchRule
searchUrl:string = ''
init(xmlDate:XmlAnalysisData){
this.xmlDate = xmlDate
this.url = xmlDate.searchUrl
this.source = this.xmlDate.bookSource?.ruleSearch
this.searchUrl = this.xmlDate.searchUrl
}

async getBookList(): Promise<SearchBook[]> {
let bookList:SearchBook[] = []
if (!this.source) return bookList
const data: dataRule = {
body: this.xmlDate.body,
rule: this.source,
searchUrl: this.searchUrl
}
let response: AxiosResponse<object> = await axios.post('http://legado.wisdoms.xin/analysisBook', data)
if (response.data){
bookList = (response.data as SearchBook[]).map(item => {
item.bookType = this.xmlDate.bookSource?.bookSourceType ?? 0
item.source = this.xmlDate.bookSource
if (item.coverUrl && !isNetworkUrl(item.coverUrl)) {
item.coverUrl = this.xmlDate.bookSource?.bookSourceUrl + item.coverUrl
}
return item
})
}

if (bookList.length > 0){
console.log('test')
}
return bookList
}

//解析xml
async analysisXml(): Promise<SearchBook[]> {
return await this.getBookList();
}

}
// const xmlAnalysis = new XmlAnalysis();
// export default xmlAnalysis as XmlAnalysis;
35 changes: 35 additions & 0 deletions entry/src/main/ets/common/model/analyzeRule/RuleAnalyzer.ets
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* @author 2008
* @datetime 2024/8/18 2:03
* @className: AnalyzerRule
*/
import { BookSource } from '../../../database/entities/BookSource';

export interface IRuleAnalyzer {
body:string //请求内容
bookSource:BookSource//书源
}

export class RuleAnalyzerData {
body:string = '' //请求内容
bookSource?:BookSource//书源
}

export class RuleAnalyzer {
ruleAnalyzerData:RuleAnalyzerData = new RuleAnalyzerData()
init(ruleAnalyzerData:RuleAnalyzerData){
this.ruleAnalyzerData = ruleAnalyzerData
}

getElements(rule:string):ESObject{
let result: ESObject = null
return []
}

/**
* 分解规则生成规则列表
*/
splitSourceRule(ruleStr?:string,allInOne:boolean = false){

}
}
122 changes: 122 additions & 0 deletions entry/src/main/ets/common/model/taskSearchBook.ets
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/**
* @author 2008
* @datetime 2024/8/16 20:16
* @className: taskSearchBook
*/
import taskPool from '@ohos.taskpool';
import { BookSource } from '../../database/entities/BookSource';
import bookSourceDao from '../../database/dao/BookSourceDao';
import { showMessage } from '../../componets/common/promptShow';
import searchUtil from '../utils/searchUtils';
import { SearchBook } from '../../database/entities/SearchBook';


class taskSearchBook{
private bookSourceParts:BookSource[] = []
MAX_THREADS:number = 5;
tasks:taskPool.Task[] = [];
taskSearchBook:SearchBook[] = []

async search(searchKey: string, returnBook: (newUrls: SearchBook[]) => void, cancel: () => void): Promise<void> {
let dataStart = Date.now();
this.tasks = [];
this.taskSearchBook = []
this.bookSourceParts = []
if (!searchKey) {
return;
}

this.bookSourceParts = await bookSourceDao.getEnabledPartByGroup();
if (!this.bookSourceParts || this.bookSourceParts.length === 0) {
showMessage('启用书源为空');
cancel()
return;
}

const numBookSources = this.bookSourceParts.length;
const numThreads = Math.min(Math.ceil(numBookSources / 20), this.MAX_THREADS);
// 创建一个回调函数
const callback = (newUrls: SearchBook[]) => {
this.taskSearchBook.push(...newUrls)
returnBook(newUrls)
};

for (let i = 0; i < numThreads; i++) {
const sourcesSlice = this.bookSourceParts.slice(
(i * numBookSources) / numThreads,
((i + 1) * numBookSources) / numThreads
);

const task = new taskPool.Task(
`搜索${i}`,
searchTask,
searchKey, sourcesSlice
);
task.onReceiveData(callback)
this.tasks.push(task);
}

try {
if (this.tasks.length > 0) {
const results = await Promise.all(this.tasks.map(async (task, index) => {
console.log(`任务执行中... ${task.name} ${task.isDone()}`);
try {
return await taskPool.execute(task, index % 3);
} catch (e) {
console.log(e.message);
return [];
}
}));
const searchBooks = results.flat();
let dataEnd = Date.now();
showMessage(`搜索中止,共搜索到${this.taskSearchBook.length}个结果` + `用时${(dataEnd - dataStart) / 1000}秒`);
cancel()
}
} catch (error) {
console.error('Error during search:', error);
cancel()
showMessage('搜索中止');
}
}

cancelAllTasks() {
if (this.tasks.length > 0) {
this.tasks.forEach((task) => {
console.log(`任务执行中 ${task.name} ${task.isDone()}`)
if (task.isDone()) {
return
}
taskPool.cancel(task)
console.log(`任务已取消 ${task.name} ${task.isDone()}`)
})
}
this.tasks = [];
this.taskSearchBook = []
this.bookSourceParts = []
}

}

@Concurrent
async function searchTask(searchKey: string, bookSource: BookSource[]): Promise<SearchBook[]> {
let searchBook:SearchBook[] = []
try {
for (const source of bookSource) {
if (taskPool.Task.isCanceled()) {
console.log('任务已取消')
return []
}
const newUrls = await searchUtil.searchData(searchKey, Date.now(), source);
if (newUrls.length > 0) {
searchBook.push(...newUrls)
}
taskPool.Task.sendData(newUrls)
}
return searchBook;
} catch (e) {
console.log(e.message);
return []
}
}
const taskSearchBooks = new taskSearchBook();
export default taskSearchBooks as taskSearchBook;
63 changes: 63 additions & 0 deletions entry/src/main/ets/common/utils/NetworkUtils.ets
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* @author 2008
* @datetime 2024/8/15 13:15
* @className: NetworkUtils
*/
import { url } from '@kit.ArkTS';
class NetworkUtils {

getAbsoluteURL(baseUrl: string, searchUrl: string): string {
try {
const absoluteUrl = url.URL.parseURL(searchUrl, baseUrl);
return absoluteUrl.href;
} catch (error) {
console.error('Failed to resolve absolute URL:', error);
return searchUrl;
}
}

async getBaseUrl(url: string): Promise<string | null> {
if (!url) return null
if(url.startsWith('http://') || url.startsWith('https://')){
let index = url.indexOf("/", 9)
if (index === -1) {
return url
} else {
return url.substring(0, index)
}
}
return null
}

checkContentType(data:string){
try {
// 尝试将数据解析为 JSON
if (typeof data === 'object') {
return true;
}
JSON.parse(data);
return true;
} catch (e) {
// 如果解析失败,检查是否存在 HTML 标签
if (/<\/?[^>]+(>|$)/.test(data)) {
return false;
} else {
// 如果既不是有效的 JSON 也不是 HTML,则返回未知类型
return null;
}
}
}

//判断类型是string还是ArrayBuffer
isString(data:string|ArrayBuffer):boolean{
return typeof data === 'string'
}

cleanUrl(url:string){
return url.replace(/^\s+|\s+$/g, '').replace(/[\r\n]+/g, '');
}


}
const networkUtil = new NetworkUtils();
export default networkUtil as NetworkUtils;
Loading

0 comments on commit fa5b280

Please sign in to comment.