feat:版本迭代

This commit is contained in:
jiangrui
2025-02-20 12:00:19 +08:00
parent fd110590af
commit 510fdc48f6
86 changed files with 5045 additions and 1161 deletions

View File

@@ -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);
}
}
}

View 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;

View File

@@ -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 : "未知错误");
}
}
}

View File

@@ -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) {

View File

@@ -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();