format:format and fix code

This commit is contained in:
jiangrui
2025-02-24 15:22:43 +08:00
parent c784b562c4
commit f5106e782a
46 changed files with 2055 additions and 1172 deletions

View File

@@ -38,7 +38,7 @@ app.use((req, res, next) => {
app.use("/", routes);
const initializeGlobalSettings = async () => {
const initializeGlobalSettings = async (): Promise<void> => {
const settings = await GlobalSetting.findOne();
if (!settings) {
await GlobalSetting.create({

View File

@@ -1,15 +1,14 @@
import { Request, Response, NextFunction } from "express";
import { Request, Response } from "express";
import { Cloud115Service } from "../services/Cloud115Service";
import { sendSuccess, sendError } from "../utils/response";
import UserSetting from "../models/UserSetting";
const cloud115 = new Cloud115Service();
const setCookie = async (req: Request) => {
const setCookie = async (req: Request): Promise<void> => {
const userId = req.user?.userId;
const userSetting = await UserSetting.findOne({
where: { userId },
});
console.log(userSetting?.dataValues.cloud115Cookie);
if (userSetting && userSetting.dataValues.cloud115Cookie) {
cloud115.setCookie(userSetting.dataValues.cloud115Cookie);
} else {
@@ -18,7 +17,7 @@ const setCookie = async (req: Request) => {
};
export const cloud115Controller = {
async getShareInfo(req: Request, res: Response, next: NextFunction) {
async getShareInfo(req: Request, res: Response): Promise<void> {
try {
const { shareCode, receiveCode } = req.query;
await setCookie(req);
@@ -30,7 +29,7 @@ export const cloud115Controller = {
}
},
async getFolderList(req: Request, res: Response, next: NextFunction) {
async getFolderList(req: Request, res: Response): Promise<void> {
try {
const { parentCid } = req.query;
await setCookie(req);
@@ -41,7 +40,7 @@ export const cloud115Controller = {
}
},
async saveFile(req: Request, res: Response, next: NextFunction) {
async saveFile(req: Request, res: Response): Promise<void> {
try {
const { shareCode, receiveCode, fileId, folderId } = req.body;
await setCookie(req);

View File

@@ -1,11 +1,11 @@
import { Request, Response, NextFunction } from "express";
import { Request, Response } from "express";
import DoubanService from "../services/DoubanService";
import { sendSuccess, sendError } from "../utils/response";
const doubanService = new DoubanService();
export const doubanController = {
async getDoubanHotList(req: Request, res: Response, next: NextFunction) {
async getDoubanHotList(req: Request, res: Response): Promise<void> {
try {
const { type = "movie", tag = "热门", page_limit = "50", page_start = "0" } = req.query;
const result = await doubanService.getHotList({

View File

@@ -1,11 +1,11 @@
import { Request, Response, NextFunction } from "express";
import { Request, Response } from "express";
import { QuarkService } from "../services/QuarkService";
import { sendSuccess, sendError } from "../utils/response";
import UserSetting from "../models/UserSetting";
const quark = new QuarkService();
const setCookie = async (req: Request) => {
const setCookie = async (req: Request): Promise<void> => {
const userId = req.user?.userId;
const userSetting = await UserSetting.findOne({
where: { userId },
@@ -18,7 +18,7 @@ const setCookie = async (req: Request) => {
};
export const quarkController = {
async getShareInfo(req: Request, res: Response, next: NextFunction) {
async getShareInfo(req: Request, res: Response): Promise<void> {
try {
const { pwdId, passcode } = req.query;
await setCookie(req);
@@ -29,7 +29,7 @@ export const quarkController = {
}
},
async getFolderList(req: Request, res: Response, next: NextFunction) {
async getFolderList(req: Request, res: Response): Promise<void> {
try {
const { parentCid } = req.query;
await setCookie(req);
@@ -40,7 +40,7 @@ export const quarkController = {
}
},
async saveFile(req: Request, res: Response, next: NextFunction) {
async saveFile(req: Request, res: Response): Promise<void> {
try {
await setCookie(req);
const result = await quark.saveSharedFile(req.body);

View File

@@ -1,22 +1,9 @@
import { Request, Response, NextFunction } from "express";
import { RSSSearcher } from "../services/RSSSearcher";
import { Request, Response } from "express";
import Searcher from "../services/Searcher";
import { sendSuccess, sendError } from "../utils/response";
export const resourceController = {
async rssSearch(req: Request, res: Response, next: NextFunction) {
try {
const { keyword } = req.query;
const searcher = new RSSSearcher();
const result = await searcher.searchAll(keyword as string);
sendSuccess(res, result);
} catch (error) {
sendError(res, {
message: (error as Error).message || "RSS 搜索失败",
});
}
},
async search(req: Request, res: Response, next: NextFunction) {
async search(req: Request, res: Response): Promise<void> {
try {
const { keyword, channelId = "", lastMessageId = "" } = req.query; // Remove `: string` from here
const result = await Searcher.searchAll(

View File

@@ -1,11 +1,11 @@
import { Request, Response, NextFunction } from "express";
import { Request, Response } from "express";
import { sendSuccess, sendError } from "../utils/response";
import Searcher from "../services/Searcher";
import UserSetting from "../models/UserSetting";
import GlobalSetting from "../models/GlobalSetting";
export const settingController = {
async get(req: Request, res: Response) {
async get(req: Request, res: Response): Promise<void> {
try {
const userId = req.user?.userId;
const role = req.user?.role;
@@ -36,7 +36,7 @@ export const settingController = {
sendError(res, { message: (error as Error).message || "获取设置失败" });
}
},
async save(req: Request, res: Response) {
async save(req: Request, res: Response): Promise<void> {
try {
const userId = req.user?.userId;
const role = req.user?.role;

View File

@@ -12,7 +12,7 @@ export class ImageControll {
this.initializeAxiosInstance();
}
private async initializeAxiosInstance(isUpdate = false) {
private async initializeAxiosInstance(isUpdate = false): Promise<void> {
let settings = null;
if (isUpdate) {
settings = await GlobalSetting.findOne();
@@ -35,7 +35,7 @@ export class ImageControll {
withCredentials: true,
});
}
async getImages(req: Request, res: Response, url: string) {
async getImages(req: Request, res: Response, url: string): Promise<void> {
try {
if (!this.isUpdate) await this.initializeAxiosInstance(true);
const response = await this.axiosInstance?.get(url, { responseType: "stream" });
@@ -50,7 +50,7 @@ export class ImageControll {
const iamgesInstance = new ImageControll();
export const imageControll = {
getImages: async (req: Request, res: Response) => {
getImages: async (req: Request, res: Response): Promise<void> => {
const url = req.query.url as string;
iamgesInstance.getImages(req, res, url);
},

View File

@@ -12,7 +12,7 @@ const isValidInput = (input: string): boolean => {
return regex.test(input);
};
export const userController = {
async register(req: Request, res: Response) {
async register(req: Request, res: Response): Promise<void> {
const { username, password, registerCode } = req.body;
const globalSetting = await GlobalSetting.findOne();
const registerCodeList = [
@@ -39,12 +39,12 @@ export const userController = {
data: user,
message: "用户注册成功",
});
} catch (error: any) {
sendError(res, { message: error.message || "用户注册失败" });
} catch (error) {
sendError(res, { message: (error as Error).message || "用户注册失败" });
}
},
async login(req: Request, res: Response) {
async login(req: Request, res: Response): Promise<void> {
const { username, password } = req.body;
const user = await User.findOne({ where: { username } });
if (!user || !(await bcrypt.compare(password, user.password))) {

View File

@@ -15,7 +15,7 @@ export const authMiddleware = async (
req: AuthenticatedRequest,
res: Response,
next: NextFunction
) => {
): Promise<void | Response> => {
if (req.path === "/user/login" || req.path === "/user/register") {
return next();
}

View File

@@ -1,6 +1,10 @@
import { Request, Response, NextFunction } from "express";
import { Request, Response } from "express";
export const errorHandler = (err: any, req: Request, res: Response, next: NextFunction) => {
interface CustomError extends Error {
status?: number;
}
export const errorHandler = (err: CustomError, req: Request, res: Response): void => {
console.error(err);
res.status(err.status || 500).json({
success: false,

View File

@@ -1,6 +1,8 @@
import { Request, Response, NextFunction } from "express";
export const validateRequest = (requiredParams: string[]) => {
export const validateRequest = (
requiredParams: string[]
): ((req: Request, res: Response, next: NextFunction) => Response | void) => {
return (req: Request, res: Response, next: NextFunction) => {
const missingParams = requiredParams.filter((param) => !req.query[param] && !req.body[param]);
if (missingParams.length > 0) {

View File

@@ -19,7 +19,6 @@ router.use("/setting", settingRoutes);
// 资源搜索
router.get("/search", resourceController.search);
router.get("/rssSearch", resourceController.rssSearch);
// 115网盘相关
router.get("/cloud115/share-info", cloud115Controller.getShareInfo);

View File

@@ -7,4 +7,4 @@ const router = express.Router();
router.post("/register", userController.register);
router.post("/login", userController.login);
export default router;
export default router;

View File

@@ -4,6 +4,23 @@ import { Logger } from "../utils/logger";
import { config } from "../config/index";
import { ShareInfoResponse } from "../types/cloud115";
interface Cloud115ListItem {
cid: string;
n: string;
s: number;
}
interface Cloud115FolderItem {
cid: string;
n: string;
ns: number;
}
interface Cloud115PathItem {
cid: string;
name: string;
}
export class Cloud115Service {
private api: AxiosInstance;
private cookie: string = "";
@@ -39,7 +56,7 @@ export class Cloud115Service {
});
}
public setCookie(cookie: string) {
public setCookie(cookie: string): void {
this.cookie = cookie;
}
@@ -56,7 +73,7 @@ export class Cloud115Service {
if (response.data?.state && response.data.data?.list?.length > 0) {
return {
data: response.data.data.list.map((item: any) => ({
data: response.data.data.list.map((item: Cloud115ListItem) => ({
fileId: item.cid,
fileName: item.n,
fileSize: item.s,
@@ -66,7 +83,9 @@ export class Cloud115Service {
throw new Error("未找到文件信息");
}
async getFolderList(parentCid = "0") {
async getFolderList(
parentCid = "0"
): Promise<{ data: { cid: string; name: string; path: Cloud115PathItem[] }[] }> {
const response = await this.api.get("/files", {
params: {
aid: 1,
@@ -87,8 +106,8 @@ export class Cloud115Service {
if (response.data?.state) {
return {
data: response.data.data
.filter((item: any) => item.cid && !!item.ns)
.map((folder: any) => ({
.filter((item: Cloud115FolderItem) => item.cid && !!item.ns)
.map((folder: Cloud115FolderItem) => ({
cid: folder.cid,
name: folder.n,
path: response.data.path,
@@ -105,7 +124,7 @@ export class Cloud115Service {
shareCode: string;
receiveCode: string;
fileId: string;
}) {
}): Promise<{ message: string; data: unknown }> {
const param = new URLSearchParams({
cid: params.cid,
user_id: config.cloud115.userId,

View File

@@ -1,6 +1,15 @@
import { AxiosHeaders, AxiosInstance } from "axios";
import { createAxiosInstance } from "../utils/axiosInstance";
interface DoubanSubject {
id: string;
title: string;
rate: string;
cover: string;
url: string;
is_new: boolean;
}
class DoubanService {
private baseUrl: string;
private api: AxiosInstance;
@@ -28,7 +37,12 @@ class DoubanService {
);
}
async getHotList(params: { type: string; tag: string; page_limit: string; page_start: string }) {
async getHotList(params: {
type: string;
tag: string;
page_limit: string;
page_start: string;
}): Promise<{ data: DoubanSubject[] }> {
try {
const response = await this.api.get("/search_subjects", {
params: params,

View File

@@ -2,6 +2,23 @@ import { AxiosInstance, AxiosHeaders } from "axios";
import { Logger } from "../utils/logger";
import { createAxiosInstance } from "../utils/axiosInstance";
interface QuarkShareInfo {
stoken?: string;
pwdId?: string;
list: {
fid: string;
file_name: string;
file_type: number;
share_fid_token: string;
}[];
}
interface QuarkFolderItem {
fid: string;
file_name: string;
file_type: number;
}
export class QuarkService {
private api: AxiosInstance;
private cookie: string = "";
@@ -34,11 +51,11 @@ export class QuarkService {
});
}
public setCookie(cookie: string) {
public setCookie(cookie: string): void {
this.cookie = cookie;
}
async getShareInfo(pwdId: string, passcode = "") {
async getShareInfo(pwdId: string, passcode = ""): Promise<{ data: QuarkShareInfo }> {
const response = await this.api.post(
`/1/clouddrive/share/sharepage/token?pr=ucpro&fr=pc&uc_param_str=&__dt=994&__t=${Date.now()}`,
{
@@ -49,7 +66,7 @@ export class QuarkService {
if (response.data?.status === 200 && response.data.data) {
const fileInfo = response.data.data;
if (fileInfo.stoken) {
let res = await this.getShareList(pwdId, fileInfo.stoken);
const res = await this.getShareList(pwdId, fileInfo.stoken);
return {
data: res,
};
@@ -58,7 +75,7 @@ export class QuarkService {
throw new Error("获取夸克分享信息失败");
}
async getShareList(pwdId: string, stoken: string) {
async getShareList(pwdId: string, stoken: string): Promise<QuarkShareInfo> {
const response = await this.api.get("/1/clouddrive/share/sharepage/detail", {
params: {
pr: "ucpro",
@@ -80,8 +97,8 @@ export class QuarkService {
});
if (response.data?.data) {
const list = response.data.data.list
.filter((item: any) => item.fid)
.map((folder: any) => ({
.filter((item: QuarkShareInfo["list"][0]) => item.fid)
.map((folder: QuarkShareInfo["list"][0]) => ({
fileId: folder.fid,
fileName: folder.file_name,
fileIdToken: folder.share_fid_token,
@@ -89,7 +106,7 @@ export class QuarkService {
return {
list,
pwdId,
stoken: stoken,
stoken,
};
} else {
return {
@@ -98,7 +115,9 @@ export class QuarkService {
}
}
async getFolderList(parentCid = "0") {
async getFolderList(
parentCid = "0"
): Promise<{ data: { cid: string; name: string; path: [] }[] }> {
const response = await this.api.get("/1/clouddrive/file/sort", {
params: {
pr: "ucpro",
@@ -116,8 +135,8 @@ export class QuarkService {
});
if (response.data?.data && response.data.data.list) {
const data = response.data.data.list
.filter((item: any) => item.fid && item.file_type === 0)
.map((folder: any) => ({
.filter((item: QuarkFolderItem) => item.fid && item.file_type === 0)
.map((folder: QuarkFolderItem) => ({
cid: folder.fid,
name: folder.file_name,
path: [],
@@ -140,7 +159,7 @@ export class QuarkService {
stoken: string;
pdir_fid: string;
scene: string;
}) {
}): Promise<{ message: string; data: unknown }> {
try {
const response = await this.api.post(
`/1/clouddrive/share/sharepage/save?pr=ucpro&fr=pc&uc_param_str=&__dt=208097&__t=${Date.now()}`,

View File

@@ -1,116 +0,0 @@
import RSSParser from "rss-parser";
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;
link?: string;
pubDate?: string;
content?: string;
description?: string;
image?: string;
cloudLinks?: string[];
}
export class RSSSearcher {
private parser: RSSParser;
private axiosInstance: AxiosInstance;
constructor() {
this.parser = new RSSParser({
customFields: {
item: [
["content:encoded", "content"],
["description", "description"],
],
},
});
this.axiosInstance = createAxiosInstance(
config.rss.baseUrl,
AxiosHeaders.from({
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
Accept: "application/xml,application/xhtml+xml,text/html,application/rss+xml",
}),
true
);
}
private extractCloudLinks(text: string): { links: string[]; cloudType: string } {
const links: string[] = [];
let cloudType = "";
Object.values(config.cloudPatterns).forEach((pattern, index) => {
const matches = text.match(pattern);
if (matches) {
links.push(...matches);
cloudType = Object.keys(config.cloudPatterns)[index];
}
});
return {
links: [...new Set(links)],
cloudType,
};
}
async searchAll(keyword: string) {
const allResults = [];
for (let i = 0; i < config.rss.channels.length; i++) {
const channel = config.rss.channels[i];
try {
const rssUrl = `${config.rss.baseUrl}/${
channel.id
}${keyword ? `/searchQuery=${encodeURIComponent(keyword)}` : ""}`;
const results = await this.searchInRSSFeed(rssUrl);
if (results.items.length > 0) {
const channelResults = results.items
.filter((item: RSSItem) => item.cloudLinks && item.cloudLinks.length > 0)
.map((item: RSSItem) => ({
...item,
channel: channel.name + "(" + channel.id + ")",
}));
allResults.push(...channelResults);
}
} catch (error) {
Logger.error(`搜索频道 ${channel.name} 失败:`, error);
}
}
return {
data: allResults,
message: "搜索成功",
};
}
async searchInRSSFeed(rssUrl: string) {
try {
const response = await this.axiosInstance.get(rssUrl);
const feed = await this.parser.parseString(response.data);
return {
items: feed.items.map((item: RSSItem) => {
const linkInfo = this.extractCloudLinks(item.content || item.description || "");
return {
title: item.title || "",
link: item.link || "",
pubDate: item.pubDate || "",
image: item.image || "",
cloudLinks: linkInfo.links,
cloudType: linkInfo.cloudType,
};
}),
};
} catch (error) {
Logger.error(`RSS源解析错误: ${rssUrl}`, error);
return {
items: [],
};
}
}
}

View File

@@ -27,7 +27,7 @@ export class Searcher {
this.initializeAxiosInstance();
}
private async initializeAxiosInstance(isUpdate = false) {
private async initializeAxiosInstance(isUpdate = false): Promise<void> {
let settings = null;
if (isUpdate) {
settings = await GlobalSetting.findOne();
@@ -78,7 +78,6 @@ export class Searcher {
async searchAll(keyword: string, channelId?: string, messageId?: string) {
const allResults = [];
const totalChannels = config.rss.channels.length;
const channelList = channelId
? config.rss.channels.filter((channel) => channel.id === channelId)
@@ -90,7 +89,7 @@ export class Searcher {
const messageIdparams = messageId ? `before=${messageId}` : "";
const url = `/${channel.id}${keyword ? `?q=${encodeURIComponent(keyword)}&${messageIdparams}` : `?${messageIdparams}`}`;
console.log(`Searching in channel ${channel.name} with URL: ${url}`);
const results = await this.searchInWeb(url, channel.id);
const results = await this.searchInWeb(url);
console.log(`Found ${results.items.length} items in channel ${channel.name}`);
if (results.items.length > 0) {
const channelResults = results.items
@@ -120,7 +119,7 @@ export class Searcher {
};
}
async searchInWeb(url: string, channelId: string) {
async searchInWeb(url: string) {
try {
if (!this.axiosInstance) {
throw new Error("Axios instance is not initialized");

View File

@@ -1,3 +1,4 @@
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { Request } from "express";
declare module "express" {

View File

@@ -1,7 +1,5 @@
import axios, { AxiosInstance, AxiosRequestHeaders } from "axios";
import tunnel from "tunnel";
import { config } from "../config";
import GlobalSetting from "../models/GlobalSetting";
interface ProxyConfig {
host: string;

View File

@@ -1,8 +1,15 @@
import { Response, NextFunction } from "express";
import { Logger } from "../utils/logger";
interface CustomError {
name?: string;
message: string;
success?: boolean;
}
export default function handleError(
res: Response,
error: any,
error: CustomError | unknown,
message: string,
next: NextFunction
) {