mirror of
https://github.com/jiangrui1994/CloudSaver.git
synced 2026-01-12 08:08:46 +08:00
feat:版本迭代
This commit is contained in:
@@ -6,12 +6,9 @@ import { ShareInfoResponse } from "../types/cloud115";
|
||||
|
||||
export class Cloud115Service {
|
||||
private api: AxiosInstance;
|
||||
private cookie: string = "";
|
||||
|
||||
constructor(cookie: string) {
|
||||
if (!cookie) {
|
||||
throw new Error("115网盘需要提供cookie进行身份验证");
|
||||
}
|
||||
|
||||
constructor(cookie?: string) {
|
||||
this.api = createAxiosInstance(
|
||||
"https://webapi.115.com",
|
||||
AxiosHeaders.from({
|
||||
@@ -29,91 +26,77 @@ export class Cloud115Service {
|
||||
Referer: "https://servicewechat.com/wx2c744c010a61b0fa/94/page-frame.html",
|
||||
"Accept-Encoding": "gzip, deflate, br",
|
||||
"Accept-Language": "zh-CN,zh;q=0.9",
|
||||
cookie: cookie,
|
||||
})
|
||||
);
|
||||
if (cookie) {
|
||||
this.setCookie(cookie);
|
||||
} else {
|
||||
console.log("请注意:115网盘需要提供cookie进行身份验证");
|
||||
}
|
||||
this.api.interceptors.request.use((config) => {
|
||||
config.headers.cookie = cookie || this.cookie;
|
||||
return config;
|
||||
});
|
||||
}
|
||||
|
||||
public setCookie(cookie: string) {
|
||||
this.cookie = cookie;
|
||||
}
|
||||
|
||||
async getShareInfo(shareCode: string, receiveCode = ""): Promise<ShareInfoResponse> {
|
||||
try {
|
||||
const response = await this.api.get("/share/snap", {
|
||||
params: {
|
||||
share_code: shareCode,
|
||||
receive_code: receiveCode,
|
||||
offset: 0,
|
||||
limit: 20,
|
||||
cid: "",
|
||||
},
|
||||
});
|
||||
|
||||
if (response.data?.state && response.data.data?.list?.length > 0) {
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
list: response.data.data.list.map((item: any) => ({
|
||||
fileId: item.cid,
|
||||
fileName: item.n,
|
||||
fileSize: item.s,
|
||||
})),
|
||||
},
|
||||
};
|
||||
}
|
||||
const response = await this.api.get("/share/snap", {
|
||||
params: {
|
||||
share_code: shareCode,
|
||||
receive_code: receiveCode,
|
||||
offset: 0,
|
||||
limit: 20,
|
||||
cid: "",
|
||||
},
|
||||
});
|
||||
|
||||
if (response.data?.state && response.data.data?.list?.length > 0) {
|
||||
return {
|
||||
success: false,
|
||||
error: "未找到文件信息",
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : "未知错误",
|
||||
data: response.data.data.list.map((item: any) => ({
|
||||
fileId: item.cid,
|
||||
fileName: item.n,
|
||||
fileSize: item.s,
|
||||
})),
|
||||
};
|
||||
}
|
||||
throw new Error("未找到文件信息");
|
||||
}
|
||||
|
||||
async getFolderList(parentCid = "0") {
|
||||
try {
|
||||
const response = await this.api.get("/files", {
|
||||
params: {
|
||||
aid: 1,
|
||||
cid: parentCid,
|
||||
o: "user_ptime",
|
||||
asc: 0,
|
||||
offset: 0,
|
||||
show_dir: 1,
|
||||
limit: 50,
|
||||
type: 0,
|
||||
format: "json",
|
||||
star: 0,
|
||||
suffix: "",
|
||||
natsort: 1,
|
||||
},
|
||||
});
|
||||
const response = await this.api.get("/files", {
|
||||
params: {
|
||||
aid: 1,
|
||||
cid: parentCid,
|
||||
o: "user_ptime",
|
||||
asc: 0,
|
||||
offset: 0,
|
||||
show_dir: 1,
|
||||
limit: 50,
|
||||
type: 0,
|
||||
format: "json",
|
||||
star: 0,
|
||||
suffix: "",
|
||||
natsort: 1,
|
||||
},
|
||||
});
|
||||
|
||||
if (response.data?.state) {
|
||||
return {
|
||||
success: true,
|
||||
data: response.data.data
|
||||
.filter((item: any) => item.cid)
|
||||
.map((folder: any) => ({
|
||||
cid: folder.cid,
|
||||
name: folder.n,
|
||||
path: response.data.path,
|
||||
})),
|
||||
};
|
||||
} else {
|
||||
Logger.error("获取目录列表失败:", response.data.error);
|
||||
return {
|
||||
success: false,
|
||||
error: "获取115pan目录列表失败:" + response.data.error,
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
Logger.error("获取目录列表失败:", error);
|
||||
if (response.data?.state) {
|
||||
return {
|
||||
success: false,
|
||||
error: "获取115pan目录列表失败",
|
||||
data: response.data.data
|
||||
.filter((item: any) => item.cid && !!item.ns)
|
||||
.map((folder: any) => ({
|
||||
cid: folder.cid,
|
||||
name: folder.n,
|
||||
path: response.data.path,
|
||||
})),
|
||||
};
|
||||
} else {
|
||||
Logger.error("获取目录列表失败:", response.data.error);
|
||||
throw new Error("获取115pan目录列表失败:" + response.data.error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,26 +106,23 @@ export class Cloud115Service {
|
||||
receiveCode: string;
|
||||
fileId: string;
|
||||
}) {
|
||||
try {
|
||||
const param = new URLSearchParams({
|
||||
cid: params.cid,
|
||||
user_id: config.cloud115.userId,
|
||||
share_code: params.shareCode,
|
||||
receive_code: params.receiveCode,
|
||||
file_id: params.fileId,
|
||||
});
|
||||
const response = await this.api.post("/share/receive", param.toString());
|
||||
|
||||
const param = new URLSearchParams({
|
||||
cid: params.cid,
|
||||
user_id: config.cloud115.userId,
|
||||
share_code: params.shareCode,
|
||||
receive_code: params.receiveCode,
|
||||
file_id: params.fileId,
|
||||
});
|
||||
const response = await this.api.post("/share/receive", param.toString());
|
||||
Logger.info("保存文件:", response.data);
|
||||
if (response.data.state) {
|
||||
return {
|
||||
success: response.data.state,
|
||||
error: response.data.error,
|
||||
data: response.data,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : "未知错误",
|
||||
message: response.data.error,
|
||||
data: response.data.data,
|
||||
};
|
||||
} else {
|
||||
Logger.error("保存文件失败:", response.data.error);
|
||||
throw new Error("保存115pan文件失败:" + response.data.error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
52
backend/src/services/DoubanService.ts
Normal file
52
backend/src/services/DoubanService.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { AxiosHeaders, AxiosInstance } from "axios";
|
||||
import { createAxiosInstance } from "../utils/axiosInstance";
|
||||
|
||||
class DoubanService {
|
||||
private baseUrl: string;
|
||||
private api: AxiosInstance;
|
||||
|
||||
constructor() {
|
||||
this.baseUrl = "https://movie.douban.com/j";
|
||||
this.api = createAxiosInstance(
|
||||
this.baseUrl,
|
||||
AxiosHeaders.from({
|
||||
accept: "*/*",
|
||||
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
|
||||
priority: "u=1, i",
|
||||
"sec-ch-ua": '"Not A(Brand";v="8", "Chromium";v="132", "Microsoft Edge";v="132"',
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": '"Windows"',
|
||||
"sec-fetch-dest": "empty",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"x-requested-with": "XMLHttpRequest",
|
||||
cookie:
|
||||
'll="118282"; bid=StA6AQFsAWQ; _pk_id.100001.4cf6=6448be57b1b5ca7e.1723172321.; _vwo_uuid_v2=DC15B8183560FF1E538FFE1D480723310|c08e2d213ecb5510005f90a6ff332121; __utmv=30149280.6282; _vwo_uuid_v2=DC15B8183560FF1E538FFE1D480723310|c08e2d213ecb5510005f90a6ff332121; __utmz=30149280.1731915179.21.6.utmcsr=search.douban.com|utmccn=(referral)|utmcmd=referral|utmcct=/movie/subject_search; __utmz=223695111.1731915179.21.6.utmcsr=search.douban.com|utmccn=(referral)|utmcmd=referral|utmcct=/movie/subject_search; douban-fav-remind=1; __utmc=30149280; __utmc=223695111; _pk_ref.100001.4cf6=%5B%22%22%2C%22%22%2C1739176523%2C%22https%3A%2F%2Fsearch.douban.com%2Fmovie%2Fsubject_search%3Fsearch_text%3D%E8%84%91%E6%B4%9E%E5%A4%A7%E5%BC%80%26cat%3D1002%22%5D; _pk_ses.100001.4cf6=1; ap_v=0,6.0; __utma=30149280.859303574.1723448979.1739167503.1739176523.42; __utmb=30149280.0.10.1739176523; __utma=223695111.1882744177.1723448979.1739167503.1739176523.42; __utmb=223695111.0.10.1739176523',
|
||||
Referer: "https://movie.douban.com/",
|
||||
"Referrer-Policy": "unsafe-url",
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
async getHotList(params: { type: string; tag: string; page_limit: string; page_start: string }) {
|
||||
try {
|
||||
const response = await this.api.get("/search_subjects", {
|
||||
params: params,
|
||||
});
|
||||
if (response.data && response.data.subjects) {
|
||||
return {
|
||||
data: response.data.subjects,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
data: [],
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching hot list:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default DoubanService;
|
||||
@@ -4,16 +4,13 @@ import { createAxiosInstance } from "../utils/axiosInstance";
|
||||
|
||||
export class QuarkService {
|
||||
private api: AxiosInstance;
|
||||
private cookie: string = "";
|
||||
|
||||
constructor(cookie: string) {
|
||||
if (!cookie) {
|
||||
throw new Error("115网盘需要提供cookie进行身份验证");
|
||||
}
|
||||
|
||||
constructor(cookie?: string) {
|
||||
this.api = createAxiosInstance(
|
||||
"https://drive-h.quark.cn",
|
||||
AxiosHeaders.from({
|
||||
cookie: cookie,
|
||||
cookie: this.cookie,
|
||||
accept: "application/json, text/plain, */*",
|
||||
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
|
||||
"content-type": "application/json",
|
||||
@@ -26,125 +23,112 @@ export class QuarkService {
|
||||
"sec-fetch-site": "same-site",
|
||||
})
|
||||
);
|
||||
if (cookie) {
|
||||
this.setCookie(cookie);
|
||||
} else {
|
||||
console.log("请注意:夸克网盘需要提供cookie进行身份验证");
|
||||
}
|
||||
this.api.interceptors.request.use((config) => {
|
||||
config.headers.cookie = cookie || this.cookie;
|
||||
return config;
|
||||
});
|
||||
}
|
||||
|
||||
public setCookie(cookie: string) {
|
||||
this.cookie = cookie;
|
||||
}
|
||||
|
||||
async getShareInfo(pwdId: string, passcode = "") {
|
||||
try {
|
||||
const response = await this.api.post(
|
||||
`/1/clouddrive/share/sharepage/token?pr=ucpro&fr=pc&uc_param_str=&__dt=994&__t=${Date.now()}`,
|
||||
{
|
||||
pwd_id: pwdId,
|
||||
passcode: "",
|
||||
}
|
||||
);
|
||||
if (response.data?.status === 200 && response.data.data) {
|
||||
const fileInfo = response.data.data;
|
||||
if (fileInfo.stoken) {
|
||||
let res = await this.getShareList(pwdId, fileInfo.stoken);
|
||||
return {
|
||||
success: true,
|
||||
data: res,
|
||||
};
|
||||
}
|
||||
const response = await this.api.post(
|
||||
`/1/clouddrive/share/sharepage/token?pr=ucpro&fr=pc&uc_param_str=&__dt=994&__t=${Date.now()}`,
|
||||
{
|
||||
pwd_id: pwdId,
|
||||
passcode,
|
||||
}
|
||||
);
|
||||
if (response.data?.status === 200 && response.data.data) {
|
||||
const fileInfo = response.data.data;
|
||||
if (fileInfo.stoken) {
|
||||
let res = await this.getShareList(pwdId, fileInfo.stoken);
|
||||
return {
|
||||
data: res,
|
||||
};
|
||||
}
|
||||
return {
|
||||
success: false,
|
||||
error: "未找到文件信息",
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : "未知错误",
|
||||
};
|
||||
}
|
||||
throw new Error("获取夸克分享信息失败");
|
||||
}
|
||||
|
||||
async getShareList(pwdId: string, stoken: string) {
|
||||
try {
|
||||
const response = await this.api.get("/1/clouddrive/share/sharepage/detail", {
|
||||
params: {
|
||||
pr: "ucpro",
|
||||
fr: "pc",
|
||||
uc_param_str: "",
|
||||
pwd_id: pwdId,
|
||||
stoken: stoken,
|
||||
pdir_fid: "0",
|
||||
force: "0",
|
||||
_page: "1",
|
||||
_size: "50",
|
||||
_fetch_banner: "1",
|
||||
_fetch_share: "1",
|
||||
_fetch_total: "1",
|
||||
_sort: "file_type:asc,updated_at:desc",
|
||||
__dt: "1589",
|
||||
__t: Date.now(),
|
||||
},
|
||||
});
|
||||
if (response.data?.data) {
|
||||
const list = response.data.data.list
|
||||
.filter((item: any) => item.fid)
|
||||
.map((folder: any) => ({
|
||||
fileId: folder.fid,
|
||||
fileName: folder.file_name,
|
||||
fileIdToken: folder.share_fid_token,
|
||||
}));
|
||||
return {
|
||||
list,
|
||||
pwdId,
|
||||
stoken: stoken,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
list: [],
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
Logger.error("获取目录列表失败:", error);
|
||||
return [];
|
||||
const response = await this.api.get("/1/clouddrive/share/sharepage/detail", {
|
||||
params: {
|
||||
pr: "ucpro",
|
||||
fr: "pc",
|
||||
uc_param_str: "",
|
||||
pwd_id: pwdId,
|
||||
stoken: stoken,
|
||||
pdir_fid: "0",
|
||||
force: "0",
|
||||
_page: "1",
|
||||
_size: "50",
|
||||
_fetch_banner: "1",
|
||||
_fetch_share: "1",
|
||||
_fetch_total: "1",
|
||||
_sort: "file_type:asc,updated_at:desc",
|
||||
__dt: "1589",
|
||||
__t: Date.now(),
|
||||
},
|
||||
});
|
||||
if (response.data?.data) {
|
||||
const list = response.data.data.list
|
||||
.filter((item: any) => item.fid)
|
||||
.map((folder: any) => ({
|
||||
fileId: folder.fid,
|
||||
fileName: folder.file_name,
|
||||
fileIdToken: folder.share_fid_token,
|
||||
}));
|
||||
return {
|
||||
list,
|
||||
pwdId,
|
||||
stoken: stoken,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
list: [],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async getFolderList(parentCid = "0") {
|
||||
try {
|
||||
const response = await this.api.get("/1/clouddrive/file/sort", {
|
||||
params: {
|
||||
pr: "ucpro",
|
||||
fr: "pc",
|
||||
uc_param_str: "",
|
||||
pdir_fid: parentCid,
|
||||
_page: "1",
|
||||
_size: "100",
|
||||
_fetch_total: "false",
|
||||
_fetch_sub_dirs: "1",
|
||||
_sort: "",
|
||||
__dt: "2093126",
|
||||
__t: Date.now(),
|
||||
},
|
||||
});
|
||||
if (response.data?.data && response.data.data.list.length) {
|
||||
return {
|
||||
success: true,
|
||||
data: response.data.data.list
|
||||
.filter((item: any) => item.fid)
|
||||
.map((folder: any) => ({
|
||||
cid: folder.fid,
|
||||
name: folder.file_name,
|
||||
path: [],
|
||||
})),
|
||||
};
|
||||
} else {
|
||||
Logger.error("获取目录列表失败:", response.data.error);
|
||||
return {
|
||||
success: false,
|
||||
error: "获取夸克目录列表失败:" + response.data.error,
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
Logger.error("获取目录列表失败:", error);
|
||||
const response = await this.api.get("/1/clouddrive/file/sort", {
|
||||
params: {
|
||||
pr: "ucpro",
|
||||
fr: "pc",
|
||||
uc_param_str: "",
|
||||
pdir_fid: parentCid,
|
||||
_page: "1",
|
||||
_size: "100",
|
||||
_fetch_total: "false",
|
||||
_fetch_sub_dirs: "1",
|
||||
_sort: "",
|
||||
__dt: "2093126",
|
||||
__t: Date.now(),
|
||||
},
|
||||
});
|
||||
if (response.data?.data && response.data.data.list.length) {
|
||||
const data = response.data.data.list
|
||||
.filter((item: any) => item.fid && item.file_type === 0)
|
||||
.map((folder: any) => ({
|
||||
cid: folder.fid,
|
||||
name: folder.file_name,
|
||||
path: [],
|
||||
}));
|
||||
return {
|
||||
success: false,
|
||||
error: "获取夸克目录列表失败",
|
||||
data,
|
||||
};
|
||||
} else {
|
||||
const message = "获取夸克目录列表失败:" + response.data.error;
|
||||
Logger.error(message);
|
||||
throw new Error(message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,15 +148,11 @@ export class QuarkService {
|
||||
);
|
||||
|
||||
return {
|
||||
success: response.data.code === 0,
|
||||
error: response.data.message,
|
||||
message: response.data.message,
|
||||
data: response.data.data,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : "未知错误",
|
||||
};
|
||||
throw new Error(error instanceof Error ? error.message : "未知错误");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { AxiosInstance, AxiosHeaders } from "axios";
|
||||
import { config } from "../config";
|
||||
import { Logger } from "../utils/logger";
|
||||
import { createAxiosInstance } from "../utils/axiosInstance";
|
||||
import { data } from "cheerio/dist/commonjs/api/attributes";
|
||||
|
||||
interface RSSItem {
|
||||
title?: string;
|
||||
@@ -81,7 +82,10 @@ export class RSSSearcher {
|
||||
}
|
||||
}
|
||||
|
||||
return allResults;
|
||||
return {
|
||||
data: allResults,
|
||||
message: "搜索成功",
|
||||
};
|
||||
}
|
||||
|
||||
async searchInRSSFeed(rssUrl: string) {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { AxiosInstance, AxiosHeaders } from "axios";
|
||||
import { createAxiosInstance } from "../utils/axiosInstance";
|
||||
import GlobalSetting from "../models/GlobalSetting";
|
||||
import { GlobalSettingAttributes } from "../models/GlobalSetting";
|
||||
import * as cheerio from "cheerio";
|
||||
import { config } from "../config";
|
||||
import { Logger } from "../utils/logger";
|
||||
@@ -7,19 +9,30 @@ import { Logger } from "../utils/logger";
|
||||
interface sourceItem {
|
||||
messageId?: string;
|
||||
title?: string;
|
||||
completeTitle?: string;
|
||||
link?: string;
|
||||
pubDate?: string;
|
||||
content?: string;
|
||||
description?: string;
|
||||
image?: string;
|
||||
cloudLinks?: string[];
|
||||
tags?: string[];
|
||||
cloudType?: string;
|
||||
}
|
||||
|
||||
export class Searcher {
|
||||
private axiosInstance: AxiosInstance;
|
||||
private axiosInstance: AxiosInstance | null = null;
|
||||
|
||||
constructor() {
|
||||
this.initializeAxiosInstance();
|
||||
}
|
||||
|
||||
private async initializeAxiosInstance(isUpdate = false) {
|
||||
let settings = null;
|
||||
if (isUpdate) {
|
||||
settings = await GlobalSetting.findOne();
|
||||
}
|
||||
const globalSetting = settings?.dataValues || ({} as GlobalSettingAttributes);
|
||||
this.axiosInstance = createAxiosInstance(
|
||||
config.telegram.baseUrl,
|
||||
AxiosHeaders.from({
|
||||
@@ -37,9 +50,15 @@ export class Searcher {
|
||||
"sec-fetch-user": "?1",
|
||||
"upgrade-insecure-requests": "1",
|
||||
}),
|
||||
true
|
||||
globalSetting?.isProxyEnabled,
|
||||
globalSetting?.isProxyEnabled
|
||||
? { host: globalSetting?.httpProxyHost, port: globalSetting?.httpProxyPort }
|
||||
: undefined
|
||||
);
|
||||
}
|
||||
public async updateAxiosInstance() {
|
||||
await this.initializeAxiosInstance(true);
|
||||
}
|
||||
|
||||
private extractCloudLinks(text: string): { links: string[]; cloudType: string } {
|
||||
const links: string[] = [];
|
||||
@@ -82,22 +101,38 @@ export class Searcher {
|
||||
channelId: channel.id,
|
||||
}));
|
||||
|
||||
allResults.push(...channelResults);
|
||||
allResults.push({
|
||||
list: channelResults,
|
||||
channelInfo: {
|
||||
...channel,
|
||||
channelLogo: results.channelLogo,
|
||||
},
|
||||
id: channel.id,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
Logger.error(`搜索频道 ${channel.name} 失败:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
return allResults;
|
||||
return {
|
||||
data: allResults,
|
||||
};
|
||||
}
|
||||
|
||||
async searchInWeb(url: string, channelId: string) {
|
||||
try {
|
||||
if (!this.axiosInstance) {
|
||||
throw new Error("Axios instance is not initialized");
|
||||
}
|
||||
const response = await this.axiosInstance.get(url);
|
||||
const html = response.data;
|
||||
const $ = cheerio.load(html);
|
||||
const items: sourceItem[] = [];
|
||||
let channelLogo = "";
|
||||
$(".tgme_header_link").each((_, element) => {
|
||||
channelLogo = $(element).find("img").attr("src") || "";
|
||||
});
|
||||
// 遍历每个消息容器
|
||||
$(".tgme_widget_message_wrap").each((_, element) => {
|
||||
const messageEl = $(element);
|
||||
@@ -109,8 +144,24 @@ export class Searcher {
|
||||
?.toString()
|
||||
.split("/")[1];
|
||||
|
||||
// 提取标题 (消息截取100长度)
|
||||
const title = messageEl.find(".js-message_text").text().trim().substring(0, 50) + "...";
|
||||
// 提取标题 (第一个<br>标签前的内容)
|
||||
const title =
|
||||
messageEl
|
||||
.find(".js-message_text")
|
||||
.html()
|
||||
?.split("<br>")[0]
|
||||
.replace(/<[^>]+>/g, "")
|
||||
.replace(/\n/g, "") || "";
|
||||
|
||||
// 提取描述 (第一个<a>标签前面的内容,不包含标题)
|
||||
const content =
|
||||
messageEl
|
||||
.find(".js-message_text")
|
||||
.html()
|
||||
?.replace(title, "")
|
||||
.split("<a")[0]
|
||||
.replace(/<br>/g, "")
|
||||
.trim() || "";
|
||||
|
||||
// 提取链接 (消息中的链接)
|
||||
// const link = messageEl.find('.tgme_widget_message').data('post');
|
||||
@@ -118,23 +169,24 @@ export class Searcher {
|
||||
// 提取发布时间
|
||||
const pubDate = messageEl.find("time").attr("datetime");
|
||||
|
||||
// 提取内容 (完整消息文本)
|
||||
const content = messageEl.find(".js-message_text").text();
|
||||
|
||||
// 提取描述 (消息文本中"描述:"后的内容)
|
||||
const description = content.split("描述:")[1]?.split("\n")[0]?.trim();
|
||||
|
||||
// 提取图片
|
||||
const image = messageEl
|
||||
.find(".tgme_widget_message_photo_wrap")
|
||||
.attr("style")
|
||||
?.match(/url\('(.+?)'\)/)?.[1];
|
||||
|
||||
const tags: string[] = [];
|
||||
// 提取云盘链接
|
||||
const links = messageEl
|
||||
.find(".tgme_widget_message_text a")
|
||||
.map((_, el) => $(el).attr("href"))
|
||||
.get();
|
||||
messageEl.find(".tgme_widget_message_text a").each((index, element) => {
|
||||
const tagText = $(element).text();
|
||||
if (tagText && tagText.startsWith("#")) {
|
||||
tags.push(tagText);
|
||||
}
|
||||
});
|
||||
const cloudInfo = this.extractCloudLinks(links.join(" "));
|
||||
// 添加到数组第一位
|
||||
items.unshift({
|
||||
@@ -142,18 +194,21 @@ export class Searcher {
|
||||
title,
|
||||
pubDate,
|
||||
content,
|
||||
description,
|
||||
image,
|
||||
cloudLinks: cloudInfo.links,
|
||||
cloudType: cloudInfo.cloudType,
|
||||
tags,
|
||||
});
|
||||
});
|
||||
return { items };
|
||||
return { items: items, channelLogo };
|
||||
} catch (error) {
|
||||
Logger.error(`RSS源解析错误: ${url}`, error);
|
||||
Logger.error(`搜索错误: ${url}`, error);
|
||||
return {
|
||||
items: [],
|
||||
channelLogo: "",
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default new Searcher();
|
||||
|
||||
Reference in New Issue
Block a user