@ikenxuan/amagi 5.12.0 → 5.12.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["logger: CustomLogger","httpLogger: CustomLogger","path","url","BilibiliVideoParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['VideoInfoParams']>","BilibiliVideoDownloadParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['VideoStreamParams']>","BilibiliCommentParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['CommentParams']>","BilibiliCommentReplyParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['CommentReplyParams']>","BilibiliUserParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['UserParams']>","BilibiliEmojiParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['EmojiParams']>","BilibiliBangumiInfoParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['BangumiInfoParams']>","data","BilibiliBangumiStreamParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['BangumiStreamParams']>","BilibiliDynamicParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['DynamicParams']>","BilibiliLiveParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['LiveRoomParams']>","BilibiliLoginParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['LoginBaseInfoParams']>","BilibiliQrcodeParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['GetQrcodeParams']>","BilibiliQrcodeStatusParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['QrcodeParams']>","BilibiliAv2BvParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['Av2BvParams']>","BilibiliBv2AvParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['Bv2AvParams']>","BilibiliArticleParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['ArticleParams']>","BilibiliArticleCardParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['ArticleCardParams']>","BilibiliArticleInfoParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['ArticleInfoParams']>","BilibiliColumnInfoParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['ColumnInfoParams']>","BilibiliApplyCaptchaParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['ApplyVoucherCaptchaParams']>","BilibiliValidateCaptchaParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['ValidateCaptchaParams']>","DouyinWorkParamsSchema: zod.ZodType<DouyinMethodOptionsMap['WorkParams']>","DouyinCommentParamsSchema: zod.ZodType<DouyinMethodOptionsMap['CommentParams']>","DouyinHotWordsParamsSchema: zod.ZodType<DouyinMethodOptionsMap['HotWordsParams']>","DouyinSearchParamsSchema: zod.ZodType<DouyinMethodOptionsMap['SearchParams']>","DouyinCommentReplyParamsSchema: zod.ZodType<DouyinMethodOptionsMap['CommentReplyParams']>","DouyinUserParamsSchema: zod.ZodType<DouyinMethodOptionsMap['UserParams']>","DouyinMusicParamsSchema: zod.ZodType<DouyinMethodOptionsMap['MusicParams']>","DouyinLiveRoomParamsSchema: zod.ZodType<DouyinMethodOptionsMap['LiveRoomParams']>","DouyinQrcodeParamsSchema: zod.ZodType<DouyinMethodOptionsMap['QrcodeParams']>","DouyinEmojiListParamsSchema: zod.ZodType<DouyinMethodOptionsMap['EmojiListParams']>","DouyinEmojiProParamsSchema: zod.ZodType<DouyinMethodOptionsMap['EmojiProParams']>","DouyinDanmakuParamsSchema: zod.ZodType<DouyinMethodOptionsMap['DanmakuParams']>","data","KuaishouVideoParamsSchema: zod.ZodType<KuaishouMethodOptionsMap['VideoInfoParams']>","KuaishouCommentParamsSchema: zod.ZodType<KuaishouMethodOptionsMap['CommentParams']>","KuaishouEmojiParamsSchema: zod.ZodType<KuaishouMethodOptionsMap['EmojiListParams']>","path","buildQueryString","data","HomeFeedParamsSchema: zod.ZodType<XiaohongshuMethodOptionsMap['HomeFeedParams']>","NoteParamsSchema: zod.ZodType<XiaohongshuMethodOptionsMap['NoteParams']>","CommentParamsSchema: zod.ZodType<XiaohongshuMethodOptionsMap['CommentParams']>","UserParamsSchema: zod.ZodType<XiaohongshuMethodOptionsMap['UserParams']>","UserNoteParamsSchema: zod.ZodType<XiaohongshuMethodOptionsMap['UserNoteParams']>","EmojiListParamsSchema: zod.ZodType<XiaohongshuMethodOptionsMap['EmojiListParams']>","SearchNoteParamsSchema: zod.ZodType<XiaohongshuMethodOptionsMap['SearchNoteParams']>","data","lastError: AxiosError | null","defHeaders: RequestConfig['headers']","data","mixinKeyEncTab: readonly number[]","url","params: RequestParams","path","bilibiliUtils: bilibiliUtilsModel","data","GlobalGetData","fetchedComments: any[]","tmpresp: any","Err: ErrorDetail","a: number[]","i: string | number[] | null","t","temp: any","b: { [key: number]: any }","random_str_list: any[]","url","result: number[]","dataArray: number[]","byteList: number[]","data","S: number[]","i","URL","url","newArray: number[]","array3: number[]","array4: number[]","a_bogus","url","r: (string | number)[]","data","baseParamsWithoutFp","url","baseRequestConfig: AxiosRequestConfig","douyinApiUrls","data","GlobalGetData","urlGenerator: ApiUrlGenerator<DouyinDataOptionsMap['评论数据']['opt']>","urlGenerator: ApiUrlGenerator<DouyinDataOptionsMap['指定评论回复数据']['opt']>","mergedData: any[]","lastValid: any","segments: Array<{ start: number, end: number }>","mergedDanmakuList: any[]","finalExtra: any","finalLogPb: any","fetchedData: T[]","lastResponse: any","Err: ErrorDetail","blocks: string[]","data","baseRequestConfig: AxiosRequestConfig","data","GlobalGetData","Err: ErrorDetail & { requestBody: string }","baseRequestConfig: AxiosRequestConfig","xiaohongshuApiUrls","data","baseRequestConfig","error: any","options: ExtendedDouyinOptions<T> | undefined","cookie: string | undefined","config: RequestConfig | undefined","options: ExtendedBilibiliOptions<T> | undefined","options: ExtendedKuaishouOptions<T> | undefined","options: ExtendedXiaohongshuOptions<T> | undefined","path","douyinUtils: douyinUtilsModel","path","kuaishouUtils: kuaishouUtilsModel","path","xiaohongshuUtils: xiaohongshuUtilsModel","options","amagiClient: typeof createAmagiClient","Client: typeof CreateApp","amagi: typeof Client"],"sources":["../../src/model/logger.ts","../../src/types/NetworksConfigType.ts","../../src/validation/utils.ts","../../src/validation/bilibili.ts","../../src/validation/douyin.ts","../../src/validation/kuaishou.ts","../../src/platform/xiaohongshu/sign/index.ts","../../src/platform/xiaohongshu/API.ts","../../src/validation/xiaohongshu.ts","../../src/validation/index.ts","../../src/model/networks.ts","../../src/platform/defaultConfigs.ts","../../src/platform/bilibili/API.ts","../../src/platform/bilibili/BilibiliApi.ts","../../src/platform/bilibili/sign/bv2av.ts","../../src/platform/bilibili/sign/wbi.ts","../../src/utils/errors.ts","../../src/middleware/validation.ts","../../src/platform/bilibili/routes.ts","../../src/platform/bilibili/index.ts","../../src/platform/bilibili/qtparam.ts","../../src/platform/bilibili/getdata.ts","../../src/platform/douyin/sign/a_bogus.ts","../../src/platform/douyin/sign/x_bogus.ts","../../src/platform/douyin/sign/index.ts","../../src/platform/douyin/API.ts","../../src/platform/douyin/getdata.ts","../../src/platform/kuaishou/API.ts","../../src/platform/kuaishou/getdata.ts","../../src/platform/xiaohongshu/getdata.ts","../../src/model/DataFetchers.ts","../../src/platform/douyin/DouyinApi.ts","../../src/platform/douyin/routes.ts","../../src/platform/douyin/index.ts","../../src/platform/kuaishou/KuaishouApi.ts","../../src/platform/kuaishou/routes.ts","../../src/platform/kuaishou/index.ts","../../src/platform/xiaohongshu/XiaohongshuApi.ts","../../src/platform/xiaohongshu/routes.ts","../../src/platform/xiaohongshu/index.ts","../../src/server/index.ts","../../src/types/BilibiliAPIParams.ts","../../src/types/ReturnDataType/Bilibili/Dynamic/index.ts","../../src/types/ReturnDataType/Bilibili/DynamicInfo.ts","../../src/index.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\nimport url from 'node:url'\n\nimport { Chalk, ChalkInstance } from 'chalk'\nimport express from 'express'\nimport type { Logger, LogLevel } from 'log4js'\nimport type * as Log4js from 'log4js'\n\n/**\n * 动态获取 log4js 库\n * 优先使用 node-karin/log4js (Karin 环境)\n * 失败则回退到 log4js (独立环境,通过别名映射到 @karinjs/log4js)\n */\nconst getLog4js = async (): Promise<typeof Log4js> => {\n try {\n const id = 'node-karin/log4js'\n const lib = await import(id)\n return lib.default as unknown as typeof Log4js\n } catch {\n const lib = await import('log4js')\n return (lib.default || lib) as unknown as typeof Log4js\n }\n}\n\nconst log4jsPromise = getLog4js()\n\n/** 获取包的绝对路径 */\nconst getPackageLogsPath = () => {\n const currentFileUrl = import.meta.url\n const currentFilePath = url.fileURLToPath(currentFileUrl)\n const currentDir = path.dirname(currentFilePath)\n\n let packageRoot = currentDir\n\n while (packageRoot !== path.dirname(packageRoot)) {\n if (fs.existsSync(path.join(packageRoot, 'package.json'))) {\n break\n }\n packageRoot = path.dirname(packageRoot)\n }\n\n // 确保 logs 目录存在\n const logsDir = path.join(packageRoot, 'logs')\n try {\n if (!fs.existsSync(logsDir)) {\n fs.mkdirSync(logsDir, { recursive: true })\n }\n } catch (error) {\n // 忽略创建目录错误,可能没有权限或者是在只读文件系统中\n // 在这种情况下,我们可能无法写入日志文件,但至少不会让程序崩溃\n }\n\n return logsDir\n}\n\nconst logsPath = getPackageLogsPath()\n\n/** 获取日志级别,优先使用环境变量,默认为 info */\nconst getLogLevel = (): string => {\n const logLevel = process.env.LOG_LEVEL ?? 'info'\n return logLevel\n}\n\nconst currentLogLevel = getLogLevel()\n\n/** 初始化 logger 配置 */\nexport const initLogger = () => {\n log4jsPromise.then(log4js => {\n log4js.configure({\n appenders: {\n console: {\n type: 'stdout',\n layout: {\n type: 'pattern',\n pattern: '%[[amagi][%d{hh:mm:ss.SSS}][%4.4p]%] %m'\n }\n },\n command: {\n type: 'dateFile',\n filename: path.join(logsPath, 'application', 'command'),\n pattern: 'yyyy-MM-dd.log',\n numBackups: 15,\n alwaysIncludePattern: true,\n layout: {\n type: 'pattern',\n pattern: '[%d{hh:mm:ss.SSS}][%4.4p] %m'\n }\n },\n httpConsole: {\n type: 'stdout',\n layout: {\n type: 'pattern',\n pattern: '%[[amagi][%d{hh:mm:ss.SSS}][HTTP]%] %m'\n }\n },\n httpRequest: {\n type: 'dateFile',\n filename: path.join(logsPath, 'http', 'requests'),\n pattern: 'yyyy-MM-dd.log',\n numBackups: 30,\n alwaysIncludePattern: true,\n layout: {\n type: 'pattern',\n pattern: '[%d{hh:mm:ss.SSS}][%4.4p] %m'\n }\n }\n },\n categories: {\n default: { appenders: ['console', 'command'], level: currentLogLevel as LogLevel },\n http: { appenders: ['httpConsole', 'httpRequest'], level: 'debug' }\n },\n pm2: true\n })\n })\n}\n\nclass CustomLogger {\n private logger: Logger | undefined\n private queue: Array<[string, any[]]> = []\n public chalk: ChalkInstance\n public red: (text: string) => string\n public green: (text: string) => string\n public yellow: (text: string) => string\n public blue: (text: string) => string\n public magenta: (text: string) => string\n public cyan: (text: string) => string\n public white: (text: string) => string\n public gray: (text: string) => string\n\n constructor (name: string) {\n log4jsPromise.then(log4js => {\n this.logger = log4js.getLogger(name)\n this.flush()\n })\n this.chalk = new Chalk()\n this.red = this.chalk.red\n this.green = this.chalk.green\n this.yellow = this.chalk.yellow\n this.blue = this.chalk.blue\n this.magenta = this.chalk.magenta\n this.cyan = this.chalk.cyan\n this.white = this.chalk.white\n this.gray = this.chalk.gray\n }\n\n private flush () {\n if (!this.logger) return\n while (this.queue.length) {\n const [method, args] = this.queue.shift()!\n // @ts-expect-error 动态调用\n this.logger[method](...args)\n }\n }\n\n private proxy (method: string, args: any[]) {\n if (this.logger) {\n // @ts-expect-error 动态调用\n this.logger[method](...args)\n } else {\n this.queue.push([method, args])\n }\n }\n\n // 代理 log4js.Logger 的方法\n public info (message: any, ...args: any[]): void {\n this.proxy('info', [message, ...args])\n }\n\n public warn (message: any, ...args: any[]): void {\n this.proxy('warn', [message, ...args])\n }\n\n public error (message: any, ...args: any[]): void {\n this.proxy('error', [message, ...args])\n }\n\n public mark (message: any, ...args: any[]): void {\n this.proxy('mark', [message, ...args])\n }\n\n public debug (message: any, ...args: any[]): void {\n this.proxy('debug', [message, ...args])\n }\n}\n\nconst logger: CustomLogger = new CustomLogger('default')\nconst httpLogger: CustomLogger = new CustomLogger('http')\n\nexport { httpLogger, logger }\n\n/**\n * 创建一个日志中间件,用于记录特定请求的详细信息\n * @param pathsToLog 指定需要记录日志的请求路径数组如果未提供,则记录所有请求的日志\n * @returns\n */\nexport const logMiddleware = (pathsToLog?: string[]): express.RequestHandler => {\n return (req, res, next) => {\n if (!pathsToLog || pathsToLog.some(path => req.url.startsWith(path))) {\n const startTime = Date.now()\n const url = req.url\n const method = req.method\n const clientIP = req.headers['x-forwarded-for'] ?? req.socket.remoteAddress\n const referer = req.headers['referer'] ?? req.headers['referrer'] ?? '-'\n const contentType = req.headers['content-type'] ?? '-'\n const requestSize = req.headers['content-length'] ?? '0'\n const protocol = req.protocol\n const httpVersion = req.httpVersion\n\n res.on('finish', () => {\n const responseTime = Date.now() - startTime\n const statusCode = res.statusCode\n const responseSize = res.get('content-length') ?? '0'\n\n const logData = {\n method,\n url,\n statusCode,\n responseTime: `${responseTime}ms`,\n clientIP,\n referer,\n contentType,\n requestSize: `${requestSize}B`,\n responseSize: `${responseSize}B`,\n protocol,\n httpVersion,\n timestamp: new Date().toISOString()\n }\n\n httpLogger.debug(JSON.stringify(logData))\n // httpLogger.debug(`[${method}] ${url} | Status: ${statusCode} | Time: ${responseTime}ms | IP: ${clientIP} | Size: ${requestSize}B→${responseSize}B`)\n })\n }\n\n next()\n }\n}\n","export type NetworksConfigType = {\n /**\n * 请求地址\n */\n url: string\n /**\n * 请求方法\n */\n method?: string\n /**\n * 请求头\n */\n headers?: any\n /**\n * 返回数据类型,默认json\n */\n responseType?: string\n /**\n * 请求体\n */\n body?: object | string\n /**\n * 超时时间,单位毫秒\n */\n timeout?: number\n /**\n * 默认跟随重定向到: 'follow',不跟随: manual\n */\n redirect?: RequestRedirect\n /**\n * 拓展参数,该次请求数据什么数据类型,注意是平台接口的类型定义,不是请求参数\n */\n methodType?: string\n}\n\n/** API标准化HTTP请求错误类型 */\nexport type ErrorDetail = {\n /**\n * 错误描述信息\n */\n errorDescription: string\n /**\n * 请求类型\n */\n requestType: string\n /**\n * 请求URL地址\n */\n requestUrl: string\n /**\n * 接口响应数据的 code 属性\n * 个别平台可能不存在\n */\n responseCode?: string\n}\n\n/** 未知错误 */\nexport enum amagiAPIErrorCode {\n /** 未知错误 */\n UNKNOWN = 'UNKNOWN_ERROR'\n}\n\n/** 抖音平台API错误码 */\nexport enum douoyinAPIErrorCode {\n /** Cookie无效或已过期 */\n COOKIE = 'INVALID_COOKIE',\n /** 内容被隐藏或下架 */\n FILTER = 'CONTENT_FILTERED',\n /** 当前用户未开播 */\n NOT_LIVE = 'USER_NOT_LIVE',\n /** 未知错误 */\n UNKNOWN = amagiAPIErrorCode.UNKNOWN\n}\n\n/** B站平台API错误码 */\nexport enum bilibiliAPIErrorCode {\n /** 应用程序不存在或已被封禁 */\n APP_NOT_FOUND = '-1',\n /** Access Key 错误 */\n ACCESS_KEY_ERROR = '-2',\n /** API 校验密匙错误 */\n API_KEY_ERROR = '-3',\n /** 调用方对该Method没有权限 */\n METHOD_NOT_PERMITTED = '-4',\n /** 账号未登录 */\n NOT_LOGGED_IN = '-101',\n /** 账号被封停 */\n ACCOUNT_BANNED = '-102',\n /** 积分不足 */\n POINTS_INSUFFICIENT = '-103',\n /** 硬币不足 */\n COINS_INSUFFICIENT = '-104',\n /** 验证码错误 */\n CAPTCHA_ERROR = '-105',\n /** 账号非正式会员或在适应期 */\n MEMBERSHIP_LIMITED = '-106',\n /** 应用不存在或者被封禁 */\n APP_BANNED = '-107',\n /** 未绑定手机 */\n PHONE_NOT_BOUND = '-108',\n /** 未绑定手机 */\n PHONE_NOT_BOUND_2 = '-110',\n /** csrf 校验失败 */\n CSRF_ERROR = '-111',\n /** 系统升级中 */\n SYSTEM_UPDATING = '-112',\n /** 账号尚未实名认证 */\n NOT_REAL_NAME_VERIFIED = '-113',\n /** 请先绑定手机 */\n NEED_BIND_PHONE = '-114',\n /** 请先完成实名认证 */\n NEED_REAL_NAME_VERIFICATION = '-115',\n /** 木有改动 */\n NO_CHANGE = '-304',\n /** 撞车跳转 */\n CONFLICT_REDIRECT = '-307',\n /** 风控校验失败 (UA 或 wbi 参数不合法) */\n RISK_CONTROL_FAILED = '-352',\n /** 请求错误 */\n BAD_REQUEST = '-400',\n /** 未认证 (或非法请求) */\n UNAUTHORIZED = '-401',\n /** 访问权限不足 */\n FORBIDDEN = '-403',\n /** 啥都木有 */\n NOT_FOUND = '-404',\n /** 不支持该方法 */\n METHOD_NOT_ALLOWED = '-405',\n /** 冲突 */\n CONFLICT = '-409',\n /** 请求被拦截 (客户端 ip 被服务端风控) */\n IP_BLOCKED = '-412',\n /** 服务器错误 */\n SERVER_ERROR = '-500',\n /** 过载保护,服务暂不可用 */\n SERVICE_UNAVAILABLE = '-503',\n /** 服务调用超时 */\n GATEWAY_TIMEOUT = '-504',\n /** 超出限制 */\n RATE_LIMITED = '-509',\n /** 上传文件不存在 */\n FILE_NOT_FOUND = '-616',\n /** 上传文件太大 */\n FILE_TOO_LARGE = '-617',\n /** 登录失败次数太多 */\n LOGIN_ATTEMPTS_EXCEEDED = '-625',\n /** 用户不存在 */\n USER_NOT_FOUND = '-626',\n /** 密码太弱 */\n WEAK_PASSWORD = '-628',\n /** 用户名或密码错误 */\n INVALID_CREDENTIALS = '-629',\n /** 操作对象数量限制 */\n OBJECT_LIMIT_EXCEEDED = '-632',\n /** 被锁定 */\n ACCOUNT_LOCKED = '-643',\n /** 用户等级太低 */\n USER_LEVEL_TOO_LOW = '-650',\n /** 重复的用户 */\n DUPLICATE_USER = '-652',\n /** Token 过期 */\n TOKEN_EXPIRED = '-658',\n /** 密码时间戳过期 */\n PASSWORD_TIMESTAMP_EXPIRED = '-662',\n /** 地理区域限制 */\n GEO_RESTRICTED = '-688',\n /** 版权限制 */\n COPYRIGHT_RESTRICTED = '-689',\n /** 扣节操失败 */\n REPUTATION_DEDUCTION_FAILED = '-701',\n /** 请求过于频繁,请稍后再试 */\n TOO_MANY_REQUESTS = '-799',\n /** 服务器开小差了 */\n SERVER_TEMPORARILY_UNAVAILABLE = '-8888',\n /** 未知错误 */\n UNKNOWN = 'UNKNOWN'\n}\n\n/** 快手平台API错误码 */\nexport enum kuaishouAPIErrorCode {\n /** Cookie无效或已过期 */\n COOKIE = 'INVALID_COOKIE',\n /** 未知错误 */\n UNKNOWN = amagiAPIErrorCode.UNKNOWN\n}\n\n/** 小红书平台API错误码 */\nexport enum xiaohongshuAPIErrorCode {\n /** Cookie无效或已过期 */\n COOKIE = 'INVALID_COOKIE',\n /** 未知错误 */\n UNKNOWN = amagiAPIErrorCode.UNKNOWN,\n /** 非法请求 */\n ILLEGAL_REQUEST = 500,\n /** 检测到帐号异常,请稍后重试 */\n ACCOUNT_ABNORMAL = 300011,\n /** 网络连接异常,请检查网络设置后重试 */\n NETWORK_ERROR = 300012,\n /** 访问频次异常,请勿频繁操作 */\n FREQUENCY_ERROR = 300013,\n /** 浏览器异常,请尝试更换浏览器后重试 */\n BROWSER_ERROR = 300015\n}\n","import zod from 'zod'\n\n/**\n * 智能数字转换器 - 自动处理字符串到数字的转换并提供自定义错误信息\n * @param errorMessage - 自定义错误信息\n * @param minValue - 最小值限制(可选,默认为1)\n * @param isInteger - 是否要求整数(可选,默认为false)\n * @returns Zod数字验证器\n */\nexport function smartNumber (errorMessage: string, minValue?: number, isInteger?: boolean): zod.ZodCoercedNumber<unknown>\nexport function smartNumber (errorMessage: string, minValue: number = 1, isInteger: boolean = false): zod.ZodCoercedNumber<unknown> {\n if (isInteger) {\n return zod.coerce.number({ error: errorMessage })\n .int({ error: `${errorMessage.replace('不能为空', '')}必须是整数,不能包含小数` })\n .min(minValue, { error: `${errorMessage.replace('不能为空', '')}必须大于等于${minValue}` })\n } else {\n return zod.coerce.number({ error: errorMessage })\n .min(minValue, { error: `${errorMessage.replace('不能为空', '')}必须大于等于${minValue}` })\n }\n}\n\n/**\n * 智能整数转换器 - 专门用于整数类型的转换\n * @param errorMessage - 自定义错误信息\n * @param minValue - 最小值限制(可选,默认为0)\n * @returns Zod整数验证器\n */\nexport const smartInteger = (errorMessage: string, minValue: number = 0): zod.ZodCoercedNumber<unknown> => {\n return smartNumber(errorMessage, minValue, true)\n}\n\n/**\n * 智能正整数转换器 - 专门用于正整数类型的转换\n * @param errorMessage - 自定义错误信息\n * @returns Zod正整数验证器\n */\nexport const smartPositiveInteger = (errorMessage: string): zod.ZodCoercedNumber<unknown> => {\n return smartNumber(errorMessage, 1, true)\n}\n\n/**\n * 从页面HTML中提取用户信息\n * @param html - 包含用户页面HTML的字符串\n * @returns 提取到的用户信息对象或null\n */\nexport const extractCreatorInfoFromHtml = (html: string) => {\n // 匹配包含初始化状态的script标签\n const match = html.match(/<script>window\\.__INITIAL_STATE__=(.+)<\\/script>/m)\n if (!match) {\n return null\n }\n\n try {\n // 替换undefined为null并解析JSON\n const jsonStr = match[1].replace(/:undefined/g, ':null')\n const info = JSON.parse(jsonStr)\n\n // 提取并返回用户页面数据\n return info?.user?.userPageData ?? null\n } catch (error) {\n // 处理JSON解析错误\n console.error('解析用户信息失败:', error)\n return null\n }\n}\n","import { BilibiliMethodOptionsMap } from 'amagi/types/BilibiliAPIParams'\nimport zod from 'zod'\n\nimport { smartNumber } from './utils'\n\nexport const BilibiliVideoParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['VideoInfoParams']> = zod.object({\n methodType: zod.literal('单个视频作品数据', { error: '方法类型必须是\"单个视频作品数据\"' }),\n bvid: zod.string({ error: 'BVID必须是字符串' }).min(1, { error: 'BVID不能为空' })\n})\n\nexport const BilibiliVideoDownloadParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['VideoStreamParams']> = zod.object({\n methodType: zod.literal('单个视频下载信息数据', { error: '方法类型必须是\"单个视频下载信息数据\"' }),\n avid: smartNumber('AVID不能为空', 1, true),\n cid: smartNumber('CID不能为空', 1, true)\n})\n\nexport const BilibiliCommentParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['CommentParams']> = zod.object({\n methodType: zod.literal('评论数据', { error: '方法类型必须是\"评论数据\"' }),\n oid: zod.string({ error: 'OID必须是字符串' }).min(1, { error: 'OID不能为空' }),\n type: smartNumber('评论类型不能为空', 1, true)\n .refine(\n (val) => [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 33].includes(val),\n { error: '无效的评论区类型' }\n ),\n number: zod.coerce.number({ error: '评论数量必须是数字' })\n .int({ error: '评论数量必须是整数' })\n .positive({ error: '评论数量必须是正数' })\n .default(20)\n .optional(),\n pn: zod.coerce.number({ error: '页码必须是数字' })\n .int({ error: '页码必须是整数' })\n .positive({ error: '页码必须是正数' })\n .default(1)\n .optional()\n})\n\nexport const BilibiliCommentReplyParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['CommentReplyParams']> = zod.object({\n methodType: zod.literal('指定评论的回复', { error: '方法类型必须是\"指定评论的回复\"' }),\n oid: zod.string({ error: 'OID必须是字符串' }).min(1, { error: 'OID不能为空' }),\n type: smartNumber('评论类型不能为空', 1, true)\n .refine(\n (val) => [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 33].includes(val),\n { error: '无效的评论区类型' }\n ),\n root: zod.string({ error: '根评论ID必须是字符串' }).min(1, { error: '根评论ID不能为空' }),\n number: zod.coerce.number({ error: '评论数量必须是数字' })\n .int({ error: '评论数量必须是整数' })\n .positive({ error: '评论数量必须是正数' })\n .default(20)\n .optional(),\n pn: zod.coerce.number({ error: '页码必须是数字' })\n .int({ error: '页码必须是整数' })\n .positive({ error: '页码必须是正数' })\n .default(1)\n .optional()\n})\n\nexport const BilibiliUserParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['UserParams']> = zod.object({\n methodType: zod.enum(['用户主页数据', '用户主页动态列表数据', '获取UP主总播放量', '用户空间详细信息'], {\n error: '方法类型必须是指定的枚举值之一'\n }),\n host_mid: smartNumber('UP主UID不能为空', 1, true)\n})\n\nexport const BilibiliEmojiParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['EmojiParams']> = zod.object({\n methodType: zod.literal('Emoji数据', { error: '方法类型必须是\"Emoji数据\"' })\n})\n\nexport const BilibiliBangumiInfoParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['BangumiInfoParams']> = zod.object({\n methodType: zod.literal('番剧基本信息数据', { error: '方法类型必须是\"番剧基本信息数据\"' }),\n ep_id: zod.string({ error: '番剧EP ID必须是字符串' }).min(1, { error: '番剧EP ID不能为空' }).optional(),\n season_id: zod.string({ error: '番剧季度ID必须是字符串' }).optional()\n}).refine(\n (data) => data.ep_id ?? data.season_id,\n {\n error: 'ep_id 和 season_id 至少需要提供一个',\n path: ['ep_id']\n }\n)\n\nexport const BilibiliBangumiStreamParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['BangumiStreamParams']> = zod.object({\n methodType: zod.literal('番剧下载信息数据', { error: '方法类型必须是\"番剧下载信息数据\"' }),\n cid: smartNumber('CID不能为空', 1, true),\n ep_id: zod.string({ error: '番剧EP ID必须是字符串' }).min(1, { error: '番剧EP ID不能为空' })\n})\n\nexport const BilibiliDynamicParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['DynamicParams']> = zod.object({\n methodType: zod.enum(['动态详情数据', '动态卡片数据'], {\n error: '方法类型必须是\"动态详情数据\"或\"动态卡片数据\"'\n }),\n dynamic_id: zod.string({ error: '动态ID必须是字符串' }).min(1, { error: '动态ID不能为空' })\n})\n\nexport const BilibiliLiveParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['LiveRoomParams']> = zod.object({\n methodType: zod.enum(['直播间信息', '直播间初始化信息'], {\n error: '方法类型必须是\"直播间信息\"或\"直播间初始化信息\"'\n }),\n room_id: zod.string({ error: '直播间ID必须是字符串' }).min(1, { error: '直播间ID不能为空' })\n})\n\nexport const BilibiliLoginParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['LoginBaseInfoParams']> = zod.object({\n methodType: zod.literal('登录基本信息', { error: '方法类型必须是\"登录基本信息\"' })\n})\n\nexport const BilibiliQrcodeParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['GetQrcodeParams']> = zod.object({\n methodType: zod.literal('申请二维码', { error: '方法类型必须是\"申请二维码\"' })\n})\n\nexport const BilibiliQrcodeStatusParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['QrcodeParams']> = zod.object({\n methodType: zod.literal('二维码状态', { error: '方法类型必须是\"二维码状态\"' }),\n qrcode_key: zod.string({ error: '二维码key必须是字符串' }).min(1, { error: '二维码key不能为空' })\n})\n\nexport const BilibiliAv2BvParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['Av2BvParams']> = zod.object({\n methodType: zod.literal('AV转BV', { error: '方法类型必须是\"AV转BV\"' }),\n avid: zod.coerce.number({ error: 'AVID必须是数字' })\n .int({ error: 'AVID必须是整数' })\n .positive({ error: 'AVID必须是正数' })\n})\n\nexport const BilibiliBv2AvParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['Bv2AvParams']> = zod.object({\n methodType: zod.literal('BV转AV', { error: '方法类型必须是\"BV转AV\"' }),\n bvid: zod.string({ error: 'BVID必须是字符串' }).min(1, { error: 'BVID不能为空' })\n})\n\nexport const BilibiliArticleParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['ArticleParams']> = zod.object({\n methodType: zod.literal('专栏正文内容', { error: '方法类型必须是\"专栏正文内容\"' }),\n id: zod.string({ error: '专栏ID必须是字符串' }).min(1, { error: '专栏ID不能为空' })\n})\n\nexport const BilibiliArticleCardParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['ArticleCardParams']> = zod.object({\n methodType: zod.literal('专栏显示卡片信息', { error: '方法类型必须是\"专栏显示卡片信息\"' }),\n ids: zod.union([\n zod.array(zod.string({ error: '被查询的 id 列表必须是字符串数组' })).min(1, { error: '被查询的 id 列表不能为空' }),\n zod.string({ error: '被查询的 id 列表必须是字符串' }).min(1, { error: '被查询的 id 列表不能为空' })\n ])\n})\n\nexport const BilibiliArticleInfoParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['ArticleInfoParams']> = zod.object({\n methodType: zod.literal('专栏文章基本信息', { error: '方法类型必须是\"专栏文章基本信息\"' }),\n id: zod.string({ error: '专栏ID必须是字符串' }).min(1, { error: '专栏ID不能为空' })\n})\n\nexport const BilibiliColumnInfoParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['ColumnInfoParams']> = zod.object({\n methodType: zod.literal('文集基本信息', { error: '方法类型必须是\"文集基本信息\"' }),\n id: zod.string({ error: '文集ID必须是字符串' }).min(1, { error: '文集ID不能为空' })\n})\n\nexport const BilibiliApplyCaptchaParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['ApplyVoucherCaptchaParams']> = zod.object({\n methodType: zod.literal('从_v_voucher_申请_captcha', { error: '方法类型必须是\"从_v_voucher_申请_captcha\"' }),\n csrf: zod.string({ error: 'CSRF Token必须是字符串' }).optional(),\n v_voucher: zod.string({ error: '验证码ID必须是字符串' }).min(1, { error: '验证码ID不能为空' })\n})\n\nexport const BilibiliValidateCaptchaParamsSchema: zod.ZodType<BilibiliMethodOptionsMap['ValidateCaptchaParams']> = zod.object({\n methodType: zod.literal('验证验证码结果', { error: '方法类型必须是\"验证验证码结果\"' }),\n csrf: zod.string({ error: 'CSRF Token必须是字符串' }).optional(),\n challenge: zod.string({ error: '验证码challenge必须是字符串' }).min(1, { error: '验证码challenge不能为空' }),\n token: zod.string({ error: '验证码token必须是字符串' }).min(1, { error: '验证码token不能为空' }),\n validate: zod.string({ error: '验证码validate必须是字符串' }).min(1, { error: '验证码validate不能为空' }),\n seccode: zod.string({ error: '验证码seccode必须是字符串' }).min(1, { error: '验证码seccode不能为空' })\n})\n\n// B站参数验证模式映射\nexport const BilibiliValidationSchemas = {\n 单个视频作品数据: BilibiliVideoParamsSchema,\n 单个视频下载信息数据: BilibiliVideoDownloadParamsSchema,\n 评论数据: BilibiliCommentParamsSchema,\n 指定评论的回复: BilibiliCommentReplyParamsSchema,\n 用户主页数据: BilibiliUserParamsSchema,\n 用户主页动态列表数据: BilibiliUserParamsSchema,\n 用户空间详细信息: BilibiliUserParamsSchema,\n Emoji数据: BilibiliEmojiParamsSchema,\n 番剧基本信息数据: BilibiliBangumiInfoParamsSchema,\n 番剧下载信息数据: BilibiliBangumiStreamParamsSchema,\n 动态详情数据: BilibiliDynamicParamsSchema,\n 动态卡片数据: BilibiliDynamicParamsSchema,\n 直播间信息: BilibiliLiveParamsSchema,\n 直播间初始化信息: BilibiliLiveParamsSchema,\n 登录基本信息: BilibiliLoginParamsSchema,\n 申请二维码: BilibiliQrcodeParamsSchema,\n 二维码状态: BilibiliQrcodeStatusParamsSchema,\n 获取UP主总播放量: BilibiliUserParamsSchema,\n AV转BV: BilibiliAv2BvParamsSchema,\n BV转AV: BilibiliBv2AvParamsSchema,\n 专栏正文内容: BilibiliArticleParamsSchema,\n 专栏显示卡片信息: BilibiliArticleCardParamsSchema,\n 专栏文章基本信息: BilibiliArticleInfoParamsSchema,\n 文集基本信息: BilibiliColumnInfoParamsSchema,\n 从_v_voucher_申请_captcha: BilibiliApplyCaptchaParamsSchema,\n 验证验证码结果: BilibiliValidateCaptchaParamsSchema\n} as const\n\nexport const BilibiliMethodRoutes = {\n 单个视频作品数据: '/fetch_one_video',\n 单个视频下载信息数据: '/fetch_video_playurl',\n 评论数据: '/fetch_work_comments',\n 指定评论的回复: '/fetch_comment_reply',\n 用户主页数据: '/fetch_user_profile',\n 用户主页动态列表数据: '/fetch_user_dynamic',\n 用户空间详细信息: '/fetch_user_space_info',\n Emoji数据: '/fetch_emoji_list',\n 番剧基本信息数据: '/fetch_bangumi_video_info',\n 番剧下载信息数据: '/fetch_bangumi_video_playurl',\n 动态详情数据: '/fetch_dynamic_info',\n 动态卡片数据: '/fetch_dynamic_card',\n 直播间信息: '/fetch_live_room_detail',\n 直播间初始化信息: '/fetch_liveroom_def',\n 登录基本信息: '/login_basic_info',\n 申请二维码: '/new_login_qrcode',\n 二维码状态: '/check_qrcode',\n 获取UP主总播放量: '/fetch_user_full_view',\n AV转BV: '/av_to_bv',\n BV转AV: '/bv_to_av',\n 专栏正文内容: '/fetch_article_content',\n 专栏显示卡片信息: '/fetch_article_card',\n 专栏文章基本信息: '/fetch_article_info',\n 文集基本信息: '/fetch_column_info',\n 从_v_voucher_申请_captcha: '/apply_captcha',\n 验证验证码结果: '/validate_captcha'\n} as const\n\nexport type BilibiliMethodType = keyof typeof BilibiliValidationSchemas\n","import { DouyinMethodOptionsMap } from 'amagi/types/DouyinAPIParams'\nimport zod from 'zod'\n\nimport { smartPositiveInteger } from './utils'\n\nexport const DouyinWorkParamsSchema: zod.ZodType<DouyinMethodOptionsMap['WorkParams']> = zod.object({\n methodType: zod.enum(['视频作品数据', '图集作品数据', '合辑作品数据', '聚合解析'], {\n error: '方法类型必须是指定的枚举值之一'\n }),\n aweme_id: zod.string({ error: '视频ID必须是字符串' }).min(1, { error: '视频ID不能为空' })\n})\n\nexport const DouyinCommentParamsSchema: zod.ZodType<DouyinMethodOptionsMap['CommentParams']> = zod.object({\n methodType: zod.literal('评论数据', { error: '方法类型必须是\"评论数据\"' }),\n aweme_id: zod.string({ error: '视频ID必须是字符串' }).min(1, { error: '视频ID不能为空' }),\n number: smartPositiveInteger('评论数量必须是正整数').optional().default(50),\n cursor: zod.coerce.number({ error: '游标必须是数字' }).int({ error: '游标必须是整数' }).min(0, { error: '游标不能小于0' }).default(0).optional()\n})\n\nexport const DouyinHotWordsParamsSchema: zod.ZodType<DouyinMethodOptionsMap['HotWordsParams']> = zod.object({\n methodType: zod.literal('热点词数据', {\n error: '方法类型必须是\"热点词数据\"'\n }),\n query: zod.string({ error: '搜索词必须是字符串' }).min(1, { error: '搜索词不能为空' })\n})\n\nexport const DouyinSearchParamsSchema: zod.ZodType<DouyinMethodOptionsMap['SearchParams']> = zod.object({\n methodType: zod.literal('搜索数据', {\n error: '方法类型必须是\"搜索数据\"'\n }),\n query: zod.string({ error: '搜索词必须是字符串' }).min(1, { error: '搜索词不能为空' }),\n type: zod.enum(['综合', '用户', '视频'], {\n error: '搜索类型必须是\"综合\"、\"用户\"或\"视频\"'\n }).optional().default('综合'),\n number: smartPositiveInteger('搜索数量必须是正整数').optional().default(10),\n search_id: zod.string({ error: '搜索ID必须是字符串' }).optional()\n})\n\nexport const DouyinCommentReplyParamsSchema: zod.ZodType<DouyinMethodOptionsMap['CommentReplyParams']> = zod.object({\n methodType: zod.literal('指定评论回复数据', { error: '方法类型必须是\"指定评论回复数据\"' }),\n aweme_id: zod.string({ error: '视频ID必须是字符串' }).min(1, { error: '视频ID不能为空' }),\n comment_id: zod.string({ error: '评论ID必须z串' }).min(1, { error: '评论ID不能为空' }),\n number: smartPositiveInteger('评论数量必须是正整数').optional().default(5),\n cursor: zod.coerce.number({ error: '游标必须是数字' }).int({ error: '游标必须是整数' }).min(0, { error: '游标不能小于0' }).default(0).optional()\n})\n\nexport const DouyinUserParamsSchema: zod.ZodType<DouyinMethodOptionsMap['UserParams']> = zod.object({\n methodType: zod.enum(['用户主页数据', '用户主页视频列表数据'], {\n error: '方法类型必须是指定的枚举值之一'\n }),\n sec_uid: zod.string({ error: '用户ID必须是字符串' }).min(1, { error: '用户ID不能为空' })\n})\n\nexport const DouyinMusicParamsSchema: zod.ZodType<DouyinMethodOptionsMap['MusicParams']> = zod.object({\n methodType: zod.literal('音乐数据', { error: '方法类型必须是\"音乐数据\"' }),\n music_id: zod.string({ error: '音乐ID必须是字符串' }).min(1, { error: '音乐ID不能为空' })\n})\n\nexport const DouyinLiveRoomParamsSchema: zod.ZodType<DouyinMethodOptionsMap['LiveRoomParams']> = zod.object({\n methodType: zod.literal('直播间信息数据', { error: '方法类型必须是\"直播间信息数据\"' }),\n web_rid: zod.string({ error: '直播间ID必须是字符串' }).min(1, { error: '直播间ID不能为空' }),\n room_id: zod.string({ error: '直播间ID必须是字符串' }).min(1, { error: '直播间ID不能为空' })\n})\n\nexport const DouyinQrcodeParamsSchema: zod.ZodType<DouyinMethodOptionsMap['QrcodeParams']> = zod.object({\n methodType: zod.literal('申请二维码数据', { error: '方法类型必须是\"申请二维码数据\"' }),\n verify_fp: zod.string({ error: 'fp指纹必须是字符串' }).min(1, { error: 'fp指纹不能为空' })\n})\n\nexport const DouyinEmojiListParamsSchema: zod.ZodType<DouyinMethodOptionsMap['EmojiListParams']> = zod.object({\n methodType: zod.literal('Emoji数据', { error: '方法类型必须是\"Emoji数据\"' })\n})\n\nexport const DouyinEmojiProParamsSchema: zod.ZodType<DouyinMethodOptionsMap['EmojiProParams']> = zod.object({\n methodType: zod.literal('动态表情数据', { error: '方法类型必须是\"动态表情数据\"' })\n})\n\nexport const DouyinDanmakuParamsSchema: zod.ZodType<DouyinMethodOptionsMap['DanmakuParams']> = zod.object({\n methodType: zod.literal('弹幕数据', { error: '方法类型必须是\"弹幕数据\"' }),\n aweme_id: zod.string({ error: '视频ID必须是字符串' }).min(1, { error: '视频ID不能为空' }),\n start_time: zod.coerce.number({ error: '开始时间必须是数字' }).int({ error: '开始时间必须是整数' }).min(0, { error: '开始时间不能小于0' }).optional(),\n end_time: zod.coerce.number({ error: '结束时间必须是数字' }).int({ error: '结束时间必须是整数' }).min(0, { error: '结束时间不能小于0' }).optional(),\n duration: zod.coerce.number({ error: '视频时长必须是数字' }).int({ error: '视频时长必须是整数' }).min(0, { error: '视频时长不能小于0' })\n}).refine(\n (data) => {\n if (data.end_time !== undefined) {\n return data.end_time <= data.duration\n }\n return true\n },\n {\n error: '获取弹幕区间的结束时间不能超过视频总时长',\n path: ['end_time']\n }\n).refine(\n (data) => {\n if (data.start_time !== undefined && data.end_time !== undefined) {\n return data.start_time < data.end_time\n }\n return true\n },\n {\n error: '获取弹幕区间的开始时间必须小于结束时间',\n path: ['start_time']\n }\n)\n\n// 抖音参数验证模式映射\nexport const DouyinValidationSchemas = {\n 文字作品数据: DouyinWorkParamsSchema,\n 聚合解析: DouyinWorkParamsSchema,\n 视频作品数据: DouyinWorkParamsSchema,\n 图集作品数据: DouyinWorkParamsSchema,\n 合辑作品数据: DouyinWorkParamsSchema,\n 评论数据: DouyinCommentParamsSchema,\n 用户主页数据: DouyinUserParamsSchema,\n 用户主页视频列表数据: DouyinUserParamsSchema,\n 热点词数据: DouyinHotWordsParamsSchema,\n 搜索数据: DouyinSearchParamsSchema,\n 音乐数据: DouyinMusicParamsSchema,\n 直播间信息数据: DouyinLiveRoomParamsSchema,\n 申请二维码数据: DouyinQrcodeParamsSchema,\n Emoji数据: DouyinEmojiListParamsSchema,\n 动态表情数据: DouyinEmojiProParamsSchema,\n 指定评论回复数据: DouyinCommentReplyParamsSchema,\n 弹幕数据: DouyinDanmakuParamsSchema\n} as const\n\nexport const DouyinMethodRoutes = {\n 聚合解析: '/fetch_one_work',\n 文字作品数据: '/fetch_one_work',\n 视频作品数据: '/fetch_one_work',\n 图集作品数据: '/fetch_one_work',\n 合辑作品数据: '/fetch_one_work',\n 评论数据: '/fetch_work_comments',\n 用户主页数据: '/fetch_user_info',\n 用户主页视频列表数据: '/fetch_user_post_videos',\n 搜索数据: '/fetch_search_info',\n 热点词数据: '/fetch_suggest_words',\n 音乐数据: '/fetch_music_work',\n Emoji数据: '/fetch_emoji_list',\n 动态表情数据: '/fetch_emoji_pro_list',\n 直播间信息数据: '/fetch_user_live_videos',\n 指定评论回复数据: '/fetch_video_comment_replies',\n 弹幕数据: '/fetch_work_danmaku'\n} as const\n\nexport type DouyinMethodType = keyof typeof DouyinValidationSchemas\n","import { KuaishouMethodOptionsMap } from 'amagi/types/KuaishouAPIParams'\nimport zod from 'zod'\n\nexport const KuaishouVideoParamsSchema: zod.ZodType<KuaishouMethodOptionsMap['VideoInfoParams']> = zod.object({\n methodType: zod.literal('单个视频作品数据', { error: '方法类型必须是\"单个视频作品数据\"' }),\n photoId: zod.string({ error: '视频ID必须是字符串' }).min(1, { error: '视频ID不能为空' })\n})\n\nexport const KuaishouCommentParamsSchema: zod.ZodType<KuaishouMethodOptionsMap['CommentParams']> = zod.object({\n methodType: zod.literal('评论数据', { error: '方法类型必须是\"评论数据\"' }),\n photoId: zod.string({ error: '视频ID必须是字符串' }).min(1, { error: '视频ID不能为空' })\n})\n\nexport const KuaishouEmojiParamsSchema: zod.ZodType<KuaishouMethodOptionsMap['EmojiListParams']> = zod.object({\n methodType: zod.literal('Emoji数据', { error: '方法类型必须是\"Emoji数据\"' })\n})\n\n// 快手参数验证模式映射\nexport const KuaishouValidationSchemas = {\n 单个视频作品数据: KuaishouVideoParamsSchema,\n 评论数据: KuaishouCommentParamsSchema,\n Emoji数据: KuaishouEmojiParamsSchema\n} as const\n\nexport const KuaishouMethodRoutes = {\n 单个视频作品数据: '/fetch_one_work',\n 评论数据: '/fetch_work_comments',\n Emoji数据: '/fetch_emoji_list'\n} as const\n\nexport type KuaishouMethodType = keyof typeof KuaishouValidationSchemas\n","import { Xhshow } from '@ikenxuan/xhshow-ts'\n\n/**\n * 小红书签名算法类\n */\nexport class xiaohongshuSign {\n private static client = new Xhshow()\n\n /**\n * 生成GET请求的X-S签名\n * @param path - API路径\n * @param a1Cookie - a1 cookie值\n * @param clientType - 客户端类型,默认为 'xhs-pc-web'\n * @param params - 查询参数对象\n * @returns X-S签名\n */\n static generateXSGet (path: string, a1Cookie: string, clientType: string = 'xhs-pc-web', params: Record<string, any> = {}): string {\n return this.client.signXsGet(path, a1Cookie, clientType, params)\n }\n\n /**\n * 生成POST请求的X-S签名\n * @param path - API路径\n * @param a1Cookie - a1 cookie值\n * @param clientType - 客户端类型,默认为 'xhs-pc-web'\n * @param body - 请求体对象\n * @returns X-S签名\n */\n static generateXSPost (path: string, a1Cookie: string, clientType: string = 'xhs-pc-web', body: Record<string, any> = {}): string {\n return this.client.signXsPost(path, a1Cookie, clientType, body)\n }\n\n /**\n * 生成X-S-Common参数\n * @param cookies - cookie字符串\n * @returns Base64编码的随机字符串\n */\n static generateXSCommon (cookies: string): string {\n return this.client.signXsCommon(cookies)\n }\n\n /**\n * 生成X-T时间戳\n * @returns 当前时间戳字符串\n */\n static generateXT (): number {\n return this.client.getXT()\n }\n\n /**\n * 生成X-B3-Traceid\n * @returns 16位随机字符串\n */\n static generateXB3Traceid (): string {\n return this.client.getB3TraceId()\n }\n\n /**\n * 从cookie字符串中提取a1值\n * @param cookieString - 完整的cookie字符串\n * @returns a1 cookie值\n */\n static extractA1FromCookie (cookieString: string): string {\n const match = cookieString.match(/a1=([^;]+)/)\n return match ? match[1] : ''\n }\n\n /**\n * 生成搜索ID\n * @returns 搜索ID字符串\n */\n static getSearchId = (): string => (BigInt(Date.now()) << 64n) + BigInt(Math.floor(Math.random() * 2147483646)).toString(36)\n}\n","import { XiaohongshuMethodOptionsMap } from 'amagi/types/XiaohongshuAPIParams'\n\nimport { xiaohongshuSign } from './sign'\n\n// 根据 XiaohongshuMethodOptionsMap 创建一个新的类型,去除每个字段中的 methodType\nexport type XiaohongshuMethodOptionsWithoutMethodType = {\n [K in keyof XiaohongshuMethodOptionsMap]: Omit<XiaohongshuMethodOptionsMap[K], 'methodType'>\n}\n\n/**\n * 搜索排序类型枚举\n */\nexport enum SearchSortType {\n /**\n * 默认排序\n */\n GENERAL = 'general',\n\n /**\n * 最受欢迎(按热度降序)\n */\n MOST_POPULAR = 'popularity_descending',\n\n /**\n * 最新发布(按时间降序)\n */\n LATEST = 'time_descending'\n}\n\n/**\n * 搜索笔记类型枚举\n */\nexport enum SearchNoteType {\n /**\n * 默认(全部类型)\n */\n ALL = 0,\n\n /**\n * 仅视频\n */\n VIDEO = 1,\n\n /**\n * 仅图片\n */\n IMAGE = 2\n}\n\n/**\n * 构建查询字符串\n * @param params - 参数对象\n * @returns 查询字符串\n */\nconst buildQueryString = (params: Record<string, any>): string => {\n return Object.entries(params)\n .filter(([_, value]) => value !== undefined && value !== null)\n .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)\n .join('&')\n}\n\n/**\n * 小红书API地址配置\n */\nexport const xiaohongshuApiUrls = {\n /**\n * 获取首页推荐数据的接口地址\n * @param data - 请求参数\n * @returns 完整的接口URL\n */\n 首页推荐数据 (data: XiaohongshuMethodOptionsWithoutMethodType['HomeFeedParams'] = {}) {\n return {\n apiPath: '/api/sns/web/v1/homefeed',\n Url: 'https://edith.xiaohongshu.com/api/sns/web/v1/homefeed',\n Body: {\n cursor_score: data.cursor_score ?? '1.7599348899670024E9',\n num: data.num ?? 33,\n refresh_type: data.refresh_type ?? 3,\n note_index: data.note_index ?? 33,\n category: data.category ?? 'homefeed_recommend',\n search_key: data.search_key ?? '',\n image_formats: ['jpg', 'webp', 'avif']\n }\n }\n },\n\n /**\n * 获取单个笔记数据的接口地址\n * @param data - 请求参数\n * @returns 完整的接口URL\n */\n 单个笔记数据 (data: XiaohongshuMethodOptionsWithoutMethodType['NoteParams']) {\n return {\n apiPath: '/api/sns/web/v1/feed',\n Url: 'https://edith.xiaohongshu.com/api/sns/web/v1/feed',\n Body: {\n source_note_id: data.note_id,\n image_formats: ['jpg', 'webp', 'avif'],\n extra: {\n need_body_topic: '1'\n },\n xsec_source: 'pc_feed',\n xsec_token: data.xsec_token\n }\n }\n },\n\n /**\n * 获取评论数据的接口地址\n * @param data - 请求参数\n * @returns 完整的接口URL\n */\n 评论数据 (data: XiaohongshuMethodOptionsWithoutMethodType['CommentParams']) {\n const baseUrl = 'https://edith.xiaohongshu.com/api/sns/web/v2/comment/page'\n const params = {\n note_id: data.note_id,\n cursor: data.cursor ?? '',\n image_formats: ['jpg', 'webp', 'avif'].join(','),\n xsec_token: data.xsec_token\n }\n return {\n apiPath: '/api/sns/web/v2/comment/page',\n Url: `${baseUrl}?${buildQueryString(params)}`\n }\n },\n\n /**\n * 获取用户数据的接口地址\n * @param data - 请求参数\n * @returns 完整的接口URL\n */\n 用户数据 (data: XiaohongshuMethodOptionsWithoutMethodType['UserParams']) {\n return {\n apiPath: '/api/sns/web/v1/user/otherinfo',\n Url: `https://www.xiaohongshu.com/user/profile/${data.user_id}`\n }\n },\n /**\n * 获取用户笔记数据的接口地址\n * @param data - 请求参数\n * @returns 完整的接口URL\n */\n 用户笔记数据 (data: XiaohongshuMethodOptionsWithoutMethodType['UserNoteParams']) {\n const baseUrl = 'https://edith.xiaohongshu.com/api/sns/web/v1/user_posted'\n const params = {\n user_id: data.user_id,\n cursor: data.cursor ?? '',\n num: data.num ?? 30,\n image_formats: ['jpg', 'webp', 'avif'].join(','),\n xsec_source: 'pc_feed'\n }\n return {\n apiPath: '/api/sns/web/v1/user_posted',\n Url: `${baseUrl}?${buildQueryString(params)}`\n }\n },\n\n /**\n * 获取笔记表情列表的接口地址\n * @param data - 请求参数\n * @returns 完整的接口URL\n */\n 表情列表 (data: XiaohongshuMethodOptionsWithoutMethodType['EmojiListParams']) {\n return {\n apiPath: '/api/im/redmoji/detail',\n Url: 'https://edith.xiaohongshu.com/api/im/redmoji/detail'\n }\n },\n\n /**\n * 搜索笔记的接口地址\n * @param data - 请求参数\n * @returns 完整的接口URL\n */\n 搜索笔记 (data: XiaohongshuMethodOptionsWithoutMethodType['SearchNoteParams']) {\n return {\n apiPath: '/api/sns/web/v1/search/notes',\n Body: {\n keyword: data.keyword,\n page: data.page ?? 1,\n page_size: data.page_size ?? 20,\n sort: SearchSortType.GENERAL,\n note_type: SearchNoteType.ALL,\n search_id: xiaohongshuSign.getSearchId(),\n image_formats: ['jpg', 'webp', 'avif']\n },\n Url: 'https://edith.xiaohongshu.com/api/sns/web/v1/search/notes'\n }\n }\n}\n\n/**\n * 创建小红书API URLs实例\n * @returns 小红书API URLs对象\n */\nexport const createXiaohongshuApiUrls = () => {\n return xiaohongshuApiUrls\n}\n","import { SearchNoteType, SearchSortType } from 'amagi/platform/xiaohongshu/API'\nimport { XiaohongshuMethodOptionsMap } from 'amagi/types/XiaohongshuAPIParams'\nimport zod from 'zod'\n\ntype SearchSortTypeUnion = (typeof SearchSortType)[keyof typeof SearchSortType]\nconst SearchSortTypeValues = Object.values(SearchSortType).filter((v) => typeof v === 'string') as unknown as readonly [SearchSortTypeUnion, ...SearchSortTypeUnion[]]\nconst SearchNoteTypeValues = Object.values(SearchNoteType).filter((v) => typeof v === 'number') as [number, ...number[]]\n\n/**\n * 小红书首页推荐数据参数验证模式\n */\nconst HomeFeedParamsSchema: zod.ZodType<XiaohongshuMethodOptionsMap['HomeFeedParams']> = zod.object({\n methodType: zod.literal('首页推荐数据', { error: '方法类型必须是\"首页推荐数据\"' }),\n cursor_score: zod.string({ error: 'cursor_score必须是字符串' }).optional(),\n num: zod.coerce.number({ error: '数量必须是数字' }).int({ error: '数量必须是整数' }).min(1, { error: '数量不能小于1' }).max(100, { error: '数量不能大于100' }).optional(),\n refresh_type: zod.coerce.number({ error: 'refresh_type必须是数字' }).int({ error: 'refresh_type必须是整数' }).optional(),\n note_index: zod.coerce.number({ error: 'note_index必须是数字' }).int({ error: 'note_index必须是整数' }).optional(),\n category: zod.string({ error: 'category必须是字符串' }).optional(),\n search_key: zod.string({ error: 'search_key必须是字符串' }).optional()\n})\n\n/**\n * 小红书单个笔记数据参数验证模式\n */\nconst NoteParamsSchema: zod.ZodType<XiaohongshuMethodOptionsMap['NoteParams']> = zod.object({\n methodType: zod.literal('单个笔记数据', { error: '方法类型必须是\"单个笔记数据\"' }),\n note_id: zod.string({ error: 'note_id必须是字符串' }),\n xsec_token: zod.string({ error: 'xsec_token必须是字符串' })\n})\n\n/**\n * 小红书评论数据参数验证模式\n */\nconst CommentParamsSchema: zod.ZodType<XiaohongshuMethodOptionsMap['CommentParams']> = zod.object({\n methodType: zod.literal('评论数据', { error: '方法类型必须是\"评论数据\"' }),\n note_id: zod.string({ error: 'note_id必须是字符串' }),\n cursor: zod.string({ error: 'cursor必须是字符串' }).optional(),\n xsec_token: zod.string({ error: 'xsec_token必须是字符串' })\n})\n\n/**\n * 小红书用户数据参数验证模式\n */\nconst UserParamsSchema: zod.ZodType<XiaohongshuMethodOptionsMap['UserParams']> = zod.object({\n methodType: zod.literal('用户数据', { error: '方法类型必须是\"用户数据\"' }),\n user_id: zod.string({ error: 'user_id必须是字符串' })\n})\n\n/**\n * 小红书用户笔记数据参数验证模式\n */\nconst UserNoteParamsSchema: zod.ZodType<XiaohongshuMethodOptionsMap['UserNoteParams']> = zod.object({\n methodType: zod.literal('用户笔记数据', { error: '方法类型必须是\"用户笔记数据\"' }),\n user_id: zod.string({ error: 'user_id必须是字符串' }),\n cursor: zod.string({ error: 'cursor必须是字符串' }).optional(),\n num: zod.coerce.number({ error: '数量必须是数字' }).int({ error: '数量必须是整数' }).min(1, { error: '数量不能小于1' }).max(100, { error: '数量不能大于100' }).optional()\n})\n\nconst EmojiListParamsSchema: zod.ZodType<XiaohongshuMethodOptionsMap['EmojiListParams']> = zod.object({\n methodType: zod.literal('表情列表', { error: '方法类型必须是\"表情列表\"' })\n})\n\n/**\n * 小红书搜索笔记参数验证模式\n */\nconst SearchNoteParamsSchema: zod.ZodType<XiaohongshuMethodOptionsMap['SearchNoteParams']> = zod.object({\n methodType: zod.literal('搜索笔记', { error: '方法类型必须是\"搜索笔记\"' }),\n keyword: zod.string({ error: 'keyword必须是字符串' }),\n page: zod.coerce.number({ error: 'page必须是数字' }).int({ error: 'page必须是整数' }).min(1, { error: 'page不能小于1' }).optional(),\n page_size: zod.coerce.number({ error: 'page_size必须是数字' }).int({ error: 'page_size必须是整数' }).min(1, { error: 'page_size不能小于1' }).max(100, { error: 'page_size不能大于100' }).optional(),\n sort: zod.enum(SearchSortTypeValues, { error: '排序类型不合法' }).optional(),\n note_type: zod.coerce.number({ error: '笔记类型必须是数字' }).int({ error: '笔记类型必须是整数' }).refine((val) => SearchNoteTypeValues.includes(val), { message: '笔记类型不合法' }).optional()\n})\n\n/**\n * 小红书验证模式映射\n */\nexport const XiaohongshuValidationSchemas = {\n 首页推荐数据: HomeFeedParamsSchema,\n 单个笔记数据: NoteParamsSchema,\n 评论数据: CommentParamsSchema,\n 用户数据: UserParamsSchema,\n 用户笔记数据: UserNoteParamsSchema,\n 表情列表: EmojiListParamsSchema,\n 搜索笔记: SearchNoteParamsSchema\n} as const\n\n/**\n * 小红书方法类型\n */\nexport const XiaohongshuMethodRoutes = {\n 首页推荐数据: '/fetch_home_feed',\n 单个笔记数据: '/fetch_one_note',\n 评论数据: '/fetch_note_comments',\n 用户数据: '/fetch_user_profile',\n 用户笔记数据: '/fetch_user_notes',\n 表情列表: '/fetch_emoji_list',\n 搜索笔记: '/fetch_search_notes'\n} as const\n\nexport type XiaohongshuMethodType = keyof typeof XiaohongshuValidationSchemas\n","import { APIErrorType } from 'amagi/types'\nimport zod from 'zod'\n\nimport { BilibiliMethodType, BilibiliValidationSchemas } from './bilibili'\nimport { DouyinMethodType, DouyinValidationSchemas } from './douyin'\nimport { KuaishouMethodType, KuaishouValidationSchemas } from './kuaishou'\nimport { XiaohongshuMethodType, XiaohongshuValidationSchemas } from './xiaohongshu'\n\n/**\n * 基础响应类型\n */\nexport type BaseResponse = {\n /** 响应消息 */\n message: string\n /** 响应状态码 */\n code: number\n}\n\n/**\n * 成功响应类型\n * @template T - 响应数据的类型,默认为any\n */\nexport type SuccessResult<T = any> = BaseResponse & {\n /** 响应状态 */\n success: true\n /** 响应数据,类型由泛型 T 决定 */\n data: T\n /** 成功响应时错误信息为空 */\n error: never\n}\n\n/**\n * 错误响应类型\n */\nexport type ErrorResult = BaseResponse & {\n /** 响应状态 */\n success: false\n /** API 错误类型 */\n error: APIErrorType\n /** 错误响应时数据为空 */\n data: never\n}\n\n/**\n * 通用API响应类型\n * @template T - 成功响应数据的类型,默认为any\n */\nexport type Result<T> = SuccessResult<T> | ErrorResult\n\n/**\n * 通用API响应类型\n * @template T - 成功响应数据的类型,默认为any\n * @deprecated 请使用 Result<T> 替代\n */\nexport type ApiResponse<T> = Result<T>\n\n/**\n * 验证抖音参数\n * @param methodType - 抖音方法类型\n * @param params - 待验证的参数\n * @returns 验证后的参数,符合原始API期望的类型\n */\nexport const validateDouyinParams = <T extends DouyinMethodType> (\n methodType: T,\n params: unknown\n): zod.infer<(typeof DouyinValidationSchemas)[T]> => {\n const schema = DouyinValidationSchemas[methodType]\n const validated = schema.parse(\n typeof params === 'object' && params !== null\n ? { methodType, ...params }\n : { methodType, params }\n )\n return validated as zod.infer<(typeof DouyinValidationSchemas)[T]>\n}\n\n/**\n * 验证哔哩哔哩参数\n * @param methodType - 哔哩哔哩方法类型\n * @param params - 待验证的参数\n * @returns 验证后的参数,符合原始API期望的类型\n */\nexport const validateBilibiliParams = <T extends BilibiliMethodType> (\n methodType: T,\n params: unknown\n): zod.infer<(typeof BilibiliValidationSchemas)[T]> => {\n const schema = BilibiliValidationSchemas[methodType]\n const validated = schema.parse(\n typeof params === 'object' && params !== null\n ? { methodType, ...params }\n : { methodType, params }\n )\n return validated as zod.infer<(typeof BilibiliValidationSchemas)[T]>\n}\n\n/**\n * 验证快手参数\n * @param methodType - 快手方法类型\n * @param params - 待验证的参数\n * @returns 验证后的参数,符合原始API期望的类型\n */\nexport const validateKuaishouParams = <T extends KuaishouMethodType> (\n methodType: T,\n params: unknown\n): zod.infer<(typeof KuaishouValidationSchemas)[T]> => {\n const schema = KuaishouValidationSchemas[methodType]\n const validated = schema.parse(\n typeof params === 'object' && params !== null\n ? { methodType, ...params }\n : { methodType, params }\n )\n return validated as zod.infer<(typeof KuaishouValidationSchemas)[T]>\n}\n\n/**\n * 验证小红书参数\n * @param methodType - 小红书方法类型\n * @param params - 待验证的参数\n * @returns 验证后的参数\n */\nexport const validateXiaohongshuParams = <T extends XiaohongshuMethodType> (\n methodType: T,\n params: unknown\n): zod.infer<(typeof XiaohongshuValidationSchemas)[T]> => {\n const schema = XiaohongshuValidationSchemas[methodType]\n const validated = schema.parse(\n typeof params === 'object' && params !== null\n ? { methodType, ...params }\n : { methodType, params }\n )\n return validated as zod.infer<(typeof XiaohongshuValidationSchemas)[T]>\n}\n\n/**\n * 创建成功响应格式\n * @param data - 响应数据\n * @param message - 响应消息(可选)\n * @param code - 响应状态码(可选,默认200)\n * @returns 格式化的成功API响应对象\n */\nexport const createSuccessResponse = <T> (\n data: T,\n message: string,\n code: number = 200\n): SuccessResult<T> => {\n return {\n success: true,\n data,\n message,\n code,\n error: undefined as never\n }\n}\n\n/**\n * 创建失败响应格式\n * @param error - 错误信息\n * @param message - 详细错误消息(可选)\n * @param code - 错误状态码(可选,默认500)\n * @returns 格式化的错误响应对象\n */\nexport const createErrorResponse = (\n error: APIErrorType,\n message: string,\n code: number = 500,\n data?: unknown\n): ErrorResult => {\n return {\n success: false,\n error,\n message,\n code,\n data: data as never\n }\n}\n\nexport * from './bilibili'\nexport * from './douyin'\nexport * from './kuaishou'\nexport * from './xiaohongshu'\n","import axios, { AxiosError, AxiosRequestConfig, AxiosResponse, RawAxiosResponseHeaders } from 'axios'\n\nimport { amagiAPIErrorCode } from '../types/NetworksConfigType'\nimport { createErrorResponse, ErrorResult } from '../validation'\nimport { logger } from './logger'\n\n/** 可恢复的错误代码列表 */\nconst RECOVERABLE_ERROR_CODES = [\n 'ECONNRESET', // 连接被重置(代理切换、网络切换)\n 'ETIMEDOUT', // 连接超时\n 'ECONNREFUSED', // 连接被拒绝\n 'ENOTFOUND', // DNS解析失败\n 'ENETUNREACH', // 网络不可达\n 'EHOSTUNREACH', // 主机不可达\n 'EPIPE', // 管道破裂\n 'EAI_AGAIN', // DNS临时失败\n 'ECONNABORTED' // 连接中止\n] as const\n\n/** 默认最大重试次数 */\nconst DEFAULT_MAX_RETRIES = 3\n\n/** 重试延迟基数(毫秒) */\nconst RETRY_DELAY_BASE = 1000\n\n/**\n * 判断错误是否可恢复\n * @param error - Axios错误对象\n * @returns 是否可恢复\n */\nconst isRecoverableError = (error: AxiosError): boolean => {\n return RECOVERABLE_ERROR_CODES.includes(error.code as typeof RECOVERABLE_ERROR_CODES[number])\n}\n\n/**\n * 延迟函数\n * @param ms - 延迟毫秒数\n */\nconst delay = (ms: number): Promise<void> => new Promise(resolve => setTimeout(resolve, ms))\n\n/**\n * 创建网络错误响应\n * @param error - 错误对象\n * @param retries - 已重试次数\n * @returns 符合Result类型的错误响应\n */\nconst createNetworkErrorResult = (error: AxiosError, retries: number): ErrorResult => {\n const errorCode = error.code ?? 'UNKNOWN'\n const message = `网络请求失败 [${errorCode}]: ${error.message} (已重试 ${retries} 次)`\n\n return createErrorResponse(\n {\n code: amagiAPIErrorCode.UNKNOWN,\n data: null,\n amagiError: {\n errorDescription: `${error.message} (已重试 ${retries} 次)`,\n requestType: error.config?.method?.toUpperCase() ?? 'UNKNOWN',\n requestUrl: error.config?.url ?? '',\n responseCode: errorCode\n },\n amagiMessage: error.message\n },\n message,\n 500\n )\n}\n\n/**\n * 清理User-Agent中的Edge标识,确保请求兼容性\n * @param userAgent - 原始User-Agent字符串\n * @returns 清理后的User-Agent字符串\n */\nconst cleanUserAgent = (userAgent: string): string => {\n return userAgent.replace(/\\s+Edg\\/[\\d\\.]+/g, '')\n}\n\n/**\n * 执行网络请求并返回数据(带自动重试)\n * @param config - axios请求配置\n * @param maxRetries - 最大重试次数,默认3次\n * @returns 响应数据或错误结果\n */\nexport const fetchData = async <T> (\n config: AxiosRequestConfig<T>,\n maxRetries: number = DEFAULT_MAX_RETRIES\n): Promise<T | ErrorResult> => {\n // 清理请求配置中的User-Agent\n const cleanedConfig = { ...config }\n if (cleanedConfig.headers && cleanedConfig.headers['User-Agent']) {\n cleanedConfig.headers['User-Agent'] = cleanUserAgent(cleanedConfig.headers['User-Agent'] as string)\n }\n\n let lastError: AxiosError | null = null\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n const response = await axios<T>({ ...cleanedConfig, validateStatus: () => true })\n return response.data\n } catch (error) {\n if (error instanceof AxiosError) {\n lastError = error\n\n if (isRecoverableError(error) && attempt < maxRetries) {\n const delayMs = RETRY_DELAY_BASE * Math.pow(2, attempt)\n logger.warn(`网络请求失败 [${error.code}],${delayMs}ms 后进行第 ${attempt + 1} 次重试...`)\n await delay(delayMs)\n continue\n }\n\n logger.error('网络请求失败:', error.message)\n return createNetworkErrorResult(error, attempt)\n }\n throw error\n }\n }\n\n return createNetworkErrorResult(lastError!, maxRetries)\n}\n\nconst normalizeHeaders = (headers: any): Record<string, string | string[]> => {\n if (headers && typeof headers.toJSON === 'function') {\n return headers.toJSON() as Record<string, string | string[]>\n }\n return (headers ?? {}) as Record<string, string | string[]>\n}\n\n/**\n * 执行网络请求并返回完整响应(带自动重试)\n * @param config - axios请求配置\n * @param maxRetries - 最大重试次数,默认3次\n * @returns 完整响应或错误结果\n */\nexport const fetchResponse = async <T = unknown> (\n config: AxiosRequestConfig,\n maxRetries: number = DEFAULT_MAX_RETRIES\n): Promise<AxiosResponse<T> | ErrorResult> => {\n // 清理请求配置中的User-Agent\n const cleanedConfig = { ...config }\n if (cleanedConfig.headers && cleanedConfig.headers['User-Agent']) {\n cleanedConfig.headers['User-Agent'] = cleanUserAgent(cleanedConfig.headers['User-Agent'] as string)\n }\n\n let lastError: AxiosError | null = null\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await axios<T>({ ...cleanedConfig, validateStatus: () => true })\n } catch (error) {\n if (error instanceof AxiosError) {\n lastError = error\n\n if (isRecoverableError(error) && attempt < maxRetries) {\n const delayMs = RETRY_DELAY_BASE * Math.pow(2, attempt)\n logger.warn(`网络请求失败 [${error.code}],${delayMs}ms 后进行第 ${attempt + 1} 次重试...`)\n await delay(delayMs)\n continue\n }\n\n logger.error('网络请求失败:', error.message)\n return createNetworkErrorResult(error, attempt)\n }\n throw error\n }\n }\n\n return createNetworkErrorResult(lastError!, maxRetries)\n}\n\n/**\n * 判断结果是否为网络错误响应\n * @param result - 请求结果\n * @returns 是否为ErrorResult\n * \n * 通过检查 error 字段中的 amagiError 来区分网络错误和业务错误\n */\nexport const isNetworkErrorResult = (result: unknown): result is ErrorResult => {\n if (result === null || typeof result !== 'object') return false\n const obj = result as Record<string, unknown>\n // 检查是否为内部网络错误结构:必须有 success: false 且 error.amagiError 存在\n return obj.success === false &&\n obj.error !== null &&\n typeof obj.error === 'object' &&\n 'amagiError' in (obj.error as Record<string, unknown>)\n}\n\n/**\n * 获取响应头和数据(带自动重试)\n * @param config - axios请求配置\n * @param maxRetries - 最大重试次数,默认3次\n * @returns 包含headers和data的对象,或错误结果\n */\nexport const getHeadersAndData = async <T = any> (\n config: AxiosRequestConfig,\n maxRetries: number = DEFAULT_MAX_RETRIES\n): Promise<{ headers: RawAxiosResponseHeaders, data: T } | ErrorResult> => {\n const response = await fetchResponse<T>(config, maxRetries)\n\n // 检查是否为错误结果\n if ('success' in response && response.success === false) {\n return response\n }\n\n return {\n headers: normalizeHeaders((response as AxiosResponse<T>).headers),\n data: (response as AxiosResponse<T>).data\n }\n}\n","import { RequestConfig } from 'amagi/server'\nimport { AxiosRequestConfig } from 'axios'\n\n/**\n * 根据User-Agent生成对应的Sec-Ch-Ua值\n * @param userAgent - 用户代理字符串\n * @returns 对应的Sec-Ch-Ua值\n */\nconst generateSecChUa = (userAgent: string): string => {\n // 提取Chrome版本号\n const chromeMatch = userAgent.match(/Chrome\\/(\\d+)/)\n const chromeVersion = chromeMatch ? chromeMatch[1] : '125'\n\n return `\"Not_A Brand\";v=\"99\", \"Chromium\";v=\"${chromeVersion}\", \"Google Chrome\";v=\"${chromeVersion}\"`\n}\n\n/**\n * 抖音平台默认请求配置\n * @param cookie - 用户Cookie\n * @param requestConfig - 外部请求配置(优先级最高)\n * @returns 合并后的请求配置\n */\nexport const getDouyinDefaultConfig = (cookie?: string, requestConfig?: RequestConfig): AxiosRequestConfig => {\n // 优先使用外部传入的User-Agent,否则使用默认值\n let finalUserAgent = requestConfig?.headers?.['User-Agent'] ??\n 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36'\n finalUserAgent = finalUserAgent.replace(/\\s+Edg\\/[\\d\\.]+/g, '')\n\n const defHeaders: RequestConfig['headers'] = {\n Accept: 'application/json, text/plain, */*',\n 'Accept-Encoding': 'gzip, deflate, br, zstd',\n 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',\n Cookie: cookie?.trim() ?? '',\n Priority: 'u=1, i',\n Referer: 'https://www.douyin.com/',\n 'Sec-Ch-Ua': generateSecChUa(finalUserAgent),\n 'Sec-Ch-Ua-Mobile': '?0',\n 'Sec-Ch-Ua-Platform': '\"Windows\"',\n 'Sec-Fetch-Dest': 'empty',\n 'Sec-Fetch-Mode': 'cors',\n 'Sec-Fetch-Site': 'same-origin',\n 'User-Agent': finalUserAgent\n }\n\n return {\n method: 'GET',\n timeout: 10000,\n ...requestConfig,\n headers: {\n ...defHeaders,\n ...(requestConfig?.headers ?? {})\n }\n }\n}\n\n/**\n * B站平台默认请求配置\n * @param cookie - 用户Cookie\n * @param requestConfig - 外部请求配置(优先级最高)\n * @returns 合并后的请求配置\n */\nexport const getBilibiliDefaultConfig = (cookie?: string, requestConfig?: RequestConfig): AxiosRequestConfig => {\n // 优先使用外部传入的User-Agent,否则使用默认值\n let finalUserAgent = requestConfig?.headers?.['User-Agent'] ??\n 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36'\n // 清理 Edge 标识,避免被识别\n finalUserAgent = finalUserAgent.replace(/\\s+Edg\\/[\\d.]+/g, '')\n\n const defHeaders: RequestConfig['headers'] = {\n Accept: 'application/json, text/plain, */*',\n 'Accept-Language': 'zh-CN,zh;q=0.9',\n 'Accept-Encoding': 'gzip, deflate, br, zstd',\n 'Cache-Control': 'no-cache',\n Pragma: 'no-cache',\n Referer: 'https://www.bilibili.com/',\n Priority: 'u=1, i',\n 'Sec-Ch-Ua': generateSecChUa(finalUserAgent),\n 'Sec-Ch-Ua-Mobile': '?0',\n 'Sec-Ch-Ua-Platform': '\"Windows\"',\n 'Sec-Fetch-Dest': 'empty',\n 'Sec-Fetch-Mode': 'cors',\n 'Sec-Fetch-Site': 'same-site',\n 'User-Agent': finalUserAgent,\n Cookie: cookie?.trim() ?? ''\n }\n\n return {\n method: 'GET',\n timeout: 10000,\n ...requestConfig,\n headers: {\n ...defHeaders,\n ...(requestConfig?.headers ?? {})\n }\n }\n}\n\n/**\n * 快手平台默认请求配置\n * @param cookie - 用户Cookie\n * @param requestConfig - 外部请求配置(优先级最高)\n * @returns 合并后的请求配置\n */\nexport const getKuaishouDefaultConfig = (cookie?: string, requestConfig?: RequestConfig): AxiosRequestConfig => {\n const defHeaders: RequestConfig['headers'] = {\n Referer: 'https://www.kuaishou.com/new-reco',\n Origin: 'https://www.kuaishou.com',\n Accept: 'application/json, text/plain, */*',\n 'Accept-Encoding': 'gzip, deflate, br, zstd',\n 'Content-Type': 'application/json',\n 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',\n Priority: 'u=0, i',\n 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0',\n Cookie: cookie?.trim() ?? ''\n }\n\n return {\n method: 'POST',\n timeout: 10000,\n ...requestConfig,\n headers: {\n ...defHeaders,\n ...(requestConfig?.headers ?? {})\n }\n }\n}\n\n/**\n * 获取小红书默认配置\n * @param cookie - 用户Cookie\n * @returns 小红书请求配置\n */\nexport const getXiaohongshuDefaultConfig = (cookie?: string) => {\n return {\n headers: {\n accept: 'application/json, text/plain, */*',\n 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',\n 'cache-control': 'no-cache',\n 'content-type': 'application/json;charset=UTF-8',\n pragma: 'no-cache',\n priority: 'u=1, i',\n referer: 'https://www.xiaohongshu.com/',\n 'sec-ch-ua': '\"Microsoft Edge\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"',\n 'sec-ch-ua-mobile': '?0',\n 'sec-ch-ua-platform': '\"Windows\"',\n 'sec-fetch-dest': 'empty',\n 'sec-fetch-mode': 'cors',\n 'sec-fetch-site': 'same-site',\n 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0',\n cookie: cookie ?? ''\n }\n }\n}\n","import { OmitMethodType } from 'amagi/types'\nimport { BilibiliMethodOptionsMap } from 'amagi/types/BilibiliAPIParams'\n\n// 根据 BilibiliMethodOptionsMap 创建一个新的类型,去除每个字段中的 methodType\ntype BilibiliMethodOptionsWithoutMethodType = {\n [K in keyof BilibiliMethodOptionsMap]: OmitMethodType<BilibiliMethodOptionsMap[K]>\n}\n\nclass BiLiBiLiAPI {\n 登录基本信息 () {\n return 'https://api.bilibili.com/x/web-interface/nav'\n }\n\n 视频详细信息 (data: BilibiliMethodOptionsWithoutMethodType['VideoInfoParams']) {\n return `https://api.bilibili.com/x/web-interface/view?bvid=${data.bvid}`\n }\n\n 视频流信息 (data: BilibiliMethodOptionsWithoutMethodType['VideoStreamParams']) {\n return `https://api.bilibili.com/x/player/playurl?avid=${data.avid}&cid=${data.cid}`\n }\n\n /** 评论区类型,type参数详见 [评论区类型代码](https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/comment/readme.md#评论区类型代码) */\n 评论区明细 (data: BilibiliMethodOptionsWithoutMethodType['CommentParams']) {\n // 构建基础参数\n const params = new URLSearchParams({\n oid: data.oid.toString(),\n type: data.type.toString(),\n mode: (data.mode ?? 3).toString(),\n plat: '1',\n seek_rpid: '',\n web_location: '1315875'\n })\n\n // 如果有 pagination_str,添加到参数中\n if (data.pagination_str) {\n params.append('pagination_str', JSON.stringify({ offset: data.pagination_str }))\n } else {\n // 首次请求的默认 pagination_str\n params.append('pagination_str', JSON.stringify({ offset: '' }))\n }\n\n return `https://api.bilibili.com/x/v2/reply/wbi/main?${params.toString()}`\n }\n\n 评论区状态 (data: BilibiliMethodOptionsWithoutMethodType['CommentParams']) {\n return `https://api.bilibili.com/x/v2/reply/subject/description?type=${data.type}&oid=${data.oid}`\n }\n\n /** 指定评论的回复 */\n 指定评论的回复 (data: BilibiliMethodOptionsWithoutMethodType['CommentReplyParams']) {\n return `https://api.bilibili.com/x/v2/reply/reply?type=${data.type}&oid=${data.oid}&root=${data.root}&ps=${data.number}`\n }\n\n 表情列表 () {\n return 'https://api.bilibili.com/x/emote/user/panel/web?business=reply&web_location=0.0'\n }\n\n 番剧明细 (data: BilibiliMethodOptionsWithoutMethodType['BangumiInfoParams']) {\n if (data.ep_id) {\n return `https://api.bilibili.com/pgc/view/web/season?ep_id=${data.ep_id}`\n } else if (data.season_id) {\n return `https://api.bilibili.com/pgc/view/web/season?season_id=${data.season_id}`\n } else {\n throw new Error('拟造接口地址出错,缺少 ep_id 或 season_id 参数')\n }\n }\n\n 番剧视频流信息 (data: BilibiliMethodOptionsWithoutMethodType['BangumiStreamParams']) {\n return `https://api.bilibili.com/pgc/player/web/playurl?cid=${data.cid}&ep_id=${data.ep_id}`\n }\n\n 用户空间动态 (data: BilibiliMethodOptionsWithoutMethodType['UserParams']) {\n const params = new URLSearchParams({\n host_mid: data.host_mid.toString(),\n offset: '',\n platform: 'web',\n features: 'itemOpusStyle,listOnlyfans,opusBigCover,onlyfansVote,forwardListHidden,decorationCard,commentsNewVersion,onlyfansAssetsV2,ugcDelete,onlyfansQaCard,avatarAutoTheme,sunflowerStyle,eva3CardOpus,eva3CardVideo,eva3CardComment'\n })\n return `https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/space?${params.toString()}`\n }\n\n 动态详情 (data: BilibiliMethodOptionsWithoutMethodType['DynamicParams']) {\n return `https://api.bilibili.com/x/polymer/web-dynamic/v1/detail?id=${data.dynamic_id}&features=itemOpusStyle,opusBigCover,onlyfansVote,endFooterHidden,decorationCard,onlyfansAssetsV2,ugcDelete,onlyfansQaCard,editable,opusPrivateVisible,avatarAutoTheme`\n }\n\n 动态卡片信息 (data: BilibiliMethodOptionsWithoutMethodType['DynamicParams']) {\n return `https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/get_dynamic_detail?dynamic_id=${data.dynamic_id}`\n }\n\n 用户名片信息 (data: BilibiliMethodOptionsWithoutMethodType['UserParams']) {\n return `https://api.bilibili.com/x/web-interface/card?mid=${data.host_mid}&photo=true`\n }\n\n 直播间信息 (data: BilibiliMethodOptionsWithoutMethodType['LiveRoomParams']) {\n return `https://api.live.bilibili.com/room/v1/Room/get_info?room_id=${data.room_id}`\n }\n\n 直播间初始化信息 (data: BilibiliMethodOptionsWithoutMethodType['LiveRoomParams']) {\n return `https://api.live.bilibili.com/room/v1/Room/room_init?id=${data.room_id}`\n }\n\n 申请二维码 () {\n return 'https://passport.bilibili.com/x/passport-login/web/qrcode/generate'\n }\n\n 二维码状态 (data: BilibiliMethodOptionsWithoutMethodType['QrcodeParams']) {\n return `https://passport.bilibili.com/x/passport-login/web/qrcode/poll?qrcode_key=${data.qrcode_key}`\n }\n\n 获取UP主总播放量 (data: BilibiliMethodOptionsWithoutMethodType['UserParams']) {\n return `https://api.bilibili.com/x/space/upstat?mid=${data.host_mid}`\n }\n\n 专栏正文内容 (data: BilibiliMethodOptionsWithoutMethodType['ArticleParams']) {\n return `https://api.bilibili.com/x/article/view?id=${data.id}`\n }\n\n 专栏显示卡片信息 (data: BilibiliMethodOptionsWithoutMethodType['ArticleCardParams']) {\n return `https://api.bilibili.com/x/article/cards?ids=${Array.isArray(data.ids) ? data.ids.join(',') : data.ids}`\n }\n\n 专栏文章基本信息 (data: BilibiliMethodOptionsWithoutMethodType['ArticleParams']) {\n return `https://api.bilibili.com/x/article/viewinfo?id=${data.id}`\n }\n\n 文集基本信息 (data: BilibiliMethodOptionsWithoutMethodType['ArticleInfoParams']) {\n return `https://api.bilibili.com/x/article/list/web/articles?id=${data.id}`\n }\n\n 用户空间详细信息 (data: BilibiliMethodOptionsWithoutMethodType['UserParams']) {\n return `https://api.bilibili.com/x/space/wbi/acc/info?mid=${data.host_mid}`\n }\n\n 从_v_voucher_申请_captcha (data: BilibiliMethodOptionsWithoutMethodType['ApplyVoucherCaptchaParams']) {\n return {\n Url: 'https://api.bilibili.com/x/gaia-vgate/v1/register',\n Body: {\n ...(data.csrf !== undefined && { csrf: data.csrf }),\n v_voucher: data.v_voucher\n }\n }\n }\n\n 验证验证码结果 (data: BilibiliMethodOptionsWithoutMethodType['ValidateCaptchaParams']) {\n return {\n Url: 'https://api.bilibili.com/x/gaia-vgate/v1/validate',\n Body: {\n challenge: data.challenge,\n token: data.token,\n validate: data.validate,\n seccode: data.seccode,\n ...(data.csrf !== undefined && { csrf: data.csrf })\n }\n }\n }\n}\n\n/** 该类下的所有方法只会返回拼接好参数后的 Url 地址,需要手动请求该地址以获取数据 */\nexport const bilibiliApiUrls = new BiLiBiLiAPI()\n","import { ConditionalReturnType, ExtendedBilibiliOptions, getBilibiliData, TypeMode } from 'amagi/model/DataFetchers'\nimport { RequestConfig } from 'amagi/server'\nimport {\n BilibiliDataOptionsMap\n} from 'amagi/types'\nimport { Result } from 'amagi/validation'\n\n/**\n * 创建B站API方法的通用工厂函数\n * @template T - B站方法类型键名\n * @param methodType - 方法类型\n * @returns 返回配置好的API方法\n */\nconst createBilibiliApiMethod = <T extends keyof BilibiliDataOptionsMap> (\n methodType: T\n) => {\n return async <M extends TypeMode> (\n options: ExtendedBilibiliOptions<T> & { typeMode?: M },\n cookie?: string\n ): Promise<Result<ConditionalReturnType<BilibiliDataOptionsMap[T]['data'], M>>> => {\n return await getBilibiliData(methodType, options, cookie)\n }\n}\n\n/**\n * 创建绑定cookie的B站API方法工厂函数\n * @template T - B站方法类型键名\n * @param methodType - 方法类型\n * @param cookie - 绑定的cookie\n * @returns 返回绑定了cookie的API方法\n */\nconst createBoundBilibiliApiMethod = <T extends keyof BilibiliDataOptionsMap> (\n methodType: T,\n cookie?: string\n) => {\n return async <M extends TypeMode> (\n options: ExtendedBilibiliOptions<T> & { typeMode?: M }\n ): Promise<Result<ConditionalReturnType<BilibiliDataOptionsMap[T]['data'], M>>> => {\n return await getBilibiliData(methodType, options, cookie)\n }\n}\n\n/**\n * B站相关 API 的命名空间。\n *\n * 部分接口可能不需要 Cookie 但建议传递有效的用户 Cookie,以获取更多数据。\n *\n * 提供了一系列方法,用于与B站相关的 API 进行交互。\n *\n * 每个方法都接受参数和 Cookie,返回 Promise,解析为统一格式的API响应。\n */\nexport const bilibili = {\n /**\n * 获取单个视频作品数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应\n */\n getVideoInfo: createBilibiliApiMethod('单个视频作品数据'),\n\n /**\n * 获取单个视频下载信息数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应\n */\n getVideoStream: createBilibiliApiMethod('单个视频下载信息数据'),\n\n /**\n * 获取评论数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应\n */\n getComments: createBilibiliApiMethod('评论数据'),\n\n /**\n * 获取指定评论的回复数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应\n */\n getCommentReply: createBilibiliApiMethod('指定评论的回复'),\n\n /**\n * 获取用户主页数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应\n */\n getUserProfile: createBilibiliApiMethod('用户主页数据'),\n\n /**\n * 获取用户主页动态列表数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应\n */\n getUserDynamic: createBilibiliApiMethod('用户主页动态列表数据'),\n\n /**\n * 获取 Emoji 数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应\n */\n getEmojiList: createBilibiliApiMethod('Emoji数据'),\n\n /**\n * 获取番剧基本信息数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应\n */\n getBangumiInfo: createBilibiliApiMethod('番剧基本信息数据'),\n\n /**\n * 获取番剧下载信息数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应\n */\n getBangumiStream: createBilibiliApiMethod('番剧下载信息数据'),\n\n /**\n * 获取动态详情数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应\n */\n getDynamicInfo: createBilibiliApiMethod('动态详情数据'),\n\n /**\n * 获取动态卡片数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应\n */\n getDynamicCard: createBilibiliApiMethod('动态卡片数据'),\n\n /**\n * 获取直播间信息\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应\n */\n getLiveRoomDetail: createBilibiliApiMethod('直播间信息'),\n\n /**\n * 获取直播间初始化信息\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应\n */\n getLiveRoomInitInfo: createBilibiliApiMethod('直播间初始化信息'),\n\n /**\n * 获取登录基本信息\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应\n */\n getLoginBasicInfo: createBilibiliApiMethod('登录基本信息'),\n\n /**\n * 申请登录二维码\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应\n */\n getLoginQrcode: createBilibiliApiMethod('申请二维码'),\n\n /**\n * 检查二维码状态\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应\n */\n checkQrcodeStatus: createBilibiliApiMethod('二维码状态'),\n\n /**\n * 获取 UP 主总播放量\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应\n */\n getUserTotalPlayCount: createBilibiliApiMethod('获取UP主总播放量'),\n\n /**\n * 将 AV 号转换为 BV 号\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie (此接口通常不需要)\n * @returns 统一格式的API响应\n */\n convertAvToBv: createBilibiliApiMethod('AV转BV'),\n\n /**\n * 将 BV 号转换为 AV 号\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie (此接口通常不需要)\n * @returns 统一格式的API响应\n */\n convertBvToAv: createBilibiliApiMethod('BV转AV'),\n\n /**\n * 获取专栏正文内容\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应\n */\n getArticleContent: createBilibiliApiMethod('专栏正文内容'),\n\n /**\n * 获取专栏显示卡片信息\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应\n */\n getArticleCard: createBilibiliApiMethod('专栏显示卡片信息'),\n\n /**\n * 获取专栏文章基本信息\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应\n */\n getArticleInfo: createBilibiliApiMethod('专栏文章基本信息'),\n\n /**\n * 获取文集基本信息\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应\n */\n getColumnInfo: createBilibiliApiMethod('文集基本信息'),\n\n /**\n * 用户空间详细信息\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应\n */\n getUserProfileDetail: createBilibiliApiMethod('用户空间详细信息'),\n\n /**\n * 从_v_voucher_申请_captcha\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应\n */\n applyVoucherCaptcha: createBilibiliApiMethod('从_v_voucher_申请_captcha'),\n\n /**\n * 验证验证码结果\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应\n */\n validateCaptcha: createBilibiliApiMethod('验证验证码结果')\n}\n\n/**\n * 创建绑定了cookie的B站API对象\n * @param cookie - 要绑定的cookie(可选)\n * @returns 绑定了cookie的B站API对象,调用时不需要再传递cookie\n */\nexport const createBoundBilibiliApi = (cookie: string, requestConfig: RequestConfig) => {\n return {\n /**\n * 获取单个视频作品数据\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n getVideoInfo: createBoundBilibiliApiMethod('单个视频作品数据', cookie),\n\n /**\n * 获取单个视频下载信息数据\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n getVideoStream: createBoundBilibiliApiMethod('单个视频下载信息数据', cookie),\n\n /**\n * 获取评论数据\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n getComments: createBoundBilibiliApiMethod('评论数据', cookie),\n\n /**\n * 获取指定评论的回复数据\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n getCommentReply: createBoundBilibiliApiMethod('指定评论的回复', cookie),\n\n /**\n * 获取用户主页数据\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n getUserProfile: createBoundBilibiliApiMethod('用户主页数据', cookie),\n\n /**\n * 获取用户主页动态列表数据\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n getUserDynamic: createBoundBilibiliApiMethod('用户主页动态列表数据', cookie),\n\n /**\n * 获取 Emoji 数据\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n getEmojiList: createBoundBilibiliApiMethod('Emoji数据', cookie),\n\n /**\n * 获取番剧基本信息数据\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n getBangumiInfo: createBoundBilibiliApiMethod('番剧基本信息数据', cookie),\n\n /**\n * 获取番剧下载信息数据\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n getBangumiStream: createBoundBilibiliApiMethod('番剧下载信息数据', cookie),\n\n /**\n * 获取动态详情数据\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n getDynamicInfo: createBoundBilibiliApiMethod('动态详情数据', cookie),\n\n /**\n * 获取动态卡片数据\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n getDynamicCard: createBoundBilibiliApiMethod('动态卡片数据', cookie),\n\n /**\n * 获取直播间信息\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n getLiveRoomDetail: createBoundBilibiliApiMethod('直播间信息', cookie),\n\n /**\n * 获取直播间初始化信息\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n getLiveRoomInitInfo: createBoundBilibiliApiMethod('直播间初始化信息', cookie),\n\n /**\n * 获取登录基本信息\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n getLoginBasicInfo: createBoundBilibiliApiMethod('登录基本信息', cookie),\n\n /**\n * 申请登录二维码\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n getLoginQrcode: createBoundBilibiliApiMethod('申请二维码', cookie),\n\n /**\n * 检查二维码状态\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n checkQrcodeStatus: createBoundBilibiliApiMethod('二维码状态', cookie),\n\n /**\n * 获取 UP 主总播放量\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n getUserTotalPlayCount: createBoundBilibiliApiMethod('获取UP主总播放量', cookie),\n\n /**\n * 将 AV 号转换为 BV 号\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n convertAvToBv: createBoundBilibiliApiMethod('AV转BV', cookie),\n\n /**\n * 将 BV 号转换为 AV 号\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n convertBvToAv: createBoundBilibiliApiMethod('BV转AV', cookie),\n\n /**\n * 获取专栏正文内容\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n getArticleContent: createBoundBilibiliApiMethod('专栏正文内容', cookie),\n\n /**\n * 获取专栏显示卡片信息\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n getArticleCard: createBoundBilibiliApiMethod('专栏显示卡片信息', cookie),\n\n /**\n * 获取专栏文章基本信息\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n getArticleInfo: createBoundBilibiliApiMethod('专栏文章基本信息', cookie),\n\n /**\n * 获取文集基本信息\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n getColumnInfo: createBoundBilibiliApiMethod('文集基本信息', cookie),\n\n /**\n * 用户空间详细信息\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n getUserProfileDetail: createBoundBilibiliApiMethod('用户空间详细信息', cookie),\n\n /**\n * 从_v_voucher_申请_captcha\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n applyVoucherCaptcha: createBoundBilibiliApiMethod('从_v_voucher_申请_captcha', cookie),\n\n /**\n * 验证验证码结果\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n validateCaptcha: createBoundBilibiliApiMethod('验证验证码结果', cookie)\n }\n}\n\n/**\n * 绑定cookie的B站API对象类型\n */\nexport type BoundBilibiliApi = ReturnType<typeof createBoundBilibiliApi>\n","const XOR_CODE = 23442827791579n\nconst MASK_CODE = 2251799813685247n\nconst MAX_AID = 1n << 51n\nconst BASE = 58n\n\nconst data = 'FcwAPNKTMug3GV5Lj7EJnHpWsx4tb8haYeviqBz6rkCy12mUSDQX9RdoZf'\n\n/**\n * av号转bv号\n * @param aid av号\n * @returns\n */\nexport const av2bv = (aid: number) => {\n const bytes = ['B', 'V', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0']\n let bvIndex = bytes.length - 1\n let tmp = (MAX_AID | BigInt(aid)) ^ XOR_CODE\n while (tmp > 0) {\n bytes[bvIndex] = data[Number(tmp % BigInt(BASE))]\n tmp = tmp / BASE\n bvIndex -= 1\n }\n [bytes[3], bytes[9]] = [bytes[9], bytes[3]];\n [bytes[4], bytes[7]] = [bytes[7], bytes[4]]\n return bytes.join('') as `BV1${string}`\n}\n\n/**\n * bv号转av号\n * @param bvid bv号\n * @returns\n */\nexport const bv2av = (bvid: string) => {\n const bvidArr = Array.from(bvid);\n [bvidArr[3], bvidArr[9]] = [bvidArr[9], bvidArr[3]];\n [bvidArr[4], bvidArr[7]] = [bvidArr[7], bvidArr[4]]\n bvidArr.splice(0, 3)\n const tmp = bvidArr.reduce((pre, bvidChar) => pre * BASE + BigInt(data.indexOf(bvidChar)), 0n)\n return Number((tmp & MASK_CODE) ^ XOR_CODE)\n}\n","import crypto from 'node:crypto'\n\nimport axios from 'axios'\n\n/**\n * 混合密钥编码表,用于对 imgKey 和 subKey 进行字符顺序打乱编码\n */\nconst mixinKeyEncTab: readonly number[] = [\n 46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49, 33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40, 61, 26,\n 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11, 36, 20, 34, 44, 52\n]\n\n/**\n * WBI 响应数据接口定义\n */\ntype WbiResponseData = {\n data: {\n wbi_img: {\n img_url: string\n sub_url: string\n }\n }\n}\n\n/**\n * WBI 密钥对接口定义\n */\ntype WbiKeys = {\n img_key: string\n sub_key: string\n}\n\n/**\n * 请求参数类型定义\n */\ntype RequestParams = Record<string, string | number | boolean>\n\n/**\n * 对 imgKey 和 subKey 进行字符顺序打乱编码\n * @param orig - 原始字符串数组,通常是 img_key + sub_key 的字符数组\n * @returns 返回经过编码表打乱后的32位字符串\n */\nconst getMixinKey = (orig: string): string =>\n mixinKeyEncTab\n .map((n) => orig[n])\n .join('')\n .slice(0, 32)\n\n/**\n * 为请求参数进行 WBI 签名\n * @param params - 请求参数对象,键值对形式\n * @param img_key - 图片密钥\n * @param sub_key - 子密钥\n * @returns 返回包含时间戳和签名的查询字符串\n */\nconst encWbi = (params: RequestParams, img_key: string, sub_key: string): string => {\n const mixin_key = getMixinKey(img_key + sub_key)\n const curr_time = Math.round(Date.now() / 1000)\n const chr_filter = /[!'()*]/g\n\n Object.assign(params, { wts: curr_time }) // 添加 wts 字段\n // 按照 key 重排参数\n const query = Object.keys(params)\n .sort()\n .map((key) => {\n // 过滤 value 中的 \"!'()*\" 字符\n const value = params[key].toString().replace(chr_filter, '')\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`\n })\n .join('&')\n\n const wbi_sign = crypto.createHash('md5').update(query + mixin_key).digest('hex') // 计算 w_rid\n\n return `&wts=${curr_time}&w_rid=${wbi_sign}`\n}\n\n/**\n * 获取最新的 img_key 和 sub_key\n * @param cookie - 有效的用户 Cookie 字符串\n * @returns 返回包含 img_key 和 sub_key 的对象\n * @throws 当网络请求失败或响应格式不正确时抛出错误\n */\nconst getWbiKeys = async (cookie: string): Promise<WbiKeys> => {\n const res = await axios('https://api.bilibili.com/x/web-interface/nav', {\n headers: {\n Cookie: cookie\n }\n })\n\n const response: WbiResponseData = res.data as WbiResponseData // 类型断言\n\n // 确保 response 是 WbiResponseData 类型后再解构\n const {\n data: {\n wbi_img: { img_url, sub_url }\n }\n } = response\n\n return {\n img_key: img_url.slice(img_url.lastIndexOf('/') + 1, img_url.lastIndexOf('.')),\n sub_key: sub_url.slice(sub_url.lastIndexOf('/') + 1, sub_url.lastIndexOf('.'))\n }\n}\n\n/**\n * 对请求链接进行 WBI 签名\n * @param BASEURL - 完整的请求地址,可以是字符串或 URL 对象\n * @param cookie - 有效的用户 Cookie 字符串\n * @returns 返回包含 WBI 签名的查询字符串\n * @throws 当获取 WBI 密钥失败或 URL 解析失败时抛出错误\n */\nexport const wbi_sign = async (BASEURL: string | URL, cookie: string): Promise<string> => {\n const web_keys = await getWbiKeys(cookie)\n const url = new URL(BASEURL)\n const params: RequestParams = {}\n\n for (const [key, value] of url.searchParams.entries()) {\n params[key] = value\n }\n\n const query = encWbi(params, web_keys.img_key, web_keys.sub_key)\n return query\n}\n","import zod from 'zod'\n\n/**\n * API错误类\n */\nexport class ApiError extends Error {\n public readonly code: number\n public readonly platform: string\n\n /**\n * 构造API错误\n * @param message - 错误消息\n * @param code - 错误代码\n * @param platform - 平台名称\n */\n constructor (message: string, code: number = 500, platform: string = 'unknown') {\n super(message)\n this.name = 'ApiError'\n this.code = code\n this.platform = platform\n }\n}\n\n/**\n * 参数验证错误类\n */\nexport class ValidationError extends Error {\n public readonly errors: Array<{ field: string; message: string }>\n public readonly requestPath?: string\n\n /**\n * 构造参数验证错误\n * @param message - 错误消息\n * @param errors - 详细错误信息\n * @param requestPath - HTTP请求路径\n */\n constructor (message: string, errors: Array<{ field: string; message: string }>, requestPath?: string) {\n super(message)\n this.name = 'ValidationError'\n this.errors = errors\n this.requestPath = requestPath\n }\n\n /**\n * 从Zod错误创建验证错误\n * @param zodError - Zod验证错误\n * @param requestPath - HTTP请求路径\n * @returns 验证错误实例\n */\n static fromZodError (zodError: zod.ZodError<any>, requestPath?: string): ValidationError {\n const errors = zodError.issues.map(err => ({\n field: err.path.join('.'),\n message: err.message\n }))\n\n return new ValidationError('参数验证失败', errors, requestPath)\n }\n}\n\n/**\n * 处理错误并返回统一格式\n * @param error - 错误对象\n * @param requestPath - HTTP请求路径(可选)\n * @returns 统一的错误响应格式\n */\nexport const handleError = (error: unknown, requestPath?: string): {\n data: null\n message: string\n code: number\n errors?: Array<{ field: string; message: string }>\n platform?: string\n requestPath?: string\n} => {\n if (error instanceof ValidationError) {\n return {\n code: 400,\n message: error.message,\n data: null,\n errors: error.errors,\n requestPath: error.requestPath ?? requestPath\n }\n }\n\n if (error instanceof ApiError) {\n return {\n code: error.code,\n message: error.message,\n data: null,\n platform: error.platform,\n requestPath\n }\n }\n\n if (error instanceof zod.ZodError) {\n const validationError = ValidationError.fromZodError(error, requestPath)\n return handleError(validationError, requestPath)\n }\n\n // 未知错误\n const errorMessage = error instanceof Error ? error.message : '未知错误'\n return {\n code: 500,\n message: errorMessage,\n data: null,\n requestPath\n }\n}\n","import { handleError } from 'amagi/utils/errors'\nimport {\n BilibiliMethodType,\n DouyinMethodType,\n KuaishouMethodType,\n validateBilibiliParams,\n validateDouyinParams,\n validateKuaishouParams,\n validateXiaohongshuParams,\n XiaohongshuMethodType\n} from 'amagi/validation'\nimport { NextFunction, Request, Response } from 'express'\n\n/**\n * 创建通用验证中间件\n * @param validateFn - 验证函数\n * @param methodType - 方法类型\n * @returns Express中间件函数\n */\nexport const createValidationMiddleware = <T> (\n validateFn: (methodType: T, params: unknown) => any,\n methodType: T\n) => {\n return (req: Request, res: Response, next: NextFunction) => {\n try {\n // 合并query和body参数\n const params = { ...req.query, ...req.body }\n\n // 验证参数\n const validatedParams = validateFn(methodType, params)\n\n // 将验证后的参数附加到请求对象\n req.validatedParams = validatedParams\n\n next()\n } catch (error) {\n const errorResponse = handleError(error, req.originalUrl)\n res.status(errorResponse.code || 500).json(errorResponse)\n }\n }\n}\n\n/**\n * 创建抖音参数验证中间件\n * @param methodType - 抖音方法类型\n * @returns Express中间件函数\n */\nexport const createDouyinValidationMiddleware = <T extends DouyinMethodType> (\n methodType: T\n) => createValidationMiddleware(validateDouyinParams, methodType)\n\n/**\n * 创建B站参数验证中间件\n * @param methodType - B站方法类型\n * @returns Express中间件函数\n */\nexport const createBilibiliValidationMiddleware = <T extends BilibiliMethodType> (\n methodType: T\n) => createValidationMiddleware(validateBilibiliParams, methodType)\n\n/**\n * 创建快手参数验证中间件\n * @param methodType - 快手方法类型\n * @returns Express中间件函数\n */\nexport const createKuaishouValidationMiddleware = <T extends KuaishouMethodType> (\n methodType: T\n) => createValidationMiddleware(validateKuaishouParams, methodType)\n\n/**\n * 创建小红书参数验证中间件\n * @param methodType - 小红书方法类型\n * @returns Express中间件函数\n */\nexport const createXiaohongshuValidationMiddleware = <T extends XiaohongshuMethodType> (\n methodType: T\n) => createValidationMiddleware(validateXiaohongshuParams, methodType)\n\n// 扩展Express Request类型\ndeclare global {\n namespace Express {\n interface Request {\n validatedParams?: any\n }\n }\n}\n","import { createBilibiliValidationMiddleware } from 'amagi/middleware/validation'\nimport { getBilibiliData } from 'amagi/model/DataFetchers'\nimport { getBilibiliDefaultConfig } from 'amagi/platform/defaultConfigs'\nimport { RequestConfig } from 'amagi/server'\nimport { BilibiliDataOptionsMap } from 'amagi/types'\nimport { handleError } from 'amagi/utils/errors'\nimport { BilibiliMethodType, Result } from 'amagi/validation'\nimport { BilibiliMethodRoutes } from 'amagi/validation/bilibili'\nimport express from 'express'\n\n/**\n * 创建B站路由处理器\n * @param dataFetcher - B站数据获取函数\n * @param methodType - B站方法类型\n * @param cookie - Cookie字符串\n * @returns Express路由处理器\n */\nconst createBilibiliRouteHandler = <T extends BilibiliMethodType> (\n dataFetcher: <K extends BilibiliMethodType>(\n methodType: K,\n options?: Omit<BilibiliDataOptionsMap[K]['opt'], 'methodType'>,\n cookie?: string,\n requestConfig?: RequestConfig\n ) => Promise<Result<BilibiliDataOptionsMap[T]['data']>>,\n methodType: T,\n cookie: string,\n requestConfig: RequestConfig = getBilibiliDefaultConfig(cookie)\n) => {\n return async (req: any, res: any) => {\n try {\n const result = await dataFetcher(methodType, req.validatedParams, cookie, requestConfig)\n res.json({\n ...result,\n requestPath: req.originalUrl\n })\n } catch (error) {\n const errorResponse = handleError(error)\n res.status(errorResponse.code || 500).json({\n ...errorResponse,\n requestPath: req.originalUrl\n })\n }\n }\n}\n\n/**\n * 创建B站路由\n * @param cookie - B站Cookie\n * @param requestConfig - 可选的请求配置\n * @returns Express路由器\n */\nexport const createBilibiliRoutes = (cookie: string, requestConfig: RequestConfig = getBilibiliDefaultConfig(cookie)): express.Router => {\n const router = express.Router()\n\n for (const [method, path] of Object.entries(BilibiliMethodRoutes)) {\n router.get(path,\n createBilibiliValidationMiddleware(method as BilibiliMethodType),\n createBilibiliRouteHandler(getBilibiliData, method as BilibiliMethodType, cookie, requestConfig)\n )\n }\n\n return router\n}\n","import { bilibiliApiUrls } from './API'\nimport { bilibili } from './BilibiliApi'\nimport { bilibiliErrorCodeMap } from './getdata'\nimport { qtparam } from './qtparam'\nimport { av2bv, bv2av } from './sign/bv2av'\nimport { wbi_sign } from './sign/wbi'\n\nexport * from './BilibiliApi'\nexport * from './routes'\nexport { av2bv, bv2av } from './sign/bv2av'\nexport { bilibiliApiUrls, qtparam, wbi_sign }\nexport { bilibiliErrorCodeMap }\n\ntype bilibiliUtilsModel = {\n /** 签名算法相关 */\n sign: {\n /** WBI签名算法 */\n wbi_sign: typeof import('amagi/platform/bilibili/sign/wbi').wbi_sign,\n /** AV号转BV号 */\n av2bv: typeof import('amagi/platform/bilibili/sign/bv2av').av2bv,\n /** BV号转AV号 */\n bv2av: typeof import('amagi/platform/bilibili/sign/bv2av').bv2av,\n }\n\n /** 该类下的所有方法只会返回拼接好参数后的 Url 地址,需要手动请求该地址以获取数据 */\n bilibiliApiUrls: typeof import('amagi/platform/bilibili/API').bilibiliApiUrls\n\n /**\n * B站相关 API 的命名空间。\n *\n * 部分接口可能不需要 Cookie 但建议传递有效的用户 Cookie,以获取更多数据。\n *\n * 提供了一系列方法,用于与B站相关的 API 进行交互。\n *\n * 每个方法都接受参数和 Cookie,返回 Promise,解析为接口返回的原始数据。\n */\n api: typeof import('amagi/platform/bilibili/BilibiliApi').bilibili\n}\n\n/** B站相关功能模块 (工具集) */\nexport const bilibiliUtils: bilibiliUtilsModel = {\n sign: {\n wbi_sign,\n av2bv,\n bv2av\n },\n bilibiliApiUrls,\n api: bilibili\n}\n","import { fetchData } from 'amagi/model'\nimport { bilibiliApiUrls, wbi_sign } from 'amagi/platform/bilibili'\n\n/**\n * 生成B站视频流请求参数\n * @param BASEURL - 基础请求URL\n * @param cookie - 用户Cookie\n * @returns 包含查询参数、登录状态和VIP状态的对象\n */\nexport const qtparam = async (BASEURL: string, cookie: string) => {\n if (cookie === '') return { QUERY: '&platform=html5', STATUS: '!isLogin' }\n\n const logininfo = await fetchData({ url: bilibiliApiUrls.登录基本信息(), headers: { Cookie: cookie } }) as any\n const sign = await wbi_sign(BASEURL, cookie)\n\n const qn = [6, 16, 32, 64, 74, 80, 112, 116, 120, 125, 126, 127]\n let isvip\n logininfo.data.vipStatus === 1 ? (isvip = true) : (isvip = false)\n\n if (isvip) {\n // fnval = 16(DASH) | 64(HDR) | 128(4K) | 256(杜比音频) | 512(杜比视界) | 1024(8K) | 2048(AV1) = 4048\n const fnval = 4048\n return {\n QUERY: `&fnval=${fnval}&fourk=1&${sign}`,\n STATUS: 'isLogin',\n isvip\n }\n } else {\n // 最高720P\n return {\n QUERY: `&qn=${qn[3]}&fnval=16&${sign}`,\n STATUS: 'isLogin',\n isvip\n }\n }\n}\n","import { fetchData, getHeadersAndData, isNetworkErrorResult, logger } from 'amagi/model'\nimport { getBilibiliDefaultConfig } from 'amagi/platform/defaultConfigs'\nimport { RequestConfig } from 'amagi/server'\nimport {\n BilibiliDataOptionsMap,\n BiliCheckQrcode\n} from 'amagi/types'\nimport { amagiAPIErrorCode, bilibiliAPIErrorCode, ErrorDetail } from 'amagi/types/NetworksConfigType'\nimport { AxiosRequestConfig } from 'axios'\n\nimport { bilibiliApiUrls } from './API'\n/**\n * B站数据获取模块\n *\n * 注意:为避免循环依赖,此文件直接从具体模块导入,而不是从平台 index 文件导入\n * 循环依赖链:DataFetchers → getdata → platform/bilibili → DataFetchers\n */\nimport { qtparam } from './qtparam'\nimport { av2bv, bv2av } from './sign/bv2av'\nimport { wbi_sign } from './sign/wbi'\n\n/**\n * B站数据获取函数\n * @param data - 请求数据参数\n * @param cookie - 用户Cookie\n * @param requestConfig - 外部请求配置(优先级最高)\n * @returns 返回B站数据\n */\nexport const fetchBilibili = async <T extends keyof BilibiliDataOptionsMap> (\n data: BilibiliDataOptionsMap[T]['opt'],\n cookie?: string,\n requestConfig?: RequestConfig\n) => {\n // 直接使用 getBilibiliDefaultConfig 合并配置,它会处理 headers 优先级\n const baseRequestConfig = getBilibiliDefaultConfig(cookie, requestConfig)\n\n switch (data.methodType) {\n case '单个视频作品数据': {\n const INFODATA = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: bilibiliApiUrls.视频详细信息({ bvid: data.bvid })\n })\n return INFODATA\n }\n\n case '单个视频下载信息数据': {\n const BASEURL = bilibiliApiUrls.视频流信息({ avid: data.avid, cid: data.cid })\n const SIGN = await qtparam(BASEURL, baseRequestConfig.headers?.Cookie as string)\n const DATA = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: bilibiliApiUrls.视频流信息({ avid: data.avid, cid: data.cid }) + SIGN.QUERY\n })\n return DATA\n }\n\n case '评论数据': {\n let { oid, number, type, mode, pagination_str, plat, seek_rpid, web_location } = data\n let fetchedComments: any[] = []\n const maxRequestCount = 100 // 设置一个最大请求次数限制\n let requestCount = 0 // 初始化请求计数器\n let tmpresp: any\n let nextPaginationStr = pagination_str // 用于懒加载的分页字符串\n let isEnd = false // 是否到达末尾\n\n // 检查评论区状态\n const checkStatusUrl = bilibiliApiUrls.评论区状态({ oid, type })\n const checkStatusRes = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: checkStatusUrl\n })\n\n if (checkStatusRes.data === null) {\n logger.error('评论区未开放')\n return {\n code: 404,\n message: '评论区未开放',\n data: null\n }\n }\n\n while (fetchedComments.length < Number(number ?? 20) && requestCount < maxRequestCount && !isEnd) {\n // 构建基础URL(不包含WBI签名)\n const baseUrl = bilibiliApiUrls.评论区明细({\n type,\n oid,\n mode: mode ?? 3,\n pagination_str: nextPaginationStr,\n plat: plat ?? 1,\n seek_rpid,\n web_location: web_location ?? '1315875'\n })\n\n // 每次请求都需要进行WBI签名\n const wbiSignQuery = await wbi_sign(baseUrl, baseRequestConfig.headers?.cookie as string)\n const finalUrl = baseUrl + wbiSignQuery\n\n const response = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: finalUrl\n })\n\n tmpresp = response\n\n // 懒加载接口返回的数据结构\n const currentComments = response.data?.replies ?? []\n fetchedComments.push(...currentComments)\n\n // 更新分页信息和结束状态\n if (response.data?.cursor) {\n // 从cursor.pagination_reply.next_offset获取下一页的分页字符串\n nextPaginationStr = response.data.cursor.pagination_reply?.next_offset\n isEnd = response.data.cursor.is_end\n } else {\n isEnd = true\n }\n\n requestCount++\n\n // 如果已经到达末尾或没有更多评论,停止请求\n if (isEnd || currentComments.length === 0 || !nextPaginationStr) {\n logger.info('已到达评论末尾或无更多评论')\n break\n }\n }\n\n const finalResponse = {\n ...tmpresp,\n data: {\n ...tmpresp.data,\n // 去重并限制数量\n replies: Array.from(new Map(fetchedComments.map(item => [item.rpid, item])).values()).slice(0, Number(data.number ?? 20))\n }\n }\n return finalResponse\n }\n\n case '指定评论的回复': {\n return await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: bilibiliApiUrls.指定评论的回复(data)\n })\n }\n\n case 'Emoji数据': {\n return await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: bilibiliApiUrls.表情列表()\n })\n }\n\n case '番剧基本信息数据': {\n /** 提取出ep_id或season_id */\n let id = data.ep_id ?? data.season_id\n /** 参数检查 */\n if (!id) {\n return false\n }\n /** 确定id类型 */\n const idType = id ? id.startsWith('ep') ? 'ep_id' : 'season_id' : 'ep_id'\n\n const newId = idType === 'ep_id' ? id.replace('ep', '') : id.replace('ss', '')\n const INFO = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: bilibiliApiUrls.番剧明细({ [idType]: newId })\n })\n return INFO\n }\n\n case '番剧下载信息数据': {\n const BASEURL = bilibiliApiUrls.番剧视频流信息({ cid: data.cid, ep_id: data.ep_id.replace('ep', '') })\n const SIGN = await qtparam(BASEURL, baseRequestConfig.headers?.cookie as string)\n const DATA = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: bilibiliApiUrls.番剧视频流信息({ cid: data.cid, ep_id: data.ep_id.replace('ep', '') }) + SIGN.QUERY\n })\n\n return DATA\n }\n\n case '用户主页动态列表数据': {\n const { host_mid } = data\n // 检查外部是否已配置 referer\n const hasExternalReferer = requestConfig?.headers &&\n ('referer' in requestConfig.headers || 'Referer' in requestConfig.headers)\n\n const customHeaders = {\n ...baseRequestConfig.headers,\n Origin: 'https://space.bilibili.com',\n // 外部没配置 referer 时,使用用户空间页面作为 referer\n ...(!hasExternalReferer && { Referer: `https://space.bilibili.com/${host_mid}/dynamic` })\n }\n const wbiSignQuery = await wbi_sign(bilibiliApiUrls.用户空间动态({ host_mid }), baseRequestConfig.headers?.cookie)\n const result = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n headers: customHeaders,\n url: bilibiliApiUrls.用户空间动态({ host_mid }) + wbiSignQuery\n })\n return result\n }\n\n case '动态详情数据': {\n // 检查外部是否已配置 referer\n const hasExternalReferer = requestConfig?.headers && 'referer' in requestConfig.headers\n\n const customHeaders = {\n ...baseRequestConfig.headers,\n // 外部没配置 referer 时,移除默认的 referer\n ...(!hasExternalReferer && { Referer: undefined })\n }\n\n const dynamicINFO = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n headers: customHeaders,\n url: bilibiliApiUrls.动态详情({ dynamic_id: data.dynamic_id })\n })\n return dynamicINFO\n }\n\n case '动态卡片数据': {\n const { dynamic_id } = data\n // 检查外部是否已配置 referer\n const hasExternalReferer = requestConfig?.headers && 'referer' in requestConfig.headers\n\n const customHeaders = {\n ...baseRequestConfig.headers,\n // 外部没配置 referer 时,移除默认的 referer\n ...(!hasExternalReferer && { Referer: undefined })\n }\n\n const dynamicINFO_CARD = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n headers: customHeaders,\n url: bilibiliApiUrls.动态卡片信息({ dynamic_id })\n })\n return dynamicINFO_CARD\n }\n\n case '用户主页数据': {\n const { host_mid } = data\n const result = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: bilibiliApiUrls.用户名片信息({ host_mid })\n })\n return result\n }\n\n case '用户空间详细信息': {\n const baseUrl = bilibiliApiUrls.用户空间详细信息({ host_mid: data.host_mid })\n const wbiSignQuery = await wbi_sign(baseUrl, baseRequestConfig.headers?.cookie)\n\n const result = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: bilibiliApiUrls.用户空间详细信息({ host_mid: data.host_mid }) + wbiSignQuery\n })\n return result\n }\n\n case '直播间信息': {\n const result = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: bilibiliApiUrls.直播间信息({ room_id: data.room_id })\n })\n return result\n }\n\n case '直播间初始化信息': {\n const result = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: bilibiliApiUrls.直播间初始化信息({ room_id: data.room_id })\n })\n return result\n }\n\n case '申请二维码': {\n const result = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: bilibiliApiUrls.申请二维码()\n })\n return result\n }\n\n case '二维码状态': {\n try {\n const result = await getHeadersAndData<BiliCheckQrcode>({\n ...baseRequestConfig,\n url: bilibiliApiUrls.二维码状态({ qrcode_key: data.qrcode_key })\n })\n\n // 处理网络层错误(自动重试后仍失败)\n if (isNetworkErrorResult(result)) {\n const networkError = new Error(result.error.amagiError.errorDescription)\n Object.assign(networkError, {\n code: result.error.code,\n data: null,\n amagiError: { ...result.error.amagiError, requestType: data.methodType }\n })\n throw networkError\n }\n\n // 检查B站API返回的code\n if (result.data.code !== 0) {\n const errorMessage = bilibiliErrorCodeMap[String(result.data.code) as keyof typeof bilibiliErrorCodeMap] || result.data.message || '未知错误'\n const Err: ErrorDetail = {\n errorDescription: `获取响应数据失败!原因:${errorMessage}!`,\n requestType: data.methodType,\n requestUrl: bilibiliApiUrls.二维码状态({ qrcode_key: data.qrcode_key })\n }\n return {\n code: result.data.code,\n data: result.data,\n amagiError: Err\n }\n }\n\n return {\n code: 0,\n data: {\n data: result.data.data,\n headers: result.headers\n },\n message: '0'\n }\n } catch (error) {\n if (error && typeof error === 'object') {\n return error\n }\n return {\n code: amagiAPIErrorCode.UNKNOWN,\n data: (error as any).data,\n amagiError: {\n errorDescription: '未知错误',\n requestType: data.methodType,\n requestUrl: bilibiliApiUrls.二维码状态({ qrcode_key: data.qrcode_key })\n }\n }\n }\n }\n\n case '登录基本信息': {\n const result = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: bilibiliApiUrls.登录基本信息()\n })\n return result\n }\n\n case '获取UP主总播放量': {\n const result = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: bilibiliApiUrls.获取UP主总播放量({ host_mid: data.host_mid })\n })\n return result\n }\n\n case 'AV转BV': {\n const result = av2bv(Number(data.avid.toString().replace(/^av/i, '')))\n return {\n code: 0,\n message: 'success',\n data: {\n bvid: result\n }\n }\n }\n\n case 'BV转AV': {\n const result = 'av' + bv2av(data.bvid)\n return {\n code: 0,\n message: 'success',\n data: {\n aid: result\n }\n }\n }\n\n case '专栏正文内容': {\n const result = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: bilibiliApiUrls.专栏正文内容({ id: data.id })\n })\n return result\n }\n case '专栏显示卡片信息': {\n const result = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: bilibiliApiUrls.专栏显示卡片信息({ ids: data.ids })\n })\n return result\n }\n\n case '专栏文章基本信息': {\n const result = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: bilibiliApiUrls.专栏文章基本信息({ id: data.id })\n })\n return result\n }\n\n case '文集基本信息': {\n const result = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: bilibiliApiUrls.文集基本信息({ id: data.id })\n })\n return result\n }\n case '从_v_voucher_申请_captcha': {\n const result = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n method: 'POST',\n url: bilibiliApiUrls.从_v_voucher_申请_captcha(data).Url,\n data: bilibiliApiUrls.从_v_voucher_申请_captcha(data).Body\n })\n return result\n }\n case '验证验证码结果': {\n const result = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n method: 'POST',\n url: bilibiliApiUrls.验证验证码结果(data).Url,\n data: bilibiliApiUrls.验证验证码结果(data).Body\n })\n return result\n }\n\n default:\n logger.warn(`未知的B站数据接口:「${logger.red((data as any).methodType)}」`)\n return null\n }\n}\n\n/**\n * 获取数据\n * @param options - 网络请求配置\n * @returns\n */\nconst GlobalGetData = async (type: string, options: AxiosRequestConfig, retryCount = 0): Promise<any | ErrorDetail> => {\n const MAX_RETRIES = 3\n let warningMessage = ''\n try {\n const result = await fetchData(options)\n\n // 处理网络层错误(自动重试后仍失败)\n if (isNetworkErrorResult(result)) {\n const networkError = new Error(result.error.amagiError.errorDescription)\n Object.assign(networkError, {\n code: result.error.code,\n data: null,\n amagiError: { ...result.error.amagiError, requestType: type }\n })\n throw networkError\n }\n\n if (!result || result === '') {\n const Err: ErrorDetail = {\n errorDescription: '获取响应数据失败!接口返回内容为空,你的B站ck可能已经失效!',\n requestType: type ?? '未知请求类型',\n requestUrl: options.url!\n }\n\n warningMessage = `\n 获取响应数据失败!原因:${logger.yellow('接口返回内容为空,你的B站ck可能已经失效!')}\n 请求类型:「${type}」\n 请求URL:${options.url}\n `\n logger.warn(warningMessage)\n const riskError = new Error(Err.errorDescription)\n Object.assign(riskError, {\n code: bilibiliAPIErrorCode.RISK_CONTROL_FAILED,\n data: result,\n amagiError: Err\n })\n throw riskError\n }\n\n if (result.code !== 0 || (!result.data || (typeof result.data === 'object' && Object.keys(result.data).length === 0))) {\n // 如果是-412错误且未超过重试次数,则自动重试\n if (result.code === -412 && retryCount < MAX_RETRIES) {\n return await GlobalGetData(type, options, retryCount + 1)\n }\n\n const errorMessage =\n (bilibiliErrorCodeMap[result.code as keyof typeof bilibiliErrorCodeMap]) ||\n ((typeof result.data === 'object' && Object.keys(result.data).length === 0) && '请求成功但无返回内容') ||\n (result.message ??\n '未知错误')\n const Err: ErrorDetail = {\n errorDescription: `获取响应数据失败!原因:${errorMessage}!`,\n requestType: type ?? '未知请求类型',\n requestUrl: options.url!,\n responseCode: result.code\n }\n warningMessage = `\n 获取响应数据失败!原因:${logger.yellow(errorMessage)}\n 错误代码:${result.code}\n 请求类型:「${type}」\n 请求URL:${options.url}\n `\n logger.warn(warningMessage)\n const apiError = new Error(Err.errorDescription)\n Object.assign(apiError, {\n code: result.code,\n data: result,\n amagiError: Err\n })\n throw apiError\n }\n\n return result\n } catch (error) {\n if (error && typeof error === 'object') {\n const err = error as ErrorDetail\n return { ...err, amagiMessage: warningMessage }\n }\n return {\n code: amagiAPIErrorCode.UNKNOWN,\n data: (error as any).data,\n amagiError: {\n errorDescription: '未知错误',\n requestType: type,\n requestUrl: options.url\n },\n amagiMessage: warningMessage\n }\n }\n}\n\n/**\n * 哔哩哔哩API官方HTTP请求错误码\n */\nexport const bilibiliErrorCodeMap = {\n '-1': '应用程序不存在或已被封禁',\n '-2': 'Access Key 错误',\n '-3': 'API 校验密匙错误',\n '-4': '调用方对该 Method 没有权限',\n '-101': '账号未登录',\n '-102': '账号被封停',\n '-103': '积分不足',\n '-104': '硬币不足',\n '-105': '验证码错误',\n '-106': '账号非正式会员或在适应期',\n '-107': '应用不存在或者被封禁',\n '-108': '未绑定手机',\n '-110': '未绑定手机',\n '-111': 'csrf 校验失败',\n '-112': '系统升级中',\n '-113': '账号尚未实名认证',\n '-114': '请先绑定手机',\n '-115': '请先完成实名认证',\n '-304': '木有改动',\n '-307': '撞车跳转',\n '-352': '风控校验失败 (UA 或 wbi 参数不合法)',\n '-400': '请求错误',\n '-401': '未认证 (或非法请求)',\n '-403': '访问权限不足',\n '-404': '啥都木有',\n '-405': '不支持该方法',\n '-409': '冲突',\n '-412': '请求被拦截 (客户端 ip 被服务端风控)',\n '-500': '服务器错误',\n '-503': '过载保护,服务暂不可用',\n '-504': '服务调用超时',\n '-509': '超出限制',\n '-616': '上传文件不存在',\n '-617': '上传文件太大',\n '-625': '登录失败次数太多',\n '-626': '用户不存在',\n '-628': '密码太弱',\n '-629': '用户名或密码错误',\n '-632': '操作对象数量限制',\n '-643': '被锁定',\n '-650': '用户等级太低',\n '-652': '重复的用户',\n '-658': 'Token 过期',\n '-662': '密码时间戳过期',\n '-688': '地理区域限制',\n '-689': '版权限制',\n '-701': '扣节操失败',\n '-799': '请求过于频繁,请稍后再试',\n '-8888': '对不起,服务器开小差了~ (ಥ﹏ಥ)',\n 100000: '验证码获取失败',\n 100003: '验证码过期'\n}\n","// All the content in this article is only for learning and communication use, not for any other purpose, strictly prohibited for commercial use and illegal use, otherwise all the consequences are irrelevant to the author!\n/* eslint-disable */\nclass SM3 {\n reg: number[]\n chunk: number[]\n size: number\n\n constructor () {\n this.reg = []\n this.chunk = []\n this.size = 0\n this.reset()\n }\n\n reset () {\n this.reg[0] = 1937774191\n this.reg[1] = 1226093241\n this.reg[2] = 388252375\n this.reg[3] = 3666478592\n this.reg[4] = 2842636476\n this.reg[5] = 372324522\n this.reg[6] = 3817729613\n this.reg[7] = 2969243214\n this.chunk = []\n this.size = 0\n }\n\n write (e: string | number[]) {\n const a: number[] = typeof e === 'string' ? this.stringToBytes(e) : e\n this.size += a.length\n let f = 64 - this.chunk.length\n if (a.length < f) {\n this.chunk = this.chunk.concat(a)\n } else {\n this.chunk = this.chunk.concat(a.slice(0, f))\n while (this.chunk.length >= 64) {\n this._compress(this.chunk)\n f < a.length ? (this.chunk = a.slice(f, Math.min(f + 64, a.length))) : (this.chunk = [])\n f += 64\n }\n }\n }\n\n sum (e?: string | number[], t?: string) {\n if (e) {\n this.reset()\n this.write(e)\n }\n this._fill()\n for (let f = 0; f < this.chunk.length; f += 64) {\n this._compress(this.chunk.slice(f, f + 64))\n }\n let i: string | number[] | null = null\n if (t === 'hex') {\n i = ''\n for (let f = 0; f < 8; f++) {\n i += this.padHex(this.reg[f].toString(16), 8)\n }\n } else {\n i = new Array(32)\n for (let f = 0; f < 8; f++) {\n let c = this.reg[f]\n i[4 * f + 3] = (255 & c) >>> 0\n c >>>= 8\n i[4 * f + 2] = (255 & c) >>> 0\n c >>>= 8\n i[4 * f + 1] = (255 & c) >>> 0\n c >>>= 8\n i[4 * f] = (255 & c) >>> 0\n }\n }\n this.reset()\n return i\n }\n\n private _compress (t: number[]) {\n if (t.length < 64) {\n console.error('compress error: not enough data')\n } else {\n for (\n var f = ((e) => {\n for (var r = new Array(132), t = 0; t < 16; t++) {\n ; (r[t] = e[4 * t] << 24), (r[t] |= e[4 * t + 1] << 16), (r[t] |= e[4 * t + 2] << 8), (r[t] |= e[4 * t + 3]), (r[t] >>>= 0)\n }\n for (var n = 16; n < 68; n++) {\n let a = r[n - 16] ^ r[n - 9] ^ this.le(r[n - 3], 15)\n ; (a = a ^ this.le(a, 15) ^ this.le(a, 23)), (r[n] = (a ^ this.le(r[n - 13], 7) ^ r[n - 6]) >>> 0)\n }\n for (n = 0; n < 64; n++) r[n + 68] = (r[n] ^ r[n + 4]) >>> 0\n return r\n })(t),\n i = this.reg.slice(0),\n c = 0;\n c < 64;\n c++\n ) {\n let o = this.le(i[0], 12) + i[4] + this.le(this.de(c), c)\n const s = ((o = this.le((o = (4294967295 & o) >>> 0), 7)) ^ this.le(i[0], 12)) >>> 0\n let u = this.pe(c, i[0], i[1], i[2])\n u = (4294967295 & (u = u + i[3] + s + f[c + 68])) >>> 0\n let b = this.he(c, i[4], i[5], i[6])\n ; (b = (4294967295 & (b = b + i[7] + o + f[c])) >>> 0),\n (i[3] = i[2]),\n (i[2] = this.le(i[1], 9)),\n (i[1] = i[0]),\n (i[0] = u),\n (i[7] = i[6]),\n (i[6] = this.le(i[5], 19)),\n (i[5] = i[4]),\n (i[4] = (b ^ this.le(b, 9) ^ this.le(b, 17)) >>> 0)\n }\n for (let l = 0; l < 8; l++) this.reg[l] = (this.reg[l] ^ i[l]) >>> 0\n }\n }\n\n private _fill () {\n let a = 8 * this.size\n let f = this.chunk.push(128) % 64\n while (64 - f < 8) {\n f -= 64\n }\n while (f < 56) {\n this.chunk.push(0)\n f++\n }\n for (let i = 0; i < 4; i++) {\n const c = Math.floor(a / 0x100000000)\n this.chunk.push((c >>> (8 * (3 - i))) & 255)\n }\n for (let i = 0; i < 4; i++) {\n this.chunk.push((a >>> (8 * (3 - i))) & 255)\n }\n }\n\n private de (e: number): number {\n return e >= 0 && e < 16 ? 2043430169 : e >= 16 && e < 64 ? 2055708042 : (console.error('invalid j for constant Tj'), 0)\n }\n\n private pe (e: number, r: number, t: number, n: number): number {\n return e >= 0 && e < 16 ? (r ^ t ^ n) >>> 0 : e >= 16 && e < 64 ? ((r & t) | (r & n) | (t & n)) >>> 0 : (console.error('invalid j for bool function FF'), 0)\n }\n\n private he (e: number, r: number, t: number, n: number): number {\n return e >= 0 && e < 16 ? (r ^ t ^ n) >>> 0 : e >= 16 && e < 64 ? ((r & t) | (~r & n)) >>> 0 : (console.error('invalid j for bool function GG'), 0)\n }\n\n private le (e: number, r: number) {\n return ((e << (r %= 32)) | (e >>> (32 - r))) >>> 0\n }\n\n private stringToBytes (str: string): number[] {\n const n = encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (_, r) => String.fromCharCode(parseInt(r, 16)))\n const a = new Array(n.length)\n for (let i = 0; i < n.length; i++) {\n a[i] = n.charCodeAt(i)\n }\n return a\n }\n\n private padHex (num: string, size: number): string {\n return num.padStart(size, '0')\n }\n}\n\nfunction rc4_encrypt (plaintext: string, key: string) {\n const s = []\n for (var i = 0; i < 256; i++) {\n s[i] = i\n }\n var j = 0\n for (var i = 0; i < 256; i++) {\n j = (j + s[i] + key.charCodeAt(i % key.length)) % 256\n var temp: any = s[i]\n s[i] = s[j]\n s[j] = temp\n }\n\n var i = 0\n var j = 0\n const cipher = []\n for (let k = 0; k < plaintext.length; k++) {\n i = (i + 1) % 256\n j = (j + s[i]) % 256\n var temp = s[i]\n s[i] = s[j]\n s[j] = temp\n const t = (s[i] + s[j]) % 256\n cipher.push(String.fromCharCode(s[t] ^ plaintext.charCodeAt(k)))\n }\n return cipher.join('')\n}\n\nfunction result_encrypt (long_str: string, num: 's0' | 's1' | 's2' | 's3' | 's4') {\n const s_obj = {\n s0: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',\n s1: 'Dkdpgh4ZKsQB80/Mfvw36XI1R25+WUAlEi7NLboqYTOPuzmFjJnryx9HVGcaStCe=',\n s2: 'Dkdpgh4ZKsQB80/Mfvw36XI1R25-WUAlEi7NLboqYTOPuzmFjJnryx9HVGcaStCe=',\n s3: 'ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe',\n s4: 'Dkdpgh2ZmsQB80/MfvV36XI1R45-WUAlEixNLwoqYTOPuzKFjJnry79HbGcaStCe'\n }\n const constant = {\n 0: 16515072,\n 1: 258048,\n 2: 4032,\n str: s_obj[num]\n }\n\n let result = ''\n let lound = 0\n let long_int = get_long_int(lound, long_str)\n for (let i = 0; i < (long_str.length / 3) * 4; i++) {\n if (Math.floor(i / 4) !== lound) {\n lound += 1\n long_int = get_long_int(lound, long_str)\n }\n let key = i % 4\n let temp_int\n switch (key) {\n case 0:\n temp_int = (long_int & constant['0']) >> 18\n result += constant['str'].charAt(temp_int)\n break\n case 1:\n temp_int = (long_int & constant['1']) >> 12\n result += constant['str'].charAt(temp_int)\n break\n case 2:\n temp_int = (long_int & constant['2']) >> 6\n result += constant['str'].charAt(temp_int)\n break\n case 3:\n temp_int = long_int & 63\n result += constant['str'].charAt(temp_int)\n break\n default:\n break\n }\n }\n return result\n}\nfunction get_long_int (round: number, long_str: string) {\n round = round * 3\n return (long_str.charCodeAt(round) << 16) | (long_str.charCodeAt(round + 1) << 8) | long_str.charCodeAt(round + 2)\n}\n\nfunction gener_random (random: number, option: number[]) {\n return [\n (random & 255 & 170) | (option[0] & 85), // 163\n (random & 255 & 85) | (option[0] & 170), // 87\n ((random >> 8) & 255 & 170) | (option[1] & 85), // 37\n ((random >> 8) & 255 & 85) | (option[1] & 170) // 41\n ]\n}\nfunction generate_rc4_bb_str (url_search_params: string, user_agent: string, window_env_str: string, suffix = 'cus', Arguments = [0, 1, 14]): string {\n let sm3 = new SM3()\n let start_time = Date.now()\n\n // url_search_params两次sm3之的结果\n const url_search_params_list = sm3.sum(sm3.sum(url_search_params + suffix))\n // 对后缀两次sm3之的结果\n const cus = sm3.sum(sm3.sum(suffix))\n // 对ua处理之后的结果\n const ua = sm3.sum(result_encrypt(rc4_encrypt(user_agent, String.fromCharCode.apply(null, [0.00390625, 1, 14])), 's3'))\n //\n const end_time = Date.now()\n\n // b object initialization\n let b: { [key: number]: any } = {\n 8: 3, // 固定\n 10: end_time, // 3次加密结束时间\n 15: {\n aid: 6383,\n pageId: 6241,\n boe: false,\n ddrt: 7,\n paths: {\n include: [{}, {}, {}, {}, {}, {}, {}],\n exclude: []\n },\n track: {\n mode: 0,\n delay: 300,\n paths: []\n },\n dump: true,\n rpU: ''\n },\n 16: start_time, // 3次加密开始时间\n 18: 44, // 固定\n 19: [1, 0, 1, 5]\n }\n\n // 3次加密开始时间\n b[20] = (b[16] >> 24) & 255\n b[21] = (b[16] >> 16) & 255\n b[22] = (b[16] >> 8) & 255\n b[23] = b[16] & 255\n b[24] = (b[16] / 256 / 256 / 256 / 256) >> 0\n b[25] = (b[16] / 256 / 256 / 256 / 256 / 256) >> 0\n\n // 参数Arguments [0, 1, 14, ...]\n // let Arguments = [0, 1, 14]\n b[26] = (Arguments[0] >> 24) & 255\n b[27] = (Arguments[0] >> 16) & 255\n b[28] = (Arguments[0] >> 8) & 255\n b[29] = Arguments[0] & 255\n\n b[30] = (Arguments[1] / 256) & 255\n b[31] = Arguments[1] % 256 & 255\n b[32] = (Arguments[1] >> 24) & 255\n b[33] = (Arguments[1] >> 16) & 255\n\n b[34] = (Arguments[2] >> 24) & 255\n b[35] = (Arguments[2] >> 16) & 255\n b[36] = (Arguments[2] >> 8) & 255\n b[37] = Arguments[2] & 255\n\n // (url_search_params + \"cus\") 两次sm3之的结果\n /** let url_search_params_list = [\n 91, 186, 35, 86, 143, 253, 6, 76,\n 34, 21, 167, 148, 7, 42, 192, 219,\n 188, 20, 182, 85, 213, 74, 213, 147,\n 37, 155, 93, 139, 85, 118, 228, 213\n ] */\n b[38] = url_search_params_list[21]\n b[39] = url_search_params_list[22]\n\n // (\"cus\") 对后缀两次sm3之的结果\n /**\n * let cus = [\n 136, 101, 114, 147, 58, 77, 207, 201,\n 215, 162, 154, 93, 248, 13, 142, 160,\n 105, 73, 215, 241, 83, 58, 51, 43,\n 255, 38, 168, 141, 216, 194, 35, 236\n ] */\n b[40] = cus[21]\n b[41] = cus[22]\n\n // 对ua处理之后的结果\n /**\n * let ua = [\n 129, 190, 70, 186, 86, 196, 199, 53,\n 99, 38, 29, 209, 243, 17, 157, 69,\n 147, 104, 53, 23, 114, 126, 66, 228,\n 135, 30, 168, 185, 109, 156, 251, 88\n ] */\n b[42] = ua[23]\n b[43] = ua[24]\n\n // 3次加密结束时间\n b[44] = (b[10] >> 24) & 255\n b[45] = (b[10] >> 16) & 255\n b[46] = (b[10] >> 8) & 255\n b[47] = b[10] & 255\n b[48] = b[8]\n b[49] = (b[10] / 256 / 256 / 256 / 256) >> 0\n b[50] = (b[10] / 256 / 256 / 256 / 256 / 256) >> 0\n\n // object配置项\n b[51] = b[15].pageId\n b[52] = (b[15].pageId >> 24) & 255\n b[53] = (b[15].pageId >> 16) & 255\n b[54] = (b[15].pageId >> 8) & 255\n b[55] = b[15].pageId & 255\n\n b[56] = b[15].aid\n b[57] = b[15].aid & 255\n b[58] = (b[15].aid >> 8) & 255\n b[59] = (b[15].aid >> 16) & 255\n b[60] = (b[15].aid >> 24) & 255\n\n // 中间进行了环境检测\n // 代码索引: 2496 索引值: 17 (索引64关键条件)\n // '1536|747|1536|834|0|30|0|0|1536|834|1536|864|1525|747|24|24|Win32'.charCodeAt()得到65位数组\n /**\n * let window_env_list = [49, 53, 51, 54, 124, 55, 52, 55, 124, 49, 53, 51, 54, 124, 56, 51, 52, 124, 48, 124, 51,\n * 48, 124, 48, 124, 48, 124, 49, 53, 51, 54, 124, 56, 51, 52, 124, 49, 53, 51, 54, 124, 56,\n * 54, 52, 124, 49, 53, 50, 53, 124, 55, 52, 55, 124, 50, 52, 124, 50, 52, 124, 87, 105, 110,\n * 51, 50]\n */\n const window_env_list = []\n for (let index = 0; index < window_env_str.length; index++) {\n window_env_list.push(window_env_str.charCodeAt(index))\n }\n b[64] = window_env_list.length\n b[65] = b[64] & 255\n b[66] = (b[64] >> 8) & 255\n\n b[69] = [].length\n b[70] = b[69] & 255\n b[71] = (b[69] >> 8) & 255\n\n b[72] =\n b[18] ^\n b[20] ^\n b[26] ^\n b[30] ^\n b[38] ^\n b[40] ^\n b[42] ^\n b[21] ^\n b[27] ^\n b[31] ^\n b[35] ^\n b[39] ^\n b[41] ^\n b[43] ^\n b[22] ^\n b[28] ^\n b[32] ^\n b[36] ^\n b[23] ^\n b[29] ^\n b[33] ^\n b[37] ^\n b[44] ^\n b[45] ^\n b[46] ^\n b[47] ^\n b[48] ^\n b[49] ^\n b[50] ^\n b[24] ^\n b[25] ^\n b[52] ^\n b[53] ^\n b[54] ^\n b[55] ^\n b[57] ^\n b[58] ^\n b[59] ^\n b[60] ^\n b[65] ^\n b[66] ^\n b[70] ^\n b[71]\n let bb = [\n b[18],\n b[20],\n b[52],\n b[26],\n b[30],\n b[34],\n b[58],\n b[38],\n b[40],\n b[53],\n b[42],\n b[21],\n b[27],\n b[54],\n b[55],\n b[31],\n b[35],\n b[57],\n b[39],\n b[41],\n b[43],\n b[22],\n b[28],\n b[32],\n b[60],\n b[36],\n b[23],\n b[29],\n b[33],\n b[37],\n b[44],\n b[45],\n b[59],\n b[46],\n b[47],\n b[48],\n b[49],\n b[50],\n b[24],\n b[25],\n b[65],\n b[66],\n b[70],\n b[71]\n ]\n bb = bb.concat(window_env_list).concat(b[72])\n return rc4_encrypt(String.fromCharCode.apply(null, bb), String.fromCharCode.apply(null, [121]))\n}\n\nfunction generate_random_str () {\n let random_str_list: any[] = []\n random_str_list = random_str_list.concat(gener_random(Math.random() * 10000, [3, 45]))\n random_str_list = random_str_list.concat(gener_random(Math.random() * 10000, [1, 0]))\n random_str_list = random_str_list.concat(gener_random(Math.random() * 10000, [1, 5]))\n return String.fromCharCode.apply(null, random_str_list)\n}\n\n/**\n * 清理User-Agent中的Edge标识\n * @param userAgent - 原始User-Agent字符串\n * @returns 清理后的User-Agent字符串\n */\nconst cleanUserAgentForSigning = (userAgent: string): string => {\n return userAgent.replace(/\\s+Edg\\/[\\d\\.]+/g, '')\n}\n\n/**\n * 抖音a_bogus签名算法\n * @param url - 需要签名的URL地址\n * @param user_agent - 用户代理字符串\n * @returns 生成的a_bogus签名\n */\nexport default (url: string, user_agent: string) => {\n const cleanedUserAgent = cleanUserAgentForSigning(user_agent)\n\n let result_str = generate_random_str() + generate_rc4_bb_str(new URLSearchParams(new URL(url).search).toString(), cleanedUserAgent, '1536|747|1536|834|0|30|0|0|1536|834|1536|864|1525|747|24|24|Win32')\n return result_encrypt(result_str, 's4') + '='\n}\n","import crypto from 'node:crypto'\nimport URL from 'node:url'\n\n/**\n * X-Bogus签名算法的返回结果类型\n */\ntype XBogusResult = {\n fullUrl: string\n xbogus: string\n userAgent: string\n}\n\n/**\n * X-Bogus 生成工具(TikTok/Douyin 签名算法)- TypeScript 版本\n * 原始 Python 代码来源:Douyin_TikTok_Download_API (Evil0ctal/Johnserf-Seed)\n */\nexport default class XBogus {\n private readonly charMap: (number | null)[]\n private readonly base64Charset: string\n private readonly uaKey: Buffer\n private readonly defaultUa: string\n public params?: string\n public xb?: string\n\n constructor () {\n // 初始化字符映射表\n this.charMap = new Array(128).fill(null)\n for (let i = 48; i <= 57; i++) {\n this.charMap[i] = i - 48\n }\n for (let i = 65; i <= 70; i++) {\n this.charMap[i] = i - 55\n }\n for (let i = 97; i <= 102; i++) {\n this.charMap[i] = i - 87\n }\n\n this.base64Charset = 'Dkdpgh4ZKsQB80/Mfvw36XI1R25-WUAlEi7NLboqYTOPuzmFjJnryx9HVGcaStCe='\n this.uaKey = Buffer.from([0x00, 0x01, 0x0c])\n this.defaultUa = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0'\n }\n\n private md5StrToArray (md5Str: string): number[] {\n const result: number[] = []\n\n if (md5Str.length > 32) {\n for (const char of md5Str) {\n result.push(char.charCodeAt(0))\n }\n return result\n }\n\n let idx = 0\n while (idx < md5Str.length) {\n const leftCharCode = md5Str.charCodeAt(idx)\n const rightCharCode = md5Str.charCodeAt(idx + 1)\n\n const left = this.charMap[leftCharCode]\n const right = this.charMap[rightCharCode]\n if (left === null || right === null) {\n throw new Error(`Invalid MD5 character: ${md5Str[idx]}${md5Str[idx + 1]}`)\n }\n\n result.push((left << 4) | right)\n idx += 2\n }\n\n return result\n }\n\n private md5 (input: string | number[]): string {\n const dataArray: number[] = typeof input === 'string'\n ? this.md5StrToArray(input)\n : input\n\n const dataBuffer = Buffer.from(dataArray)\n return crypto.createHash('md5')\n .update(dataBuffer)\n .digest('hex')\n }\n\n private md5Encrypt (urlPath: string): number[] {\n const firstMd5 = this.md5(urlPath)\n const firstArray = this.md5StrToArray(firstMd5)\n const secondMd5 = this.md5(firstArray)\n return this.md5StrToArray(secondMd5)\n }\n\n private encodingConversion (...params: (number | string)[]): string {\n const byteList: number[] = []\n\n for (const param of params) {\n if (typeof param === 'number') {\n byteList.push(Math.floor(param))\n } else if (typeof param === 'string') {\n for (const char of param) {\n byteList.push(char.charCodeAt(0))\n }\n }\n }\n\n return Buffer.from(byteList).toString('latin1')\n }\n\n private encodingConversion2 (a: number, b: number, c: string): string {\n return String.fromCharCode(a) + String.fromCharCode(b) + c\n }\n\n private rc4Encrypt (key: string | Buffer, data: string): string {\n const keyBuffer = typeof key === 'string'\n ? Buffer.from(key, 'latin1')\n : key\n const dataBuffer = Buffer.from(data, 'latin1')\n\n const S: number[] = Array.from({ length: 256 }, (_, i) => i)\n let j = 0\n\n for (let i = 0; i < 256; i++) {\n j = (j + S[i] + keyBuffer[i % keyBuffer.length]) % 256;\n [S[i], S[j]] = [S[j], S[i]]\n }\n\n const encryptedBuffer = Buffer.alloc(dataBuffer.length)\n let i = 0\n j = 0\n\n for (let k = 0; k < dataBuffer.length; k++) {\n i = (i + 1) % 256\n j = (j + S[i]) % 256;\n [S[i], S[j]] = [S[j], S[i]]\n\n const t = (S[i] + S[j]) % 256\n encryptedBuffer[k] = dataBuffer[k] ^ S[t]\n }\n\n return encryptedBuffer.toString('latin1')\n }\n\n private calculation (a1: number, a2: number, a3: number): string {\n const x1 = (a1 & 0xff) << 16\n const x2 = (a2 & 0xff) << 8\n const x3 = x1 | x2 | (a3 & 0xff)\n\n const c1 = this.base64Charset[(x3 & 0xffc000) >> 18]\n const c2 = this.base64Charset[(x3 & 0x3f000) >> 12]\n const c3 = this.base64Charset[(x3 & 0xfc0) >> 6]\n const c4 = this.base64Charset[x3 & 0x3f]\n\n return c1 + c2 + c3 + c4\n }\n\n /**\n * 生成X-Bogus签名\n * @param url 完整的URL地址\n * @param ua 可选的User-Agent,不提供则使用默认值\n * @returns 包含完整URL、X-Bogus值和使用的User-Agent的元组\n */\n public getXBogus (url: string, ua?: string): XBogusResult {\n const parsedUrl = new URL.URL(url)\n const urlPath = parsedUrl.pathname + parsedUrl.search\n const currentUa = ua ?? this.defaultUa\n\n // 生成array1\n const rc4EncryptedUa = this.rc4Encrypt(this.uaKey, currentUa)\n const base64Ua = Buffer.from(rc4EncryptedUa, 'latin1').toString('base64')\n const md5Ua = this.md5(base64Ua)\n const array1 = this.md5StrToArray(md5Ua)\n\n // 生成array2\n const emptyStrMd5 = 'd41d8cd98f00b204e9800998ecf8427e'\n const array2 = this.md5StrToArray(this.md5(this.md5StrToArray(emptyStrMd5)))\n\n // 生成URL加密数组\n const urlEncryptedArray = this.md5Encrypt(urlPath)\n\n // 时间戳与固定值处理\n const timestamp = Math.floor(Date.now() / 1000)\n const ct = 536919696\n\n // 构建newArray并计算异或结果\n const newArray: number[] = [\n 64, 1,\n 1, 12,\n urlEncryptedArray[14], urlEncryptedArray[15],\n array2[14], array2[15],\n array1[14], array1[15],\n (timestamp >> 24) & 0xff, (timestamp >> 16) & 0xff, (timestamp >> 8) & 0xff, timestamp & 0xff,\n (ct >> 24) & 0xff, (ct >> 16) & 0xff, (ct >> 8) & 0xff, ct & 0xff\n ]\n\n let xorResult = newArray[0]\n for (let i = 1; i < newArray.length; i++) {\n xorResult ^= newArray[i]\n }\n newArray.push(xorResult)\n\n // 拆分与合并数组\n const array3: number[] = []\n const array4: number[] = []\n let idx = 0\n while (idx < newArray.length) {\n array3.push(newArray[idx])\n if (idx + 1 < newArray.length) {\n array4.push(newArray[idx + 1])\n }\n idx += 2\n }\n const mergedArray = [...array3, ...array4]\n\n // 生成乱码字符串\n const firstConversion = this.encodingConversion(...mergedArray)\n const rc4Garbled = this.rc4Encrypt('ÿ', firstConversion)\n const garbledCode = this.encodingConversion2(2, 255, rc4Garbled)\n\n // 生成最终X-Bogus\n let xb = ''\n idx = 0\n while (idx < garbledCode.length) {\n if (idx + 2 >= garbledCode.length) break\n\n const a1 = garbledCode.charCodeAt(idx)\n const a2 = garbledCode.charCodeAt(idx + 1)\n const a3 = garbledCode.charCodeAt(idx + 2)\n xb += this.calculation(a1, a2, a3)\n idx += 3\n }\n\n // 构建最终URL\n const fullUrl = url.includes('?')\n ? `${url}&X-Bogus=${xb}`\n : `${url}?X-Bogus=${xb}`\n\n // 修改返回格式为对象\n return {\n fullUrl,\n xbogus: xb,\n userAgent: currentUa\n }\n }\n}\n","import crypto from 'node:crypto'\n\nimport a_bogus from './a_bogus'\nimport XBogus from './x_bogus'\n\nconst defaultUserAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36'\n\nexport class douyinSign {\n /**\n * 生成一个指定长度的随机字符串\n * @param length 字符串长度,默认为116\n * @returns\n */\n static Mstoken (length: number): string {\n const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'\n const randomBytes = crypto.randomBytes(length ?? 116)\n return Array.from(randomBytes, (byte) => characters[byte % characters.length]).join('')\n }\n\n /**\n * a_bogus 签名算法\n * @param url 需要签名的地址\n * @returns 对此地址签名后的URL查询参数\n */\n static AB (url: string, userAgent?: string): string {\n return a_bogus(url, userAgent ?? defaultUserAgent)\n }\n\n /**\n * X-Bogus 签名算法\n * @param url 需要签名的地址\n * @returns 对此地址签名后的URL查询参数\n */\n static XB (url: string, userAgent?: string): string {\n const xbogusResult = new XBogus().getXBogus(url, userAgent ?? defaultUserAgent)\n return xbogusResult.xbogus\n }\n\n /** 生成一个唯一的验证字符串 */\n static VerifyFpManager (): string {\n const e = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('')\n const t = e.length\n const n = new Date().getTime().toString(36)\n const r: (string | number)[] = []\n\n r[8] = '_'\n r[13] = '_'\n r[18] = '_'\n r[23] = '_'\n r[14] = '4'\n\n for (let o, i = 0; i < 36; i++) {\n if (!r[i]) {\n o = 0 | (Math.random() * t)\n r[i] = e[i === 19 ? (3 & o) | 8 : o]\n }\n }\n\n return 'verify_' + n + '_' + r.join('')\n }\n}\n","import { DouyinDataOptionsMap, OmitMethodType } from 'amagi/types'\n\nimport { douyinSign } from './sign'\n\n// 根据 DouyinMethodOptionsMap 创建一个新的类型,去除每个字段中的 methodType\ntype DouyinMethodOptionsWithoutMethodType = {\n [K in keyof DouyinDataOptionsMap]: OmitMethodType<DouyinDataOptionsMap[K]['opt']>\n}\n\n/**\n * 从User-Agent中提取浏览器版本信息\n * @param userAgent - 用户代理字符串\n * @returns 浏览器版本号,默认为125.0.0.0\n */\nconst extractBrowserVersion = (userAgent?: string): string => {\n if (!userAgent) return '125.0.0.0'\n\n // 匹配Chrome版本号\n const chromeMatch = userAgent.match(/Chrome\\/(\\d+\\.\\d+\\.\\d+\\.\\d+)/)\n if (chromeMatch) {\n return chromeMatch[1]\n }\n\n // 匹配Edge版本号\n const edgeMatch = userAgent.match(/Edg\\/(\\d+\\.\\d+\\.\\d+\\.\\d+)/)\n if (edgeMatch) {\n return edgeMatch[1]\n }\n\n // 默认返回125.0.0.0\n return '125.0.0.0'\n}\n\n/**\n * 将参数对象转换为URL查询字符串\n * @param params - 参数对象\n * @returns URL查询字符串\n */\nconst buildQueryString = (params: Record<string, any>): string => {\n return Object.entries(params)\n .filter(([_, value]) => value !== undefined && value !== null)\n .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)\n .join('&')\n}\n\nconst fp = douyinSign.VerifyFpManager()\n\nclass DouyinAPI {\n browserVersion: string\n\n /**\n * 构造函数\n * @param userAgent - 用户代理字符串,用于提取浏览器版本信息\n */\n constructor (userAgent?: string) {\n this.browserVersion = extractBrowserVersion(userAgent)\n }\n\n /**\n * 获取通用的基础参数\n * @returns 通用基础参数对象\n */\n getBaseParams (): Record<string, any> {\n return {\n device_platform: 'webapp',\n aid: '6383',\n channel: 'channel_pc_web',\n pc_client_type: '1',\n cookie_enabled: 'true',\n browser_language: 'zh-CN',\n browser_platform: 'Win32',\n browser_name: 'Chrome',\n browser_version: this.browserVersion,\n browser_online: 'true',\n engine_name: 'Blink',\n engine_version: this.browserVersion,\n os_name: 'Windows',\n os_version: '10',\n cpu_core_num: '16',\n device_memory: '8',\n platform: 'PC',\n downlink: '10',\n effective_type: '4g',\n msToken: douyinSign.Mstoken(184),\n verifyFp: fp,\n fp\n }\n }\n\n /**\n * 获取视频或图集数据的接口地址\n * @param data - 请求参数,包含aweme_id\n * @returns 完整的接口URL\n */\n 视频或图集 (data: DouyinMethodOptionsWithoutMethodType['聚合解析']): string {\n const baseUrl = 'https://www.douyin.com/aweme/v1/web/aweme/detail/'\n const params = {\n ...this.getBaseParams(),\n aweme_id: data.aweme_id,\n update_version_code: '170400',\n version_code: '190500',\n version_name: '19.5.0',\n screen_width: '2328',\n screen_height: '1310',\n round_trip_time: '150',\n webid: '7351848354471872041'\n }\n return `${baseUrl}?${buildQueryString(params)}`\n }\n\n /**\n * 获取评论数据的接口地址\n * @param data - 请求参数,包含aweme_id、cursor、number等\n * @returns 完整的接口URL\n */\n 评论 (data: DouyinMethodOptionsWithoutMethodType['评论数据']): string {\n const baseUrl = 'https://www.douyin.com/aweme/v1/web/comment/list/'\n const params = {\n ...this.getBaseParams(),\n aweme_id: data.aweme_id,\n cursor: data.cursor ?? 0,\n count: data.number ?? 50,\n item_type: '0',\n insert_ids: '',\n whale_cut_token: '',\n cut_version: '1',\n rcFT: '',\n version_code: '170400',\n version_name: '17.4.0',\n screen_width: '1552',\n screen_height: '970',\n round_trip_time: '50'\n }\n return `${baseUrl}?${buildQueryString(params)}`\n }\n\n /**\n * 获取二级评论数据的接口地址\n * @param data - 请求参数,包含aweme_id、comment_id等\n * @returns 完整的接口URL\n */\n 二级评论 (data: DouyinMethodOptionsWithoutMethodType['指定评论回复数据']): string {\n const baseUrl = 'https://www-hj.douyin.com/aweme/v1/web/comment/list/reply/'\n const params = {\n device_platform: 'webapp',\n aid: '6383',\n channel: 'channel_pc_web',\n item_id: data.aweme_id,\n comment_id: data.comment_id,\n cut_version: '1',\n cursor: data.cursor,\n count: data.number,\n item_type: '0',\n update_version_code: '170400',\n pc_client_type: '1',\n pc_libra_divert: 'Windows',\n support_h265: '1',\n support_dash: '1',\n version_code: '170400',\n version_name: '17.4.0',\n cookie_enabled: 'true',\n screen_width: '1552',\n screen_height: '970',\n browser_language: 'zh-CN',\n browser_platform: 'Win32',\n browser_name: 'Edge',\n browser_version: this.browserVersion,\n browser_online: 'true',\n engine_name: 'Blink',\n engine_version: this.browserVersion,\n os_name: 'Windows',\n os_version: '10',\n cpu_core_num: '16',\n device_memory: '8',\n platform: 'PC',\n downlink: '10',\n effective_type: '4g',\n round_trip_time: '50',\n webid: '7487210762873685515',\n verifyFp: fp,\n fp\n }\n return `${baseUrl}?${buildQueryString(params)}`\n }\n\n /**\n * 获取动图数据的接口地址\n * @param data - 请求参数,包含aweme_id\n * @returns 完整的接口URL\n */\n 动图 (data: DouyinMethodOptionsWithoutMethodType['聚合解析']): string {\n const baseUrl = 'https://www.iesdouyin.com/web/api/v2/aweme/slidesinfo/'\n const params = {\n reflow_source: 'reflow_page',\n web_id: '7326472315356857893',\n device_id: '7326472315356857893',\n aweme_ids: `[${data.aweme_id}]`,\n request_source: '200',\n msToken: douyinSign.Mstoken(116),\n verifyFp: fp,\n fp\n }\n return `${baseUrl}?${buildQueryString(params)}`\n }\n\n /**\n * 获取表情数据的接口地址\n * @returns 完整的接口URL\n */\n 表情 (): string {\n return 'https://www.douyin.com/aweme/v1/web/emoji/list'\n }\n\n /**\n * 获取用户主页视频数据的接口地址\n * @param data - 请求参数,包含sec_uid\n * @returns 完整的接口URL\n */\n 用户主页视频 (data: DouyinMethodOptionsWithoutMethodType['用户主页视频列表数据']): string {\n const baseUrl = 'https://www.douyin.com/aweme/v1/web/aweme/post/'\n const params = {\n ...this.getBaseParams(),\n sec_user_id: data.sec_uid,\n max_cursor: '0',\n locate_query: 'false',\n show_live_replay_strategy: '1',\n need_time_list: '1',\n time_list_query: '0',\n whale_cut_token: '',\n cut_version: '1',\n count: '18',\n publish_video_strategy_type: '2',\n version_code: '170400',\n version_name: '17.4.0',\n screen_width: '1552',\n screen_height: '970',\n round_trip_time: '50',\n webid: '7338423850134226495'\n }\n return `${baseUrl}?${buildQueryString(params)}`\n }\n\n /**\n * 获取用户主页信息的接口地址\n * @param data - 请求参数,包含sec_uid\n * @returns 完整的接口URL\n */\n 用户主页信息 (data: DouyinMethodOptionsWithoutMethodType['用户主页数据']): string {\n const baseUrl = 'https://www.douyin.com/aweme/v1/web/user/profile/other/'\n const params = {\n ...this.getBaseParams(),\n publish_video_strategy_type: '2',\n source: 'channel_pc_web',\n sec_user_id: data.sec_uid,\n personal_center_strategy: '1',\n version_code: '170400',\n version_name: '17.4.0',\n screen_width: '1552',\n screen_height: '970',\n round_trip_time: '0',\n webid: '7327957959955580467'\n }\n return `${baseUrl}?${buildQueryString(params)}`\n }\n\n /**\n * 获取热点词数据的接口地址\n * @param data - 请求参数,包含query\n * @returns 完整的接口URL\n */\n 热点词 (data: DouyinMethodOptionsWithoutMethodType['热点词数据']): string {\n const baseUrl = 'https://www.douyin.com/aweme/v1/web/api/suggest_words/'\n const params = {\n ...this.getBaseParams(),\n query: data.query,\n business_id: '30088',\n from_group_id: '7129543174929812767',\n version_code: '170400',\n version_name: '17.4.0',\n screen_width: '1552',\n screen_height: '970',\n round_trip_time: '50',\n webid: '7327957959955580467'\n }\n return `${baseUrl}?${buildQueryString(params)}`\n }\n\n /**\n * 获取搜索数据的接口地址\n * @param data - 请求参数,包含query、type、number、search_id等\n * @returns 完整的接口URL\n */\n 搜索 (data: DouyinMethodOptionsWithoutMethodType['搜索数据']): string {\n const searchType = data.type ?? '综合'\n const { verifyFp, fp, ...baseParamsWithoutFp } = this.getBaseParams()\n\n if (searchType === '用户') {\n // 用户搜索接口\n const baseUrl = 'https://www.douyin.com/aweme/v1/web/discover/search/'\n const params = {\n ...baseParamsWithoutFp,\n count: data.number ?? 10,\n disable_rs: '0',\n from_group_id: '',\n is_filter_search: '0',\n keyword: data.query,\n list_type: 'single',\n need_filter_settings: '1',\n offset: '0',\n pc_libra_divert: 'Windows',\n pc_search_top_1_params: '{\"enable_ai_search_top_1\":1}',\n query_correct_type: '1',\n round_trip_time: '250',\n screen_height: '1310',\n screen_width: '2328',\n search_channel: 'aweme_user_web',\n search_source: 'switch_tab',\n support_dash: '1',\n support_h265: '1',\n version_code: '170400',\n version_name: '17.4.0',\n webid: '7521399115230610959',\n ...(data.search_id && { search_id: data.search_id })\n }\n return `${baseUrl}?${buildQueryString(params)}`\n } else if (searchType === '视频') {\n // 视频搜索接口\n const baseUrl = 'https://www.douyin.com/aweme/v1/web/search/item/'\n const { verifyFp, fp, ...baseParamsWithoutFp } = this.getBaseParams()\n const params = {\n ...baseParamsWithoutFp,\n count: data.number ?? 10,\n disable_rs: '0',\n enable_history: '1',\n from_group_id: '',\n is_filter_search: '0',\n keyword: data.query,\n list_type: 'single',\n need_filter_settings: '1',\n offset: '0',\n pc_libra_divert: 'Windows',\n pc_search_top_1_params: '{\"enable_ai_search_top_1\":1}',\n query_correct_type: '1',\n round_trip_time: '50',\n screen_height: '1310',\n screen_width: '2328',\n search_channel: 'aweme_video_web',\n search_source: 'switch_tab',\n support_dash: '1',\n support_h265: '1',\n version_code: '170400',\n version_name: '17.4.0',\n webid: '7521399115230610959',\n ...(data.search_id && { search_id: data.search_id })\n }\n return `${baseUrl}?${buildQueryString(params)}`\n } else {\n // 综合搜索接口(默认)\n const baseUrl = 'https://www.douyin.com/aweme/v1/web/general/search/stream/'\n const params = {\n ...baseParamsWithoutFp,\n count: data.number ?? 10,\n disable_rs: '0',\n enable_history: '1',\n is_filter_search: '0',\n keyword: data.query,\n list_type: '',\n need_filter_settings: '1',\n offset: '0',\n pc_libra_divert: 'Windows',\n pc_search_top_1_params: '{\"enable_ai_search_top_1\":1}',\n query_correct_type: '1',\n round_trip_time: '0',\n screen_height: '1310',\n screen_width: '2328',\n search_channel: 'aweme_general',\n search_source: 'normal_search',\n support_dash: '1',\n support_h265: '1',\n version_code: '190600',\n version_name: '19.6.0',\n webid: '7521399115230610959'\n }\n return `${baseUrl}?${buildQueryString(params)}`\n }\n }\n\n /**\n * 获取互动表情数据的接口地址\n * @returns 完整的接口URL\n */\n 互动表情 (): string {\n const baseUrl = 'https://www.douyin.com/aweme/v1/web/im/strategy/config'\n const params = {\n device_platform: 'webapp',\n aid: '1128',\n channel: 'channel_pc_web',\n publish_video_strategy_type: '2',\n app_id: '1128',\n scenes: '[%22interactive_resources%22]',\n pc_client_type: '1',\n version_code: '170400',\n version_name: '17.4.0',\n cookie_enabled: 'true',\n screen_width: '2328',\n screen_height: '1310',\n browser_language: 'zh-CN',\n browser_platform: 'Win32',\n browser_name: 'Chrome',\n browser_version: '126.0.0.0',\n browser_online: 'true',\n engine_name: 'Blink',\n engine_version: '126.0.0.0',\n os_name: 'Windows',\n os_version: '10',\n cpu_core_num: '16',\n device_memory: '8',\n platform: 'PC',\n downlink: '1.5',\n effective_type: '4g',\n round_trip_time: '350',\n webid: '7347329698282833447',\n msToken: douyinSign.Mstoken(116),\n verifyFp: fp,\n fp\n }\n return `${baseUrl}?${buildQueryString(params)}`\n }\n\n /**\n * 获取背景音乐数据的接口地址\n * @param data - 请求参数,包含music_id\n * @returns 完整的接口URL\n */\n 背景音乐 (data: DouyinMethodOptionsWithoutMethodType['音乐数据']): string {\n const baseUrl = 'https://www.douyin.com/aweme/v1/web/music/detail/'\n const params = {\n device_platform: 'webapp',\n aid: '6383',\n channel: 'channel_pc_web',\n music_id: data.music_id,\n scene: '1',\n pc_client_type: '1',\n version_code: '170400',\n version_name: '17.4.0',\n cookie_enabled: 'true',\n screen_width: '2328',\n screen_height: '1310',\n browser_language: 'zh-CN',\n browser_platform: 'Win32',\n browser_name: 'Chrome',\n browser_version: '126.0.0.0',\n browser_online: 'true',\n engine_name: 'Blink',\n engine_version: '126.0.0.0',\n os_name: 'Windows',\n os_version: '10',\n cpu_core_num: '16',\n device_memory: '8',\n platform: 'PC',\n downlink: '1.5',\n effective_type: '4g',\n round_trip_time: '350',\n webid: '7347329698282833447',\n msToken: douyinSign.Mstoken(116),\n verifyFp: fp,\n fp\n }\n return `${baseUrl}?${buildQueryString(params)}`\n }\n\n /**\n * 获取直播间信息的接口地址\n * @param data - 请求参数,包含web_rid、room_id\n * @returns 完整的接口URL\n */\n 直播间信息 (data: DouyinMethodOptionsWithoutMethodType['直播间信息数据']): string {\n const baseUrl = 'https://live.douyin.com/webcast/room/web/enter/'\n const params = {\n aid: '6383',\n app_name: 'douyin_web',\n live_id: '1',\n device_platform: 'web',\n language: 'zh-CN',\n enter_from: 'web_share_link',\n cookie_enabled: 'true',\n screen_width: '2048',\n screen_height: '1152',\n browser_language: 'zh-CN',\n browser_platform: 'Win32',\n browser_name: 'Chrome',\n browser_version: '125.0.0.0',\n web_rid: data.web_rid,\n room_id_str: data.room_id,\n enter_source: '',\n is_need_double_stream: 'false',\n insert_task_id: '',\n live_reason: '',\n msToken: douyinSign.Mstoken(116),\n verifyFp: fp,\n fp\n }\n return `${baseUrl}?${buildQueryString(params)}`\n }\n\n /**\n * 获取申请二维码的接口地址\n * @param data - 请求参数,包含verify_fp\n * @returns 完整的接口URL\n */\n 申请二维码 (data: DouyinMethodOptionsWithoutMethodType['申请二维码数据']): string {\n const baseUrl = 'https://sso.douyin.com/get_qrcode/'\n const params = {\n verifyFp: data.verify_fp,\n fp: data.verify_fp\n }\n return `${baseUrl}?${buildQueryString(params)}`\n }\n\n /**\n * 获取弹幕数据的接口地址\n * @param data - 请求参数,包含group_id、item_id等\n * @returns 完整的接口URL\n */\n 弹幕 (data: DouyinMethodOptionsWithoutMethodType['弹幕数据']): string {\n const baseUrl = 'https://www-hj.douyin.com/aweme/v1/web/danmaku/get_v2/'\n const params = {\n ...this.getBaseParams(),\n app_name: 'aweme',\n format: 'json',\n group_id: data.aweme_id,\n item_id: data.aweme_id,\n start_time: data.start_time ?? '0',\n end_time: data.end_time ?? '32000',\n duration: data.duration,\n update_version_code: '170400',\n pc_libra_divert: 'Windows',\n support_h265: '1',\n support_dash: '1',\n version_code: '170400',\n version_name: '17.4.0',\n screen_width: '2328',\n screen_height: '1310',\n browser_name: 'Edge',\n browser_version: '140.0.0.0',\n engine_name: 'Blink',\n engine_version: '140.0.0.0',\n downlink: '1.55',\n round_trip_time: '200',\n webid: '7487210762873685515',\n msToken: douyinSign.Mstoken(116),\n verifyFp: fp,\n fp\n }\n return `${baseUrl}?${buildQueryString(params)}`\n }\n}\n\n/**\n * 创建DouyinAPI实例的工厂函数\n * @param userAgent - 用户代理字符串\n * @returns DouyinAPI实例\n */\nexport const createDouyinApiUrls = (userAgent?: string) => {\n return new DouyinAPI(userAgent)\n}\n\n/**\n * 默认的DouyinAPI实例(使用默认浏览器版本125.0.0.0)\n * 该类下的所有方法只会返回拼接好参数后的 Url 地址,需要手动请求该地址以获取数据\n *\n * 缺少 `a_bougs` 参数,请自行生成拼接\n */\nexport const douyinApiUrls = new DouyinAPI()\n","import { fetchData, isNetworkErrorResult, logger } from 'amagi/model'\nimport { getDouyinDefaultConfig } from 'amagi/platform/defaultConfigs'\nimport { RequestConfig } from 'amagi/server'\nimport { DouyinDataOptionsMap } from 'amagi/types'\nimport { amagiAPIErrorCode, douoyinAPIErrorCode, ErrorDetail } from 'amagi/types/NetworksConfigType'\nimport { DouyinReturnTypeMap } from 'amagi/types/ReturnDataType/Douyin'\nimport { AxiosRequestConfig } from 'axios'\n\n/**\n * 抖音数据获取模块\n *\n * 注意:为避免循环依赖,此文件直接从具体模块导入,而不是从平台 index 文件导入\n * 循环依赖链:DataFetchers → getdata → platform/douyin → DataFetchers\n */\nimport { createDouyinApiUrls } from './API'\nimport { douyinSign } from './sign'\n\n/**\n * 接口URL生成器类型定义\n * @template T - 参数类型\n */\ntype ApiUrlGenerator<T> = (params: T) => string\n\n/**\n * 签名算法类型\n */\ntype SignType = 'a_bogus' | 'x_bogus'\n\n/**\n * 获取签名参数\n * @param url - 需要签名的URL\n * @param signType - 签名算法类型\n * @param userAgent - 用户代理\n * @returns 签名后的参数字符串\n */\nconst getSignature = (url: string, signType: SignType = 'a_bogus', userAgent: string): string => {\n switch (signType) {\n case 'x_bogus':\n return douyinSign.XB(url, userAgent)\n case 'a_bogus':\n default:\n return douyinSign.AB(url, userAgent)\n }\n}\n\n/**\n * 获取签名参数名称\n * @param signType - 签名算法类型\n * @returns 签名参数名称\n */\nconst getSignParamName = (signType: SignType = 'a_bogus'): string => {\n switch (signType) {\n case 'x_bogus':\n return 'X-Bogus'\n case 'a_bogus':\n default:\n return 'a_bogus'\n }\n}\n\n/**\n * 构建带签名的URL\n * @param url - 基础URL\n * @param signType - 签名算法类型\n * @param userAgent - 用户代理\n * @returns 带签名的完整URL\n */\nconst buildSignedUrl = (url: string, signType: SignType = 'a_bogus', userAgent: string): string => {\n const signature = getSignature(url, signType, userAgent)\n const paramName = getSignParamName(signType)\n return `${url}&${paramName}=${signature}`\n}\n\n/**\n * 抖音数据获取函数\n * @param data - 请求数据参数\n * @param cookie - 用户Cookie\n * @param requestConfig - 外部请求配置(优先级最高)\n * @returns 返回抖音数据\n */\nexport const DouyinData = async <T extends keyof DouyinDataOptionsMap> (\n data: DouyinDataOptionsMap[T]['opt'],\n cookie?: string,\n requestConfig?: RequestConfig\n) => {\n const defHeaders = getDouyinDefaultConfig(cookie)['headers']\n\n const baseRequestConfig: AxiosRequestConfig = {\n method: 'GET',\n timeout: 10000,\n ...requestConfig,\n headers: {\n ...defHeaders,\n ...(requestConfig?.headers ?? {})\n }\n }\n\n // 从请求配置中获取User-Agent,创建对应的API实例\n const userAgent = baseRequestConfig.headers?.['User-Agent'] as string\n const douyinApiUrls = createDouyinApiUrls(userAgent)\n\n // 获取签名算法类型,默认为 a_bogus\n const signType = (data as any).signType ?? 'a_bogus'\n\n switch (data.methodType) {\n case '文字作品数据':\n case '聚合解析':\n case '视频作品数据':\n case '图集作品数据':\n case '合辑作品数据': {\n const url = douyinApiUrls.视频或图集({ aweme_id: data.aweme_id })\n const VideoData = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: buildSignedUrl(url, signType, userAgent)\n })\n return VideoData\n }\n\n case '评论数据': {\n const urlGenerator: ApiUrlGenerator<DouyinDataOptionsMap['评论数据']['opt']> = (params: DouyinDataOptionsMap['评论数据']['opt']) => douyinApiUrls.评论(params)\n const response = await fetchPaginatedData<any, DouyinDataOptionsMap['评论数据']['opt'], DouyinReturnTypeMap['评论数据'], DouyinReturnTypeMap['评论数据']>({\n type: data.methodType,\n apiUrlGenerator: urlGenerator,\n params: { ...data, cursor: data.cursor ?? 0 },\n maxPageSize: 50,\n requestConfig: baseRequestConfig,\n signType,\n extractList: (resp) => resp.comments ?? [],\n updateParams: (params, resp) => ({ ...params, cursor: resp.cursor }),\n hasMore: (resp) => resp.has_more === 1,\n formatFinalResponse: (resp, list) => ({\n ...resp,\n comments: list,\n cursor: resp.cursor ?? list.length\n })\n })\n return response\n }\n\n case '指定评论回复数据': {\n const urlGenerator: ApiUrlGenerator<DouyinDataOptionsMap['指定评论回复数据']['opt']> = (params: DouyinDataOptionsMap['指定评论回复数据']['opt']) => douyinApiUrls.二级评论(params)\n const response = await fetchPaginatedData<any, DouyinDataOptionsMap['指定评论回复数据']['opt'], DouyinReturnTypeMap['指定评论回复数据'], DouyinReturnTypeMap['指定评论回复数据']>({\n type: data.methodType,\n apiUrlGenerator: urlGenerator,\n params: { ...data, cursor: data.cursor ?? 0 },\n maxPageSize: 3,\n requestConfig: baseRequestConfig,\n signType: 'x_bogus',\n extractList: (resp) => resp.comments ?? [],\n updateParams: (params, resp) => ({ ...params, cursor: resp.cursor }),\n hasMore: (resp) => resp.has_more === 1,\n formatFinalResponse: (resp, list) => ({\n ...resp,\n comments: list,\n cursor: resp.cursor ?? list.length\n })\n })\n return response\n }\n\n case '用户主页数据': {\n const url = douyinApiUrls.用户主页信息({ sec_uid: data.sec_uid })\n const customConfig = {\n ...baseRequestConfig,\n headers: {\n ...baseRequestConfig.headers,\n // 只有在外部配置没有Referer时才设置内部的Referer\n ...(!requestConfig?.headers || !('Referer' in requestConfig.headers)) && {\n Referer: `https://www.douyin.com/user/${data.sec_uid}`\n }\n }\n }\n const UserInfoData = await GlobalGetData(data.methodType, {\n ...customConfig,\n url: buildSignedUrl(url, signType, userAgent)\n })\n return UserInfoData\n }\n\n case 'Emoji数据': {\n const url = douyinApiUrls.表情()\n const EmojiData = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url\n })\n return EmojiData\n }\n\n case '用户主页视频列表数据': {\n const url = douyinApiUrls.用户主页视频({ sec_uid: data.sec_uid })\n const customConfig = {\n ...baseRequestConfig,\n headers: {\n ...baseRequestConfig.headers,\n ...(!requestConfig?.headers || !('Referer' in requestConfig.headers)) && {\n Referer: `https://www.douyin.com/user/${data.sec_uid}`\n }\n }\n }\n const UserVideoListData = await GlobalGetData(data.methodType, {\n ...customConfig,\n url: buildSignedUrl(url, signType, userAgent)\n })\n return UserVideoListData\n }\n\n case '热点词数据': {\n const url = douyinApiUrls.热点词({ query: data.query })\n const customConfig = {\n ...baseRequestConfig,\n headers: {\n ...baseRequestConfig.headers,\n ...(!requestConfig?.headers || !('Referer' in requestConfig.headers)) && {\n Referer: `https://www.douyin.com/search/${encodeURIComponent(String(data.query))}`\n }\n }\n }\n const SuggestWordsData = await GlobalGetData(data.methodType, {\n ...customConfig,\n url: buildSignedUrl(url, signType, userAgent)\n })\n return SuggestWordsData\n }\n\n case '搜索数据': {\n const searchType = data.type ?? '综合'\n const refererUrl = searchType === '用户'\n ? `https://www.douyin.com/search/${encodeURIComponent(String(data.query))}?type=user`\n : searchType === '视频'\n ? `https://www.douyin.com/search/${encodeURIComponent(String(data.query))}?type=video`\n : `https://www.douyin.com/root/search/${encodeURIComponent(String(data.query))}`\n\n const customConfig = {\n ...baseRequestConfig,\n headers: {\n ...baseRequestConfig.headers,\n ...(!requestConfig?.headers || !('Referer' in requestConfig.headers)) && {\n referer: refererUrl\n }\n }\n }\n\n const isUserSearch = searchType === '用户'\n const isVideoSearch = searchType === '视频'\n\n const response = await fetchPaginatedData<any, any, DouyinReturnTypeMap['搜索数据'], DouyinReturnTypeMap['搜索数据']>({\n type: data.methodType,\n apiUrlGenerator: (params) => douyinApiUrls.搜索(params),\n params: {\n query: data.query,\n type: data.type,\n number: data.number ?? 10,\n search_id: ''\n },\n maxPageSize: 15,\n requestConfig: customConfig,\n signType: null,\n processRawResponse: (raw) => {\n if (!isUserSearch && !isVideoSearch) {\n const chunks: any[] = typeof raw === 'string'\n ? parseDouyinMultiJson(raw)\n : [raw]\n const responses = filterSearchResponses(chunks)\n\n if (responses.length === 0) return raw\n\n const mergedData: any[] = []\n let lastValid: any = {}\n for (const resp of responses) {\n if (Array.isArray(resp.data) && resp.data.length > 0) {\n mergedData.push(...resp.data)\n }\n lastValid = resp\n }\n return { ...lastValid, data: mergedData }\n }\n return raw\n },\n extractList: (resp) => {\n if (isUserSearch) {\n const userResp = resp as unknown as { user_list: any[] }\n return userResp.user_list ?? []\n }\n const videoResp = resp as unknown as { data: any[] }\n return videoResp.data ?? []\n },\n updateParams: (params, resp) => {\n let nextSearchId = params.search_id\n if (isUserSearch) {\n const userResp = resp as unknown as { rid: string }\n nextSearchId = userResp.rid ?? nextSearchId\n } else {\n const videoResp = resp as unknown as { log_pb: { impr_id: string } }\n nextSearchId = videoResp.log_pb?.impr_id ?? nextSearchId\n }\n return { ...params, search_id: nextSearchId }\n },\n hasMore: (resp) => {\n const hasMoreResp = resp as unknown as { has_more: number }\n return hasMoreResp.has_more !== 0\n },\n validateFirstPage: (list, raw, url) => {\n const typeStr = isUserSearch ? '用户' : isVideoSearch ? '视频' : '综合'\n let isInvalidResponse = false\n\n // 这里由于 raw 类型比较复杂(联合类型),先断言为 any 进行松散检查,或者使用类型守卫\n const rawAny = raw as any\n\n if (!rawAny || typeof rawAny !== 'object') {\n isInvalidResponse = true\n } else {\n if (isUserSearch && !rawAny.user_list) isInvalidResponse = true\n else if (isVideoSearch && !rawAny.data) isInvalidResponse = true\n else if (!isUserSearch && !isVideoSearch && !rawAny.data) isInvalidResponse = true\n }\n\n if (isInvalidResponse) {\n const desc = `抖音${typeStr}搜索返回无有效数据,疑似触发反爬机制,你的抖音Cookie可能已经失效!`\n const warningMessage = `\n 获取响应数据失败!原因:${logger.yellow(`${typeStr}搜索返回无有效数据,疑似触发反爬机制`)}\n 请求类型:「${data.methodType}」\n 搜索关键词:「${data.query}」\n 请求URL:${url}\n `\n // 第一次请求失败不打印警告,直接返回错误(保持原逻辑)\n return {\n code: douoyinAPIErrorCode.COOKIE,\n data: raw,\n amagiError: {\n errorDescription: desc,\n requestType: data.methodType ?? '未知请求类型',\n requestUrl: url\n },\n amagiMessage: warningMessage\n }\n }\n\n if (!list || list.length === 0) {\n const desc = `抖音${typeStr}搜索接口第一次请求就返回空数组,可能该关键词无搜索结果或触发风控限制,你的抖音Cookie可能已经失效!`\n const warningMessage = `\n 获取响应数据失败!原因:${logger.yellow(`${typeStr}搜索接口第一次请求就返回空数组,你的抖音Cookie可能已经失效!`)}\n 请求类型:「${data.methodType}」\n 搜索关键词:「${data.query}」\n 请求URL:${url}\n `\n logger.warn(warningMessage)\n return {\n data: raw,\n amagiError: {\n errorDescription: desc,\n requestType: data.methodType ?? '未知请求类型',\n requestUrl: url\n },\n amagiMessage: warningMessage\n }\n }\n return null\n },\n formatFinalResponse: (resp, list) => {\n if (isUserSearch) return { ...resp, user_list: list } as any\n return { ...resp, data: list } as any\n }\n })\n\n return response\n }\n\n case '动态表情数据': {\n const url = douyinApiUrls.互动表情()\n const ExpressionPlusData = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: buildSignedUrl(url, signType, userAgent)\n })\n return ExpressionPlusData\n }\n\n case '音乐数据': {\n const url = douyinApiUrls.背景音乐({ music_id: data.music_id })\n const MusicData = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: buildSignedUrl(url, signType, userAgent)\n })\n return MusicData\n }\n\n case '直播间信息数据': {\n let url = douyinApiUrls.直播间信息({ room_id: data.room_id, web_rid: data.web_rid })\n const liveCustomConfig = {\n ...baseRequestConfig,\n url: buildSignedUrl(url, signType, userAgent),\n headers: {\n ...baseRequestConfig.headers,\n ...((!requestConfig?.headers || !('Referer' in requestConfig.headers)) && {\n Referer: `https://live.douyin.com/${data.web_rid}`\n })\n }\n }\n\n const LiveRoomData = await GlobalGetData(data.methodType, {\n ...liveCustomConfig,\n url: buildSignedUrl(url, signType, userAgent)\n })\n return LiveRoomData\n }\n\n case '申请二维码数据': {\n const url = douyinApiUrls.申请二维码({ verify_fp: data.verify_fp })\n const LoginQrcodeStatusData = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: buildSignedUrl(url, signType, userAgent)\n })\n return LoginQrcodeStatusData\n }\n\n case '弹幕数据': {\n // 弹幕接口限制:每次最多获取32000ms(32秒)区间的弹幕\n const MAX_SEGMENT_DURATION = 32000\n\n // 如果用户没有指定start_time和end_time,则获取整个视频的弹幕\n const startTime = data.start_time ?? 0\n const endTime = data.end_time ?? data.duration\n const totalDuration = endTime - startTime\n\n // 如果请求区间小于等于32秒,直接请求\n if (totalDuration <= MAX_SEGMENT_DURATION) {\n const url = douyinApiUrls.弹幕({\n aweme_id: data.aweme_id,\n start_time: startTime,\n end_time: endTime,\n duration: data.duration\n })\n const DanmakuData = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: buildSignedUrl(url, signType, userAgent)\n })\n return DanmakuData\n }\n\n // 分段获取弹幕数据\n const segments: Array<{ start: number, end: number }> = []\n let currentStart = startTime\n\n // 计算所有需要请求的时间段\n while (currentStart < endTime) {\n const currentEnd = Math.min(currentStart + MAX_SEGMENT_DURATION, endTime)\n segments.push({ start: currentStart, end: currentEnd })\n currentStart = currentEnd\n }\n\n logger.debug(`弹幕数据需要分${segments.length}段获取,总时长:${totalDuration}ms`)\n\n // 并发请求所有段的弹幕数据\n const segmentPromises = segments.map(async (segment, index) => {\n const url = douyinApiUrls.弹幕({\n aweme_id: data.aweme_id,\n start_time: segment.start,\n end_time: segment.end,\n duration: data.duration\n })\n\n try {\n const segmentData = await GlobalGetData(`${data.methodType}-段${index + 1}`, {\n ...baseRequestConfig,\n url: buildSignedUrl(url, signType, userAgent)\n })\n\n logger.debug(`弹幕第${index + 1}段获取成功 (${segment.start}ms-${segment.end}ms)`)\n return segmentData\n } catch (error) {\n logger.debug(`弹幕第${index + 1}段获取失败 (${segment.start}ms-${segment.end}ms):`, error)\n return null\n }\n })\n\n // 等待所有段的数据返回\n const segmentResults = await Promise.all(segmentPromises)\n\n // 合并所有段的弹幕数据\n const mergedDanmakuList: any[] = []\n let totalCount = 0\n let finalStartTime = startTime\n let finalEndTime = endTime\n let finalExtra: any = null\n let finalLogPb: any = null\n let finalStatusCode = 0\n\n segmentResults.forEach((segmentData, index) => {\n if (segmentData && segmentData.danmaku_list) {\n // 合并弹幕列表\n mergedDanmakuList.push(...segmentData.danmaku_list)\n totalCount += segmentData.total ?? 0\n\n // 保存第一段的额外信息作为最终结果的基础信息\n if (index === 0) {\n finalExtra = segmentData.extra\n finalLogPb = segmentData.log_pb\n finalStatusCode = segmentData.status_code\n }\n }\n })\n\n // 按时间排序弹幕(确保弹幕按时间顺序排列)\n mergedDanmakuList.sort((a, b) => (a.offset_time ?? 0) - (b.offset_time ?? 0))\n\n // 构造最终的弹幕数据结构\n const finalDanmakuData = {\n danmaku_list: mergedDanmakuList,\n start_time: finalStartTime,\n end_time: finalEndTime,\n total: mergedDanmakuList.length, // 使用实际合并后的数量\n status_code: finalStatusCode,\n extra: finalExtra,\n log_pb: finalLogPb\n }\n\n logger.debug(`弹幕数据合并完成,共获取${mergedDanmakuList.length}条弹幕`)\n return finalDanmakuData\n }\n\n default: {\n const customUrl = (data as any).custom_url\n if (typeof customUrl === 'string' && customUrl.length > 0) {\n const url = buildSignedUrl(customUrl, signType, userAgent)\n const resp = await GlobalGetData((data as any).methodType ?? '自定义请求', {\n ...baseRequestConfig,\n url\n })\n return resp\n }\n logger.warn(`未知的抖音数据接口:「${logger.red((data as any).methodType)}」`)\n return null\n }\n }\n}\n\ntype CommentGlobalParams = {\n /** 视频ID */\n aweme_id: string\n /**\n * 获取的评论数量\n * 默认情况下,如果指定的数量不足,则获取实际的评论数量。\n */\n number?: number\n /**\n * 游标,作用类似于翻页,根据上一次评论数量递增\n * @defaultValue 0\n */\n cursor?: number\n}\n\n/**\n * 通用分页请求配置接口\n * @template T - 列表项的数据类型 (例如: CommentItem, UserItem, VideoItem)\n * @template P - 请求参数的数据类型 (例如: { cursor: number, aweme_id: string })\n * @template R - 最终返回的数据类型 (例如: DyWorkComments, DySearchInfo)\n * @template RawResp - 接口原始响应类型 (默认为 any,可指定具体类型以获得类型提示)\n */\ninterface PaginationConfig<T, P, R, RawResp = any> {\n /**\n * 请求类型标识\n * 用于日志记录和错误追踪,例如 '评论数据', '搜索数据'\n */\n type: string\n\n /**\n * 接口 URL 生成器函数\n * 根据当前参数生成请求 URL\n * @param params - 当前请求参数\n * @returns 完整的接口路径 (不包含域名和签名参数)\n */\n apiUrlGenerator: (params: P) => string\n\n /**\n * 初始请求参数\n * 包含第一次请求所需的所有字段\n */\n params: P\n\n /**\n * 单次请求的最大数据量限制\n * 即使 params.number 指定了更大的数量,每次请求也不会超过此值\n * 用于计算剩余需要请求的数量\n */\n maxPageSize: number\n\n /**\n * Axios 请求配置\n * 包含 headers (如 User-Agent, Referer) 等基础配置\n */\n requestConfig: AxiosRequestConfig\n\n /**\n * 签名算法类型\n * - 'a_bogus': 默认签名算法\n * - 'x_bogus': 旧版签名算法\n * - null: 不进行签名 (直接使用原始 URL)\n */\n signType?: SignType | null\n\n /**\n * 数据提取函数\n * 从原始响应对象中提取出数据列表数组\n * @param response - 接口返回的原始 JSON 对象\n * @returns 提取出的数据数组,如果无数据应返回空数组 []\n */\n extractList: (response: RawResp) => T[]\n\n /**\n * 参数更新函数\n * 根据上一次的响应结果,更新下一次请求的参数 (如翻页 cursor)\n * @param currentParams - 当前使用的请求参数\n * @param lastResponse - 上一次接口返回的原始响应\n * @returns 更新后的下一次请求参数\n */\n updateParams: (currentParams: P, lastResponse: RawResp) => P\n\n /**\n * 结束条件判断函数\n * 判断是否还有更多数据需要获取\n * @param lastResponse - 上一次接口返回的原始响应\n * @returns true 表示还有更多数据,false 表示已结束\n */\n hasMore: (lastResponse: RawResp) => boolean\n\n /**\n * 最终响应格式化函数\n * 将所有获取到的数据合并,构造成最终符合 TypeScript 接口定义的返回结构\n * @param lastResponse - 最后一次接口返回的原始响应 (通常包含 extra, log_pb 等元数据)\n * @param allData - 所有分组合并后的完整数据列表 (已根据 params.number 截断)\n * @returns 最终返回给调用者的数据对象\n */\n formatFinalResponse: (lastResponse: RawResp, allData: T[]) => R\n\n /**\n * (可选) 原始响应预处理函数\n * 在数据提取前对原始响应进行转换,例如处理抖音特殊的 multi-json 格式\n * @param raw - Axios 返回的原始数据\n * @returns 处理后的 JSON 对象\n */\n processRawResponse?: (raw: any) => RawResp\n\n /**\n * (可选) 首屏数据校验函数\n * 用于检测反爬虫、风控或 Cookie 失效等异常情况\n * 仅在第一次请求完成后调用\n * @param data - 第一次请求提取出的数据列表\n * @param response - 第一次请求的原始响应\n * @param url - 请求的完整 URL (用于错误日志)\n * @returns 如果校验失败返回错误对象 (ErrorDetail),校验通过返回 null\n */\n validateFirstPage?: (data: T[], response: RawResp, url: string) => any | null\n}\n\n/**\n * 通用的分页请求函数\n * 封装了循环分页请求、数据合并、错误处理和反爬检测逻辑\n *\n * @template T - 列表项类型\n * @template P - 参数类型\n * @template R - 返回值类型\n * @template RawResp - 原始响应类型\n * @param config - 分页请求配置对象\n * @returns Promise<R> 返回最终构造的数据对象\n */\nconst fetchPaginatedData = async <T, P, R, RawResp = any> (\n config: PaginationConfig<T, P, R, RawResp>\n): Promise<R> => {\n const {\n type,\n apiUrlGenerator,\n params,\n maxPageSize,\n requestConfig,\n signType = 'a_bogus',\n extractList,\n updateParams,\n hasMore,\n formatFinalResponse,\n processRawResponse,\n validateFirstPage\n } = config\n\n let currentParams = { ...params }\n const fetchedData: T[] = []\n let lastResponse: any = {}\n let isFirstRequest = true\n const userAgent = requestConfig.headers?.['User-Agent'] as string\n\n // 获取目标数量,优先使用 params 中的 number,否则使用 maxPageSize\n const targetNumber = Number((params as any).number ?? maxPageSize)\n\n while (fetchedData.length < targetNumber) {\n const currentCount = fetchedData.length\n const remaining = targetNumber - currentCount\n const requestCount = Math.min(remaining, maxPageSize)\n\n // 更新请求数量\n ; (currentParams as any).number = requestCount\n\n const url = apiUrlGenerator(currentParams)\n const finalUrl = signType ? buildSignedUrl(url, signType, userAgent) : url\n\n const raw = await GlobalGetData(type, {\n ...requestConfig,\n url: finalUrl\n })\n\n const response = processRawResponse ? processRawResponse(raw) : raw\n\n // 检查是否为错误响应(GlobalGetData 可能返回错误对象)\n if (response && response.amagiError) {\n return response\n }\n\n const list = extractList(response)\n\n if (isFirstRequest && validateFirstPage) {\n const error = validateFirstPage(list, response, finalUrl)\n if (error) return error\n }\n\n if (Array.isArray(list) && list.length > 0) {\n fetchedData.push(...list)\n }\n\n lastResponse = response\n\n if (!hasMore(response)) {\n break\n }\n\n if (!list || list.length === 0) {\n break\n }\n\n currentParams = updateParams(currentParams, response)\n isFirstRequest = false\n }\n\n // 如果需要截断数据以匹配精确数量\n const slicedData = targetNumber === 0 ? [] : fetchedData.slice(0, targetNumber)\n\n return formatFinalResponse(lastResponse, slicedData)\n}\n\n/**\n * 全局数据获取函数\n * @param type - 请求类型\n * @param config - 完整的axios请求配置\n * @returns 返回请求结果或错误详情\n */\nconst GlobalGetData = async (type: string, config: AxiosRequestConfig): Promise<any | ErrorDetail> => {\n let warningMessage = ''\n try {\n const result = await fetchData(config)\n\n // 处理网络层错误(自动重试后仍失败)\n if (isNetworkErrorResult(result)) {\n const networkError = new Error(result.error.amagiError.errorDescription)\n Object.assign(networkError, {\n code: result.error.code,\n data: null,\n amagiError: { ...result.error.amagiError, requestType: type }\n })\n throw networkError\n }\n\n if (!result || result === '') {\n const Err: ErrorDetail = {\n errorDescription: '获取响应数据失败!接口返回内容为空,你的抖音ck可能已经失效!',\n requestType: type ?? '未知请求类型',\n requestUrl: config.url!\n }\n warningMessage = `\n 获取响应数据失败!原因:${logger.yellow('接口返回内容为空,你的抖音ck可能已经失效!')}\n 请求类型:「${type}」\n 请求URL:${config.url}\n `\n logger.warn(warningMessage)\n const cookieError = new Error(Err.errorDescription)\n Object.assign(cookieError, {\n code: douoyinAPIErrorCode.COOKIE,\n data: result,\n amagiError: Err\n })\n throw cookieError\n }\n\n // 处理视频被隐藏或删除的情况\n if (result.filter_detail && result.filter_detail.filter_reason) {\n const filterReason = result.filter_detail.filter_reason\n const Err: ErrorDetail = {\n errorDescription: `获取响应数据失败!原因:${filterReason}!`,\n requestType: type ?? '未知请求类型',\n requestUrl: config.url!\n }\n warningMessage = `\n 获取响应数据失败!原因:${logger.yellow(filterReason)}\n 请求类型:「${type}」\n 请求URL:${config.url}\n `\n logger.warn(warningMessage)\n const filterError = new Error(Err.errorDescription)\n Object.assign(filterError, {\n code: douoyinAPIErrorCode.FILTER,\n data: result,\n amagiError: Err\n })\n throw filterError\n }\n return result\n } catch (error) {\n if (error && typeof error === 'object') {\n const err = error as ErrorDetail\n return { ...err, amagiMessage: warningMessage }\n }\n return {\n code: amagiAPIErrorCode.UNKNOWN,\n data: null,\n amagiError: {\n errorDescription: '未知错误',\n requestType: type,\n requestUrl: config.url\n },\n amagiMessage: warningMessage\n }\n }\n}\n\n/** 解析抖音反爬的 multi-JSON 响应 */\nconst parseDouyinMultiJson = (raw: string): any[] => {\n const blocks: string[] = []\n let depth = 0\n let start = -1\n\n /**\n * 遇到 { → 深度 +1\n * 遇到 } → 深度 -1\n * 当深度回到 0 时 → 找到一个完整 JSON\n */\n for (let i = 0; i < raw.length; i++) {\n const c = raw[i]\n\n if (c === '{') {\n if (depth === 0) start = i\n depth++\n } else if (c === '}') {\n depth--\n if (depth === 0 && start !== -1) {\n blocks.push(raw.slice(start, i + 1))\n start = -1\n }\n }\n }\n\n const parsed = []\n for (const block of blocks) {\n try {\n parsed.push(JSON.parse(block))\n } catch { }\n }\n return parsed\n}\n\n/** 只保留包含 cursor/has_more/data 的合法搜索响应 */\nconst filterSearchResponses = (objs: any[]): any[] => {\n return objs.filter(o =>\n o &&\n typeof o.cursor === 'number' &&\n typeof o.has_more === 'number' &&\n Array.isArray(o.data)\n )\n}\n","import { OmitMethodType } from 'amagi/types'\nimport { KuaishouMethodOptionsMap } from 'amagi/types/KuaishouAPIParams'\n\n// 根据 KuaishouMethodOptionsMap 创建一个新的类型,去除每个字段中的 methodType\ntype KuaishouMethodOptionsWithoutMethodType = {\n [K in keyof KuaishouMethodOptionsMap]: OmitMethodType<KuaishouMethodOptionsMap[K]>\n}\n\nclass API {\n 单个作品信息<T extends KuaishouMethodOptionsWithoutMethodType['VideoInfoParams']> (data: T) {\n return {\n /** 接口类型 */\n type: 'visionVideoDetail',\n /** 请求url */\n url: 'https://www.kuaishou.com/graphql',\n /** 请求参数 */\n body: {\n /** 接口类型 */\n operationName: 'visionVideoDetail',\n variables: {\n /** 作品ID */\n photoId: data.photoId,\n page: 'detail'\n },\n query: 'query visionVideoDetail($photoId: String, $type: String, $page: String, $webPageArea: String) {\\n visionVideoDetail(photoId: $photoId, type: $type, page: $page, webPageArea: $webPageArea) {\\n status\\n type\\n author {\\n id\\n name\\n following\\n headerUrl\\n __typename\\n }\\n photo {\\n id\\n duration\\n caption\\n likeCount\\n realLikeCount\\n coverUrl\\n photoUrl\\n liked\\n timestamp\\n expTag\\n llsid\\n viewCount\\n videoRatio\\n stereoType\\n musicBlocked\\n manifest {\\n mediaType\\n businessType\\n version\\n adaptationSet {\\n id\\n duration\\n representation {\\n id\\n defaultSelect\\n backupUrl\\n codecs\\n url\\n height\\n width\\n avgBitrate\\n maxBitrate\\n m3u8Slice\\n qualityType\\n qualityLabel\\n frameRate\\n featureP2sp\\n hidden\\n disableAdaptive\\n __typename\\n }\\n __typename\\n }\\n __typename\\n }\\n manifestH265\\n photoH265Url\\n coronaCropManifest\\n coronaCropManifestH265\\n croppedPhotoH265Url\\n croppedPhotoUrl\\n videoResource\\n __typename\\n }\\n tags {\\n type\\n name\\n __typename\\n }\\n commentLimit {\\n canAddComment\\n __typename\\n }\\n llsid\\n danmakuSwitch\\n __typename\\n }\\n}\\n'\n }\n }\n }\n\n 作品评论信息<T extends KuaishouMethodOptionsWithoutMethodType['CommentParams']> (data: T) {\n return {\n type: 'commentListQuery',\n url: 'https://www.kuaishou.com/graphql',\n body: {\n operationName: 'commentListQuery',\n variables: {\n photoId: data.photoId,\n pcursor: ''\n },\n query: 'query commentListQuery($photoId: String, $pcursor: String) {\\n visionCommentList(photoId: $photoId, pcursor: $pcursor) {\\n commentCount\\n pcursor\\n rootComments {\\n commentId\\n authorId\\n authorName\\n content\\n headurl\\n timestamp\\n likedCount\\n realLikedCount\\n liked\\n status\\n authorLiked\\n subCommentCount\\n subCommentsPcursor\\n subComments {\\n commentId\\n authorId\\n authorName\\n content\\n headurl\\n timestamp\\n likedCount\\n realLikedCount\\n liked\\n status\\n authorLiked\\n replyToUserName\\n replyTo\\n __typename\\n }\\n __typename\\n }\\n __typename\\n }\\n}\\n'\n }\n }\n }\n\n 表情 () { // 这个方法不需要泛型参数\n return {\n type: 'visionBaseEmoticons',\n url: 'https://www.kuaishou.com/graphql',\n body: {\n operationName: 'visionBaseEmoticons',\n variables: {},\n query: 'query visionBaseEmoticons {\\n visionBaseEmoticons {\\n iconUrls\\n __typename\\n }\\n}\\n'\n }\n }\n }\n}\n\n/** 该类下的所有方法只会返回拼接好参数后的 Url 地址和请求体,需要手动请求该地址以获取数据 */\nexport const kuaishouApiUrls = new API()\n","import { fetchData, isNetworkErrorResult, logger } from 'amagi/model'\nimport { getKuaishouDefaultConfig } from 'amagi/platform/defaultConfigs'\nimport { RequestConfig } from 'amagi/server'\nimport { KuaishouDataOptionsMap } from 'amagi/types'\nimport { amagiAPIErrorCode, ErrorDetail, kuaishouAPIErrorCode } from 'amagi/types/NetworksConfigType'\nimport { AxiosRequestConfig } from 'axios'\n\n/**\n * 快手数据获取模块\n *\n * 注意:为避免循环依赖,此文件直接从具体模块导入,而不是从平台 index 文件导入\n * 循环依赖链:DataFetchers → getdata → platform/kuaishou → DataFetchers\n */\nimport { kuaishouApiUrls } from './API'\n\n/**\n * 快手数据获取函数\n * @param data - 请求数据参数\n * @param cookie - 用户Cookie\n * @param requestConfig - 外部请求配置(优先级最高)\n * @returns 返回快手数据\n */\nexport const KuaishouData = async <T extends keyof KuaishouDataOptionsMap> (\n data: KuaishouDataOptionsMap[T]['opt'],\n cookie?: string,\n requestConfig?: RequestConfig\n) => {\n const defHeaders = getKuaishouDefaultConfig(cookie)['headers']\n\n const baseRequestConfig: AxiosRequestConfig = {\n method: 'POST',\n timeout: 10000,\n ...requestConfig,\n headers: {\n ...defHeaders,\n ...(requestConfig?.headers ?? {})\n }\n }\n\n switch (data.methodType) {\n case '单个视频作品数据': {\n const body = kuaishouApiUrls.单个作品信息({ photoId: data.photoId })\n const VideoData = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: body.url,\n data: body.body\n })\n return VideoData\n }\n\n case '评论数据': {\n const body = kuaishouApiUrls.作品评论信息({ photoId: data.photoId })\n const VideoData = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: body.url,\n data: body.body\n })\n return VideoData\n }\n\n case 'Emoji数据': {\n const body = kuaishouApiUrls.表情()\n const EmojiData = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: body.url,\n data: body.body\n })\n return EmojiData\n }\n\n default:\n logger.warn(`未知的快手数据接口:「${logger.red((data as any).methodType)}」`)\n return null\n }\n}\n\n/**\n * 数据获取函数\n * @param options - 网络请求配置选项\n */\nconst GlobalGetData = async (type: string, options: AxiosRequestConfig): Promise<any | ErrorDetail> => {\n let warningMessage = ''\n try {\n const result = await fetchData(options)\n\n // 处理网络层错误(自动重试后仍失败)\n if (isNetworkErrorResult(result)) {\n const networkError = new Error(result.error.amagiError.errorDescription)\n Object.assign(networkError, {\n code: result.error.code,\n data: null,\n amagiError: { ...result.error.amagiError, requestType: type }\n })\n throw networkError\n }\n\n if (result === '' || !result || result.result === 2) {\n const Err: ErrorDetail & { requestBody: string } = {\n errorDescription: '获取响应数据失败!接口返回内容为空!',\n requestType: type ?? '未知请求类型',\n requestUrl: options.url!,\n requestBody: JSON.stringify(options.data)\n }\n warningMessage = `\n 获取响应数据失败!原因:${logger.yellow('接口返回内容为空,你的快手ck可能已经失效!')}\n 请求类型:「${type}」\n 请求URL:${options.url}\n 请求参数:${JSON.stringify(options.data, null, 2)}\n `\n logger.warn(warningMessage)\n const cookieError = new Error(Err.errorDescription)\n Object.assign(cookieError, {\n code: kuaishouAPIErrorCode.COOKIE,\n data: result,\n amagiError: Err\n })\n throw cookieError\n }\n return result\n } catch (error) {\n if (error && typeof error === 'object') {\n const err = error as ErrorDetail\n return { ...err, amagiMessage: warningMessage }\n }\n return {\n code: amagiAPIErrorCode.UNKNOWN,\n data: null,\n amagiError: {\n errorDescription: '未知错误',\n requestType: type,\n requestUrl: options.url\n },\n amagiMessage: warningMessage\n }\n }\n}\n","import { fetchData, isNetworkErrorResult, logger } from 'amagi/model'\nimport { getXiaohongshuDefaultConfig } from 'amagi/platform/defaultConfigs'\nimport { RequestConfig } from 'amagi/server'\nimport { XiaohongshuDataOptionsMap } from 'amagi/types'\nimport { ErrorDetail } from 'amagi/types/NetworksConfigType'\nimport { extractCreatorInfoFromHtml } from 'amagi/validation/utils'\nimport { AxiosRequestConfig } from 'axios'\n\nimport { createXiaohongshuApiUrls } from './API'\nimport { xiaohongshuSign } from './sign'\n\n/**\n * 小红书数据获取函数\n * @param data - 请求数据参数\n * @param cookie - 用户Cookie\n * @param requestConfig - 外部请求配置\n * @returns 返回小红书数据\n */\nexport const XiaohongshuData = async <T extends keyof XiaohongshuDataOptionsMap> (\n data: XiaohongshuDataOptionsMap[T]['opt'],\n cookie?: string,\n requestConfig?: RequestConfig\n) => {\n const defHeaders = getXiaohongshuDefaultConfig(cookie)['headers']\n\n const baseRequestConfig: AxiosRequestConfig = {\n method: 'POST',\n timeout: 10000,\n ...requestConfig,\n headers: {\n ...defHeaders,\n ...(requestConfig?.headers ?? {})\n }\n }\n\n const xiaohongshuApiUrls = createXiaohongshuApiUrls()\n\n switch (data.methodType) {\n case '首页推荐数据': {\n const homeFeedData = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: xiaohongshuApiUrls.首页推荐数据(data).Url,\n data: JSON.stringify(xiaohongshuApiUrls.首页推荐数据(data).Body),\n headers: {\n ...baseRequestConfig.headers,\n 'x-s': xiaohongshuSign.generateXSPost(\n xiaohongshuApiUrls.首页推荐数据(data).apiPath,\n xiaohongshuSign.extractA1FromCookie(cookie ?? ''),\n 'xhs-pc-web',\n xiaohongshuApiUrls.首页推荐数据(data).Body\n ),\n 'x-s-common': xiaohongshuSign.generateXSCommon(cookie ?? ''),\n 'x-t': xiaohongshuSign.generateXT()\n }\n })\n return homeFeedData\n }\n\n case '单个笔记数据': {\n const noteData = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: xiaohongshuApiUrls.单个笔记数据(data).Url,\n data: xiaohongshuApiUrls.单个笔记数据(data).Body,\n headers: {\n ...baseRequestConfig.headers,\n 'x-s': xiaohongshuSign.generateXSPost(\n xiaohongshuApiUrls.单个笔记数据(data).apiPath,\n xiaohongshuSign.extractA1FromCookie(cookie ?? ''),\n 'xhs-pc-web',\n xiaohongshuApiUrls.单个笔记数据(data).Body\n ),\n 'x-s-common': xiaohongshuSign.generateXSCommon(cookie ?? ''),\n 'x-t': xiaohongshuSign.generateXT()\n }\n })\n return noteData\n }\n\n case '评论数据': {\n const baseRequestConfig: AxiosRequestConfig = {\n method: 'GET',\n timeout: 10000,\n ...requestConfig,\n headers: {\n ...defHeaders,\n ...(requestConfig?.headers ?? {})\n }\n }\n\n const commentData = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: xiaohongshuApiUrls.评论数据(data).Url,\n headers: {\n ...baseRequestConfig.headers,\n 'x-s': xiaohongshuSign.generateXSGet(\n xiaohongshuApiUrls.评论数据(data).apiPath,\n xiaohongshuSign.extractA1FromCookie(cookie ?? ''),\n 'xhs-pc-web'\n ),\n 'x-s-common': xiaohongshuSign.generateXSCommon(cookie ?? ''),\n 'x-t': xiaohongshuSign.generateXT()\n }\n })\n return commentData\n }\n\n case '用户数据': {\n const baseRequestConfig: AxiosRequestConfig = {\n method: 'GET',\n timeout: 10000,\n ...requestConfig,\n headers: {\n ...defHeaders,\n ...(requestConfig?.headers ?? {})\n }\n }\n\n const userData = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: xiaohongshuApiUrls.用户数据(data).Url,\n headers: {\n ...baseRequestConfig.headers,\n 'x-s': xiaohongshuSign.generateXSGet(\n xiaohongshuApiUrls.用户数据(data).apiPath,\n xiaohongshuSign.extractA1FromCookie(cookie ?? ''),\n 'xhs-pc-web'\n ),\n 'x-s-common': xiaohongshuSign.generateXSCommon(cookie ?? ''),\n 'x-t': xiaohongshuSign.generateXT()\n }\n })\n const pageData = extractCreatorInfoFromHtml(userData)\n\n return {\n code: 0,\n data: pageData,\n msg: '成功'\n }\n }\n\n case '用户笔记数据': {\n const userNoteData = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n method: 'GET',\n url: xiaohongshuApiUrls.用户笔记数据(data).Url,\n headers: {\n ...baseRequestConfig.headers,\n 'x-b3-traceid': xiaohongshuSign.generateXB3Traceid(),\n 'x-s': xiaohongshuSign.generateXSGet(\n xiaohongshuApiUrls.用户笔记数据(data).apiPath,\n xiaohongshuSign.extractA1FromCookie(cookie ?? ''),\n 'xhs-pc-web'\n ),\n 'x-s-common': xiaohongshuSign.generateXSCommon(cookie ?? ''),\n 'x-t': xiaohongshuSign.generateXT()\n }\n })\n return userNoteData\n }\n\n case '表情列表': {\n const baseRequestConfig: AxiosRequestConfig = {\n method: 'GET',\n timeout: 10000,\n ...requestConfig,\n headers: {\n ...defHeaders,\n ...(requestConfig?.headers ?? {})\n }\n }\n\n const emojiListData = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: xiaohongshuApiUrls.表情列表(data).Url,\n headers: {\n ...baseRequestConfig.headers,\n 'x-s': xiaohongshuSign.generateXSGet(\n xiaohongshuApiUrls.表情列表(data).apiPath,\n xiaohongshuSign.extractA1FromCookie(cookie ?? ''),\n 'xhs-pc-web'\n ),\n 'x-s-common': xiaohongshuSign.generateXSCommon(cookie ?? ''),\n 'x-t': xiaohongshuSign.generateXT()\n }\n })\n return emojiListData\n }\n\n case '搜索笔记': {\n const searchNoteData = await GlobalGetData(data.methodType, {\n ...baseRequestConfig,\n url: xiaohongshuApiUrls.搜索笔记(data).Url,\n data: xiaohongshuApiUrls.搜索笔记(data).Body,\n headers: {\n ...baseRequestConfig.headers,\n 'x-s': xiaohongshuSign.generateXSPost(\n xiaohongshuApiUrls.搜索笔记(data).apiPath,\n xiaohongshuSign.extractA1FromCookie(cookie ?? ''),\n 'xhs-pc-web'\n ),\n 'x-s-common': xiaohongshuSign.generateXSCommon(cookie ?? ''),\n 'x-t': xiaohongshuSign.generateXT()\n }\n })\n return searchNoteData\n }\n\n default:\n throw new Error(`未知的小红书数据接口: 「${logger.red((data as any).methodType)}」`)\n }\n}\n\n/**\n * 全局数据获取函数\n */\nconst GlobalGetData = async (methodType: string, config: AxiosRequestConfig) => {\n try {\n const response = await fetchData(config)\n\n // 处理网络层错误(自动重试后仍失败)\n if (isNetworkErrorResult(response)) {\n const networkError = new Error(response.error.amagiError.errorDescription)\n Object.assign(networkError, {\n code: response.error.code,\n data: null,\n amagiError: { ...response.error.amagiError, requestType: methodType }\n })\n throw networkError\n }\n\n if (typeof response === 'string' && response.includes('<html>')) {\n return response\n }\n if (response.code !== 0) {\n throw new Error(`API请求失败: ${response.data?.msg ?? response.msg ?? '未知错误'}, code: ${response.code}`)\n }\n\n return response\n } catch (error: any) {\n logger.error(`小红书API请求失败 [${methodType}]:`, error.message)\n\n const errorDetail: ErrorDetail = {\n errorDescription: error.message ?? '未知错误',\n requestType: methodType,\n requestUrl: config.url ?? ''\n }\n\n return {\n code: 500,\n message: 'error',\n data: null,\n amagiError: errorDetail,\n amagiMessage: `小红书API请求失败: ${error.message}`\n }\n }\n}\n","/* eslint-disable @stylistic/indent */\nimport { fetchBilibili } from 'amagi/platform/bilibili/getdata'\nimport { DouyinData } from 'amagi/platform/douyin/getdata'\nimport { KuaishouData } from 'amagi/platform/kuaishou/getdata'\nimport { XiaohongshuData } from 'amagi/platform/xiaohongshu/getdata'\nimport { RequestConfig } from 'amagi/server'\nimport type {\n BilibiliDataOptionsMap,\n DouyinDataOptionsMap,\n DouyinMethodOptMap,\n KuaishouDataOptionsMap,\n XiaohongshuDataOptionsMap\n} from 'amagi/types'\nimport { kuaishouAPIErrorCode, xiaohongshuAPIErrorCode } from 'amagi/types/NetworksConfigType'\nimport type {\n BilibiliReturnTypeMap,\n DouyinReturnTypeMap,\n KuaishouReturnTypeMap\n} from 'amagi/types/ReturnDataType'\nimport {\n BilibiliMethodType,\n createErrorResponse,\n createSuccessResponse,\n DouyinMethodType,\n KuaishouMethodType,\n Result,\n validateBilibiliParams,\n validateDouyinParams,\n validateKuaishouParams,\n validateXiaohongshuParams,\n XiaohongshuMethodType\n} from 'amagi/validation'\n\n/**\n * 获取返回类型\n * 类型定义时间:2025-02-02\n *\n * 类型解析模式:\n * - `strict`: 返回严格类型(基于接口响应定义,随时间推移可能缺少未声明的字段)\n * - `loose` 或 `未指定`: 返回宽松的 any 类型(默认)\n *\n * @default 'loose'\n */\nexport type TypeMode = 'strict' | 'loose'\n\n/** 条件类型:根据TypeMode决定返回类型 */\nexport type ConditionalReturnType<T, M extends TypeMode> = M extends 'strict' ? T : any\n\n// 扩展选项类型,添加typeMode属性\nexport type ExtendedDouyinOptions<T extends DouyinMethodType, Opts = Omit<DouyinDataOptionsMap[T]['opt'], 'methodType'>> = Opts & {\n /**\n * 获取返回类型\n * 类型定义时间:2025-02-02\n *\n * 类型解析模式:\n * - `strict`: 返回严格类型(基于接口响应定义,随时间推移可能缺少未声明的字段)\n * - `loose` 或 `未指定`: 返回宽松的 any 类型(默认)\n *\n * @default 'loose'\n */\n typeMode?: TypeMode\n}\n\n// 根据搜索类型推导返回类型的辅助类型\ntype InferDouyinSearchReturnType<Opts, M extends TypeMode> =\n // 先尝试推导 type 字段\n Opts extends { type: infer T }\n ? T extends '综合'\n ? import('amagi/types/ReturnDataType/Douyin/SearchInfo').SearchInfoGeneralData\n : T extends '用户'\n ? import('amagi/types/ReturnDataType/Douyin/SearchInfo').SearchInfoUser\n : T extends '视频'\n ? import('amagi/types/ReturnDataType/Douyin/SearchInfo').SearchInfoVideo\n : DouyinReturnTypeMap['搜索数据']\n : DouyinReturnTypeMap['搜索数据']\n\nexport type ExtendedBilibiliOptions<T extends BilibiliMethodType> = Omit<BilibiliDataOptionsMap[T]['opt'], 'methodType'> & {\n /**\n * 获取返回类型\n * 类型定义时间:2025-02-02\n *\n * 类型解析模式:\n * - `strict`: 返回严格类型(基于接口响应定义,随时间推移可能缺少未声明的字段)\n * - `loose` 或 `未指定`: 返回宽松的 any 类型(默认)\n *\n * @default 'loose'\n */\n typeMode?: TypeMode\n}\n\nexport type ExtendedKuaishouOptions<T extends KuaishouMethodType> = Omit<KuaishouDataOptionsMap[T]['opt'], 'methodType'> & {\n /**\n * 获取返回类型\n * 类型定义时间:2025-02-02\n *\n * 类型解析模式:\n * - `strict`: 返回严格类型(基于接口响应定义,随时间推移可能缺少未声明的字段)\n * - `loose` 或 `未指定`: 返回宽松的 any 类型(默认)\n *\n * @default 'loose'\n */\n typeMode?: TypeMode\n}\n\nexport type ExtendedXiaohongshuOptions<T extends XiaohongshuMethodType> = Omit<XiaohongshuDataOptionsMap[T]['opt'], 'methodType'> & {\n /**\n * 获取返回类型\n * 类型定义时间:2025-02-02\n *\n * 类型解析模式:\n * - `strict`: 返回严格类型(基于接口响应定义,随时间推移可能缺少未声明的字段)\n * - `loose` 或 `未指定`: 返回宽松的 any 类型(默认)\n *\n * @default 'loose'\n */\n typeMode?: TypeMode\n}\n\n/**\n * 获取抖音数据的核心方法(推荐用法:第三个参数为cookie)\n * @param methodType - 请求数据类型\n * @param options - 请求参数对象,包含typeMode属性控制返回类型\n * @param cookie - 可选的用户Cookie\n * @param requestConfig - 可选的请求配置\n * @returns 根据typeMode返回对应类型的数据\n */\nexport function getDouyinData<\n const T extends DouyinMethodType,\n const Opts extends ExtendedDouyinOptions<T>,\n const M extends TypeMode = Opts extends { typeMode: infer Mode extends TypeMode } ? Mode : 'loose'\n> (\n methodType: T,\n options?: Opts,\n cookie?: string,\n requestConfig?: RequestConfig\n): Promise<Result<\n T extends '搜索数据'\n ? InferDouyinSearchReturnType<Opts, M>\n : ConditionalReturnType<DouyinReturnTypeMap[T], M>\n>>\n\n/**\n * 获取抖音数据的核心方法(重载:第二个参数为cookie)\n * @param methodType - 请求数据类型\n * @param cookie - 用户Cookie\n * @param options - 请求参数对象,包含typeMode属性控制返回类型\n * @param requestConfig - 可选的请求配置\n * @returns 根据typeMode返回对应类型的数据\n */\nexport function getDouyinData<\n const T extends DouyinMethodType,\n const Opts extends ExtendedDouyinOptions<T>,\n M extends TypeMode = Opts extends { typeMode: infer Mode extends TypeMode } ? Mode : 'loose'\n> (\n methodType: T,\n cookie: string,\n options?: Opts,\n requestConfig?: RequestConfig\n): Promise<Result<\n T extends '搜索数据'\n ? InferDouyinSearchReturnType<Opts, M>\n : ConditionalReturnType<DouyinReturnTypeMap[T], M>\n>>\n\n/**\n * 获取抖音数据的核心方法实现\n */\nexport async function getDouyinData<\n const T extends DouyinMethodType,\n const Opts extends ExtendedDouyinOptions<T>,\n M extends TypeMode = Opts extends { typeMode: infer Mode extends TypeMode } ? Mode : 'loose'\n> (\n methodType: T,\n optionsOrCookie?: Opts | string,\n cookieOrOptions?: Opts | string,\n requestConfig?: RequestConfig\n): Promise<Result<\n T extends '搜索数据'\n ? InferDouyinSearchReturnType<Opts, M>\n : ConditionalReturnType<DouyinReturnTypeMap[T], M>\n>> {\n try {\n // 判断参数类型并正确分配\n let options: ExtendedDouyinOptions<T> | undefined\n let cookie: string | undefined\n let config: RequestConfig | undefined\n\n if (typeof optionsOrCookie === 'string') {\n // 第二个参数是cookie的情况\n cookie = optionsOrCookie\n options = cookieOrOptions as ExtendedDouyinOptions<T> | undefined\n config = requestConfig\n } else {\n // 第二个参数是options的情况(推荐用法)\n options = optionsOrCookie\n cookie = cookieOrOptions as string | undefined\n config = requestConfig\n }\n\n // 从options中移除typeMode,准备验证参数\n const { typeMode: _, ...validationOptions } = options ?? {}\n\n // 使用Zod验证参数\n const validatedParams = validateDouyinParams(methodType, validationOptions)\n\n // 构造符合原始API期望的参数格式\n const apiParams = {\n ...validatedParams\n } as DouyinDataOptionsMap[T]['opt']\n\n // 调用原始数据获取方法,传递请求配置\n const rawData = await DouyinData(apiParams, cookie, config)\n\n // 返回统一格式的响应\n if (rawData.data === '' || rawData.status_code !== 0) {\n return createErrorResponse(rawData.amagiError, rawData.status_msg ?? '抖音数据获取失败')\n }\n return createSuccessResponse(rawData, '获取成功', 200)\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : '未知错误'\n throw new Error(`抖音数据获取失败: ${errorMessage}`)\n }\n}\n\n/**\n * 获取B站数据的核心方法(推荐用法:第三个参数为cookie)\n * @param methodType - 请求数据类型\n * @param options - 请求参数对象,包含typeMode属性控制返回类型\n * @param cookie - 可选的用户Cookie\n * @returns 根据typeMode返回对应类型的数据\n */\nexport function getBilibiliData<\n T extends BilibiliMethodType,\n M extends TypeMode\n> (\n methodType: T,\n options?: ExtendedBilibiliOptions<T> & { typeMode?: M },\n cookie?: string,\n requestConfig?: RequestConfig\n): Promise<Result<ConditionalReturnType<BilibiliReturnTypeMap[T], M>>>\n\n/**\n * 获取B站数据的核心方法(重载:第二个参数为cookie)\n * @param methodType - 请求数据类型\n * @param cookie - 用户Cookie\n * @param options - 请求参数对象,包含typeMode属性控制返回类型\n * @returns 根据typeMode返回对应类型的数据\n */\nexport function getBilibiliData<\n T extends BilibiliMethodType,\n M extends TypeMode\n> (\n methodType: T,\n cookie: string,\n options?: ExtendedBilibiliOptions<T> & { typeMode?: M },\n requestConfig?: RequestConfig\n): Promise<Result<ConditionalReturnType<BilibiliReturnTypeMap[T], M>>>\n\n/**\n * 获取B站数据的核心方法实现\n */\nexport async function getBilibiliData<T extends BilibiliMethodType, M extends TypeMode> (\n methodType: T,\n optionsOrCookie?: (ExtendedBilibiliOptions<T> & { typeMode?: M }) | string,\n cookieOrOptions?: string | (ExtendedBilibiliOptions<T> & { typeMode?: M }),\n requestConfig?: RequestConfig\n): Promise<Result<ConditionalReturnType<BilibiliReturnTypeMap[T], M>>> {\n try {\n // 判断参数类型并正确分配\n let options: ExtendedBilibiliOptions<T> | undefined\n let cookie: string | undefined\n let config: RequestConfig | undefined\n\n if (typeof optionsOrCookie === 'string') {\n // 第二个参数是cookie的情况\n cookie = optionsOrCookie\n options = cookieOrOptions as ExtendedBilibiliOptions<T> | undefined\n config = requestConfig\n } else {\n // 第二个参数是options的情况(推荐用法)\n options = optionsOrCookie\n cookie = cookieOrOptions as string | undefined\n config = requestConfig\n }\n\n // 从options中移除typeMode,准备验证参数\n const { typeMode: _, ...validationOptions } = options ?? {}\n\n // 使用Zod验证参数\n const validatedParams = validateBilibiliParams(methodType, validationOptions)\n\n // 构造符合原始API期望的参数格式\n const apiParams = {\n ...validatedParams\n } as BilibiliDataOptionsMap[T]['opt']\n\n // 调用原始数据获取方法,传递请求配置\n const rawData = await fetchBilibili(apiParams, cookie, config)\n\n // 返回统一格式的响应\n if (rawData.code !== 0) {\n return createErrorResponse(rawData.amagiError, 'B站数据获取失败', rawData.code, rawData.data)\n }\n return createSuccessResponse(rawData, '获取成功', 200)\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : '未知错误'\n throw new Error(`B站数据获取失败: ${errorMessage}`)\n }\n}\n\n/**\n * 获取快手数据的核心方法(推荐用法:第三个参数为cookie)\n * @param methodType - 请求数据类型\n * @param options - 请求参数对象,包含typeMode属性控制返回类型\n * @param cookie - 可选的用户Cookie\n * @returns 根据typeMode返回对应类型的数据\n */\nexport function getKuaishouData<\n T extends KuaishouMethodType,\n M extends TypeMode\n> (\n methodType: T,\n options?: ExtendedKuaishouOptions<T> & { typeMode?: M },\n cookie?: string,\n requestConfig?: RequestConfig\n): Promise<Result<ConditionalReturnType<KuaishouReturnTypeMap[T], M>>>\n\n/**\n * 获取快手数据的核心方法(重载:第二个参数为cookie)\n * @param methodType - 请求数据类型\n * @param cookie - 用户Cookie\n * @param options - 请求参数对象,包含typeMode属性控制返回类型\n * @returns 根据typeMode返回对应类型的数据\n */\nexport function getKuaishouData<\n T extends KuaishouMethodType,\n M extends TypeMode\n> (\n methodType: T,\n cookie: string,\n options?: ExtendedKuaishouOptions<T> & { typeMode?: M },\n requestConfig?: RequestConfig\n): Promise<Result<ConditionalReturnType<KuaishouReturnTypeMap[T], M>>>\n\n/**\n * 获取快手数据的核心方法实现\n */\nexport async function getKuaishouData<T extends KuaishouMethodType, M extends TypeMode> (\n methodType: T,\n optionsOrCookie?: ExtendedKuaishouOptions<T> | string,\n cookieOrOptions?: string | ExtendedKuaishouOptions<T>,\n requestConfig?: RequestConfig\n): Promise<Result<ConditionalReturnType<KuaishouReturnTypeMap[T], M>>> {\n try {\n // 判断参数类型并正确分配\n let options: ExtendedKuaishouOptions<T> | undefined\n let cookie: string | undefined\n\n if (typeof optionsOrCookie === 'string') {\n // 第二个参数是cookie的情况\n cookie = optionsOrCookie\n options = cookieOrOptions as ExtendedKuaishouOptions<T> | undefined\n } else {\n // 第二个参数是options的情况(推荐用法)\n options = optionsOrCookie\n cookie = cookieOrOptions as string | undefined\n }\n\n // 从options中移除typeMode,准备验证参数\n const { typeMode: _, ...validationOptions } = options ?? {}\n\n // 使用Zod验证参数\n const validatedParams = validateKuaishouParams(methodType, validationOptions)\n\n // 构造符合原始API期望的参数格式\n const apiParams = {\n ...validatedParams\n } as KuaishouDataOptionsMap[T]['opt']\n\n // 调用原始数据获取方法\n const rawData = await KuaishouData(apiParams, cookie)\n\n // 返回统一格式的响应\n if (rawData.code && Object.values(kuaishouAPIErrorCode).includes(rawData.code)) {\n return createErrorResponse(rawData.amagiError, '快手数据获取失败')\n }\n return createSuccessResponse(rawData, '获取成功', 200)\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : '未知错误'\n throw new Error(`快手数据获取失败: ${errorMessage}`)\n }\n}\n\n/**\n * 获取小红书数据的核心方法(推荐用法:第三个参数为cookie)\n * @param methodType - 请求数据类型\n * @param options - 请求参数对象,包含typeMode属性控制返回类型\n * @param cookie - 可选的用户Cookie\n * @returns 根据typeMode返回对应类型的数据\n */\nexport function getXiaohongshuData<\n T extends XiaohongshuMethodType,\n M extends TypeMode\n> (\n methodType: T,\n options?: ExtendedXiaohongshuOptions<T> & { typeMode?: M },\n cookie?: string,\n requestConfig?: RequestConfig\n): Promise<Result<ConditionalReturnType<XiaohongshuDataOptionsMap[T]['data'], M>>>\n\n/**\n * 获取小红书数据的核心方法(重载:第二个参数为cookie)\n * @param methodType - 请求数据类型\n * @param cookie - 用户Cookie\n * @param options - 请求参数对象,包含typeMode属性控制返回类型\n * @returns 根据typeMode返回对应类型的数据\n */\nexport function getXiaohongshuData<\n T extends XiaohongshuMethodType,\n M extends TypeMode\n> (\n methodType: T,\n cookie: string,\n options?: ExtendedXiaohongshuOptions<T> & { typeMode?: M },\n requestConfig?: RequestConfig\n): Promise<Result<ConditionalReturnType<XiaohongshuDataOptionsMap[T]['data'], M>>>\n\n/**\n * 获取小红书数据的核心方法实现\n */\nexport async function getXiaohongshuData<T extends XiaohongshuMethodType, M extends TypeMode> (\n methodType: T,\n optionsOrCookie?: ExtendedXiaohongshuOptions<T> | string,\n cookieOrOptions?: string | ExtendedXiaohongshuOptions<T>,\n requestConfig?: RequestConfig\n): Promise<Result<ConditionalReturnType<XiaohongshuDataOptionsMap[T]['data'], M>>> {\n try {\n // 判断参数类型并正确分配\n let options: ExtendedXiaohongshuOptions<T> | undefined\n let cookie: string | undefined\n\n if (typeof optionsOrCookie === 'string') {\n // 第二个参数是cookie的情况\n cookie = optionsOrCookie\n options = cookieOrOptions as ExtendedXiaohongshuOptions<T> | undefined\n } else {\n // 第二个参数是options的情况(推荐用法)\n options = optionsOrCookie\n cookie = cookieOrOptions as string | undefined\n }\n\n // 从options中移除typeMode,准备验证参数\n const { typeMode: _, ...validationOptions } = options ?? {}\n\n // 使用Zod验证参数\n const validatedParams = validateXiaohongshuParams(methodType, validationOptions)\n\n // 构造符合原始API期望的参数格式\n const apiParams = {\n ...validatedParams\n } as XiaohongshuDataOptionsMap[T]['opt']\n\n // 调用原始数据获取方法\n const rawData = await XiaohongshuData(apiParams, cookie)\n\n // 返回统一格式的响应\n if (rawData.code && Object.values(xiaohongshuAPIErrorCode).includes(rawData.code)) {\n return createErrorResponse(rawData.amagiError, '小红书数据获取失败')\n }\n return createSuccessResponse(rawData, '获取成功', 200)\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : '未知错误'\n throw new Error(`小红书数据获取失败: ${errorMessage}`)\n }\n}\n","import { ConditionalReturnType, ExtendedDouyinOptions, getDouyinData, TypeMode } from 'amagi/model/DataFetchers'\nimport { RequestConfig } from 'amagi/server'\nimport type { DouyinReturnTypeMap } from 'amagi/types/ReturnDataType/Douyin'\nimport { DouyinMethodType, Result } from 'amagi/validation'\n\n/**\n * 创建抖音API方法的通用工厂函数\n * @template T - 抖音方法类型键名\n * @param methodType - 方法类型\n * @returns 返回配置好的API方法\n */\nconst createDouyinApiMethod = <T extends DouyinMethodType> (\n methodType: T\n) => {\n return async <\n const Opts extends ExtendedDouyinOptions<T>,\n M extends TypeMode = Opts extends { typeMode: infer Mode extends TypeMode } ? Mode : 'loose'\n > (\n options: Opts,\n cookie: string,\n requestConfig?: RequestConfig\n ): Promise<Result<\n T extends '搜索数据'\n ? Opts extends { type: infer SearchType }\n ? SearchType extends '综合'\n ? import('amagi/types/ReturnDataType/Douyin/SearchInfo').SearchInfoGeneralData\n : SearchType extends '用户'\n ? import('amagi/types/ReturnDataType/Douyin/SearchInfo').SearchInfoUser\n : SearchType extends '视频'\n ? import('amagi/types/ReturnDataType/Douyin/SearchInfo').SearchInfoVideo\n : DouyinReturnTypeMap[T]\n : DouyinReturnTypeMap[T]\n : ConditionalReturnType<DouyinReturnTypeMap[T], M>\n >> => {\n return await getDouyinData(methodType, options, cookie, requestConfig) as any\n }\n}\n\n/**\n * 创建绑定cookie的抖音API方法工厂函数\n * @template T - 抖音方法类型键名\n * @param methodType - 方法类型\n * @param cookie - 绑定的cookie\n * @returns 返回绑定了cookie的API方法\n */\nconst createBoundDouyinApiMethod = <T extends DouyinMethodType> (\n methodType: T,\n cookie: string,\n requestConfig: RequestConfig\n) => {\n return async <\n const Opts extends ExtendedDouyinOptions<T>,\n M extends TypeMode = Opts extends { typeMode: infer Mode extends TypeMode } ? Mode : 'loose'\n > (\n options: Opts\n ): Promise<Result<\n T extends '搜索数据'\n ? Opts extends { type: infer SearchType }\n ? SearchType extends '综合'\n ? import('amagi/types/ReturnDataType/Douyin/SearchInfo').SearchInfoGeneralData\n : SearchType extends '用户'\n ? import('amagi/types/ReturnDataType/Douyin/SearchInfo').SearchInfoUser\n : SearchType extends '视频'\n ? import('amagi/types/ReturnDataType/Douyin/SearchInfo').SearchInfoVideo\n : DouyinReturnTypeMap[T]\n : DouyinReturnTypeMap[T]\n : ConditionalReturnType<DouyinReturnTypeMap[T], M>\n >> => {\n return await getDouyinData(methodType, options, cookie, requestConfig) as any\n }\n}\n\n/**\n * 封装了所有抖音相关的API请求,采用对象化的方式组织。\n *\n * 提供了一系列方法,用于与抖音相关的 API 进行交互。\n *\n * 每个方法都接受参数和 Cookie,返回 Promise,解析为统一格式的API响应。\n */\nexport const douyin = {\n /**\n * 获取文字作品数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应,包含文字作品详细信息\n */\n getTextWorkInfo: createDouyinApiMethod('文字作品数据'),\n\n /**\n * 聚合解析 (视频/图集/合辑)\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应,包含视频、图集或合辑数据\n */\n getWorkInfo: createDouyinApiMethod('聚合解析'),\n\n /**\n * 获取视频作品数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应,包含视频作品详细信息\n */\n getVideoWorkInfo: createDouyinApiMethod('视频作品数据'),\n\n /**\n * 获取图集作品数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应,包含图集作品详细信息\n */\n getImageAlbumWorkInfo: createDouyinApiMethod('图集作品数据'),\n\n /**\n * 获取合辑作品数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应,包含合辑作品详细信息\n */\n getSlidesWorkInfo: createDouyinApiMethod('合辑作品数据'),\n\n /**\n * 获取评论数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应,包含评论列表数据\n */\n getComments: createDouyinApiMethod('评论数据'),\n\n /**\n * 获取指定评论回复数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应,包含评论回复数据\n */\n getCommentReplies: createDouyinApiMethod('指定评论回复数据'),\n\n /**\n * 获取用户主页数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应,包含用户详细信息\n */\n getUserProfile: createDouyinApiMethod('用户主页数据'),\n\n /**\n * 获取 Emoji 数据\n * @param options 请求参数\n * @param cookie 可选的用户 Cookie\n * @returns 统一格式的API响应,包含Emoji列表数据\n */\n getEmojiList: createDouyinApiMethod('Emoji数据'),\n\n /**\n * 获取动态表情数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应,包含动态表情数据\n */\n getEmojiProList: createDouyinApiMethod('动态表情数据'),\n\n /**\n * 获取用户主页视频列表数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应,包含用户发布的视频列表\n */\n getUserVideos: createDouyinApiMethod('用户主页视频列表数据'),\n\n /**\n * 获取音乐数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应,包含音乐详细信息\n */\n getMusicInfo: createDouyinApiMethod('音乐数据'),\n\n /**\n * 获取热点词数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应,包含热点搜索词列表\n */\n getSuggestWords: createDouyinApiMethod('热点词数据'),\n\n /**\n * 获取搜索数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应,包含搜索结果数据\n */\n search: createDouyinApiMethod('搜索数据'),\n\n /**\n * 获取直播间信息\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应,包含直播间详细信息\n */\n getLiveRoomInfo: createDouyinApiMethod('直播间信息数据'),\n\n /**\n * 获取弹幕数据\n * @param options 请求参数\n * @returns 统一格式的API响应,包含弹幕数据\n */\n getDanmaku: createDouyinApiMethod('弹幕数据'),\n\n /**\n * 调用抖音API方法\n * @param methodType 抖音API方法类型\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @param requestConfig 可选的请求配置\n * @returns 统一格式的API响应,包含方法返回的数据\n */\n invoke: async <\n const T extends DouyinMethodType,\n const Opts extends ExtendedDouyinOptions<T>,\n M extends TypeMode = Opts extends { typeMode: infer Mode extends TypeMode } ? Mode : 'loose'\n > (\n methodType: T,\n options: Opts,\n cookie: string,\n requestConfig?: RequestConfig\n ): Promise<Result<\n T extends '搜索数据'\n ? Opts extends { type: infer SearchType }\n ? SearchType extends '综合'\n ? import('amagi/types/ReturnDataType/Douyin/SearchInfo').SearchInfoGeneralData\n : SearchType extends '用户'\n ? import('amagi/types/ReturnDataType/Douyin/SearchInfo').SearchInfoUser\n : SearchType extends '视频'\n ? import('amagi/types/ReturnDataType/Douyin/SearchInfo').SearchInfoVideo\n : DouyinReturnTypeMap[T]\n : DouyinReturnTypeMap[T]\n : ConditionalReturnType<DouyinReturnTypeMap[T], M>\n >> => {\n return await getDouyinData(methodType, options, cookie, requestConfig) as any\n }\n}\n\n/**\n * 创建绑定了cookie的抖音API对象\n * @param cookie - 要绑定的cookie\n * @returns 绑定了cookie的抖音API对象,调用时不需要再传递cookie\n */\nexport const createBoundDouyinApi = (cookie: string, requestConfig: RequestConfig) => {\n return {\n /**\n * 获取文字作品数据\n * @param options 请求参数\n * @returns 统一格式的API响应,包含文字作品详细信息\n */\n getTextWorkInfo: createBoundDouyinApiMethod('文字作品数据', cookie, requestConfig),\n\n /**\n * 聚合解析 (视频/图集/合辑)\n * @param options 请求参数\n * @returns 统一格式的API响应,包含视频、图集或合辑数据\n */\n getWorkInfo: createBoundDouyinApiMethod('聚合解析', cookie, requestConfig),\n\n /**\n * 获取视频作品数据\n * @param options 请求参数\n * @returns 统一格式的API响应,包含视频作品详细信息\n */\n getVideoWorkInfo: createBoundDouyinApiMethod('视频作品数据', cookie, requestConfig),\n\n /**\n * 获取图集作品数据\n * @param options 请求参数\n * @returns 统一格式的API响应,包含图集作品详细信息\n */\n getImageAlbumWorkInfo: createBoundDouyinApiMethod('图集作品数据', cookie, requestConfig),\n\n /**\n * 获取合辑作品数据\n * @param options 请求参数\n * @returns 统一格式的API响应,包含合辑作品详细信息\n */\n getSlidesWorkInfo: createBoundDouyinApiMethod('合辑作品数据', cookie, requestConfig),\n\n /**\n * 获取评论数据\n * @param options 请求参数\n * @returns 统一格式的API响应,包含评论列表数据\n */\n getComments: createBoundDouyinApiMethod('评论数据', cookie, requestConfig),\n\n /**\n * 获取指定评论回复数据\n * @param options 请求参数\n * @returns 统一格式的API响应,包含评论回复数据\n */\n getCommentReplies: createBoundDouyinApiMethod('指定评论回复数据', cookie, requestConfig),\n\n /**\n * 获取用户主页数据\n * @param options 请求参数\n * @returns 统一格式的API响应,包含用户详细信息\n */\n getUserProfile: createBoundDouyinApiMethod('用户主页数据', cookie, requestConfig),\n\n /**\n * 获取 Emoji 数据\n * @param options 请求参数\n * @returns 统一格式的API响应,包含Emoji列表数据\n */\n getEmojiList: createBoundDouyinApiMethod('Emoji数据', cookie, requestConfig),\n\n /**\n * 获取动态表情数据\n * @param options 请求参数\n * @returns 统一格式的API响应,包含动态表情数据\n */\n getEmojiProList: createBoundDouyinApiMethod('动态表情数据', cookie, requestConfig),\n\n /**\n * 获取用户主页视频列表数据\n * @param options 请求参数\n * @returns 统一格式的API响应,包含用户发布的视频列表\n */\n getUserVideos: createBoundDouyinApiMethod('用户主页视频列表数据', cookie, requestConfig),\n\n /**\n * 获取音乐数据\n * @param options 请求参数\n * @returns 统一格式的API响应,包含音乐详细信息\n */\n getMusicInfo: createBoundDouyinApiMethod('音乐数据', cookie, requestConfig),\n\n /**\n * 获取热点词数据\n * @param options 请求参数\n * @returns 统一格式的API响应,包含热点搜索词列表\n */\n getSuggestWords: createBoundDouyinApiMethod('热点词数据', cookie, requestConfig),\n\n /**\n * 获取搜索数据\n * @param options 请求参数\n * @returns 统一格式的API响应,包含搜索结果数据\n */\n getSearchData: createBoundDouyinApiMethod('搜索数据', cookie, requestConfig),\n\n /**\n * 获取直播间信息\n * @param options 请求参数\n * @returns 统一格式的API响应,包含直播间详细信息\n */\n getLiveRoomInfo: createBoundDouyinApiMethod('直播间信息数据', cookie, requestConfig),\n\n /**\n * 获取弹幕数据\n * @param options 请求参数\n * @returns 统一格式的API响应,包含弹幕数据\n */\n getDanmaku: createBoundDouyinApiMethod('弹幕数据', cookie, requestConfig),\n\n /**\n * 调用抖音API方法\n * @param methodType 抖音API方法类型\n * @param options 请求参数\n * @returns 统一格式的API响应,包含方法返回的数据\n */\n invoke: async <\n const T extends DouyinMethodType,\n const Opts extends ExtendedDouyinOptions<T>,\n M extends TypeMode = Opts extends { typeMode: infer Mode extends TypeMode } ? Mode : 'loose'\n > (\n methodType: T,\n options: Opts\n ): Promise<Result<\n T extends '搜索数据'\n ? Opts extends { type: infer SearchType }\n ? SearchType extends '综合'\n ? import('amagi/types/ReturnDataType/Douyin/SearchInfo').SearchInfoGeneralData\n : SearchType extends '用户'\n ? import('amagi/types/ReturnDataType/Douyin/SearchInfo').SearchInfoUser\n : SearchType extends '视频'\n ? import('amagi/types/ReturnDataType/Douyin/SearchInfo').SearchInfoVideo\n : DouyinReturnTypeMap[T]\n : DouyinReturnTypeMap[T]\n : ConditionalReturnType<DouyinReturnTypeMap[T], M>\n >> => {\n return await getDouyinData(methodType, options, cookie, requestConfig) as any\n }\n }\n}\n\n/**\n * 绑定cookie的抖音API对象类型\n */\nexport type BoundDouyinApi = ReturnType<typeof createBoundDouyinApi>\n","import { createDouyinValidationMiddleware } from 'amagi/middleware/validation'\nimport { getDouyinData } from 'amagi/model/DataFetchers'\nimport { getDouyinDefaultConfig } from 'amagi/platform/defaultConfigs'\nimport { RequestConfig } from 'amagi/server'\nimport { DouyinDataOptionsMap } from 'amagi/types'\nimport { handleError } from 'amagi/utils/errors'\nimport { DouyinMethodType, Result } from 'amagi/validation'\nimport { DouyinMethodRoutes } from 'amagi/validation/douyin'\nimport express from 'express'\n\n/**\n * 创建抖音路由处理器\n * @param dataFetcher - 抖音数据获取函数\n * @param methodType - 抖音方法类型\n * @param cookie - Cookie字符串\n * @param requestConfig - 可选的请求配置\n * @returns Express路由处理器\n */\nconst createDouyinRouteHandler = <T extends DouyinMethodType> (\n dataFetcher: <K extends DouyinMethodType>(\n methodType: K,\n options?: Omit<DouyinDataOptionsMap[K]['opt'], 'methodType'>,\n cookie?: string,\n requestConfig?: RequestConfig\n ) => Promise<Result<DouyinDataOptionsMap[T]['data']>>,\n methodType: T,\n cookie: string,\n requestConfig: RequestConfig = getDouyinDefaultConfig(cookie)\n) => {\n return async (req: any, res: any) => {\n try {\n const result = await dataFetcher(methodType, req.validatedParams, cookie, requestConfig)\n res.json({\n ...result,\n requestPath: req.originalUrl\n })\n } catch (error) {\n const errorResponse = handleError(error)\n res.status(errorResponse.code || 500).json({\n ...errorResponse,\n requestPath: req.originalUrl\n })\n }\n }\n}\n\n/**\n * 创建抖音路由\n * @param cookie - 抖音Cookie\n * @param requestConfig - 可选的请求配置\n * @returns Express路由器\n */\nexport const createDouyinRoutes = (cookie: string, requestConfig: RequestConfig = getDouyinDefaultConfig(cookie)): express.Router => {\n const router = express.Router()\n\n for (const [method, path] of Object.entries(DouyinMethodRoutes)) {\n router.get(path,\n createDouyinValidationMiddleware(method as DouyinMethodType),\n createDouyinRouteHandler(getDouyinData, method as DouyinMethodType, cookie, requestConfig)\n )\n }\n\n return router\n}\n","import { douyinApiUrls } from './API'\nimport { douyin } from './DouyinApi'\nimport { douyinSign } from './sign'\n\nexport * from './DouyinApi'\nexport * from './routes'\nexport { douyinApiUrls, douyinSign }\n\ntype douyinUtilsModel = {\n /** 签名算法相关 */\n sign: typeof import('amagi/platform/douyin/sign').douyinSign\n\n /**\n * 该类下的所有方法只会返回拼接好参数后的 Url 地址,需要手动请求该地址以获取数据\n *\n * 缺少 `a_bougs` 参数,请自行生成拼接\n */\n douyinApiUrls: typeof import('amagi/platform/douyin/API').douyinApiUrls\n\n /**\n * 封装了所有抖音相关的API请求,采用对象化的方式组织。\n *\n * 提供了一系列方法,用于与抖音相关的 API 进行交互。\n *\n * 每个方法都接受参数和 Cookie,返回 Promise,解析为接口返回的原始数据。\n */\n api: typeof import('amagi/platform/douyin/DouyinApi').douyin\n}\n\n/** 抖音相关功能模块 (工具集) */\nexport const douyinUtils: douyinUtilsModel = {\n sign: douyinSign,\n douyinApiUrls,\n api: douyin\n}\n","import { ConditionalReturnType, ExtendedKuaishouOptions, getKuaishouData, TypeMode } from 'amagi/model/DataFetchers'\nimport { RequestConfig } from 'amagi/server'\nimport {\n KuaishouDataOptionsMap\n} from 'amagi/types'\nimport { Result } from 'amagi/validation'\n\n/**\n * 创建快手API方法的通用工厂函数\n * @template T - 快手方法类型键名\n * @param methodType - 方法类型\n * @returns 返回配置好的API方法\n */\nconst createKuaishouApiMethod = <T extends keyof KuaishouDataOptionsMap> (\n methodType: T\n) => {\n return async <M extends TypeMode> (\n options: ExtendedKuaishouOptions<T> & { typeMode?: M },\n cookie?: string\n ): Promise<Result<ConditionalReturnType<KuaishouDataOptionsMap[T]['data'], M>>> => {\n return await getKuaishouData(methodType, options, cookie)\n }\n}\n\n/**\n * 创建绑定cookie的快手API方法工厂函数\n * @template T - 快手方法类型键名\n * @param methodType - 方法类型\n * @param cookie - 绑定的cookie\n * @returns 返回绑定了cookie的API方法\n */\nconst createBoundKuaishouApiMethod = <T extends keyof KuaishouDataOptionsMap> (\n methodType: T,\n cookie?: string\n) => {\n return async <M extends TypeMode> (\n options: ExtendedKuaishouOptions<T> & { typeMode?: M }\n ): Promise<Result<ConditionalReturnType<KuaishouDataOptionsMap[T]['data'], M>>> => {\n return await getKuaishouData(methodType, options, cookie)\n }\n}\n\n/**\n * 快手相关 API 的命名空间。\n */\nexport const kuaishou = {\n /**\n * 获取单个视频作品数据\n * @param options 请求参数\n * @param cookie 可选的用户 Cookie\n * @returns 统一格式的API响应\n */\n getWorkInfo: createKuaishouApiMethod('单个视频作品数据'),\n\n /**\n * 获取评论数据\n * @param options 请求参数\n * @param cookie 可选的用户 Cookie\n * @returns 统一格式的API响应\n */\n getComments: createKuaishouApiMethod('评论数据'),\n\n /**\n * 获取 Emoji 数据\n * @param options 请求参数\n * @param cookie 可选的用户 Cookie\n * @returns 统一格式的API响应\n */\n getEmojiList: createKuaishouApiMethod('Emoji数据')\n}\n\n/**\n * 创建绑定了cookie的快手API对象\n * @param cookie - 要绑定的cookie(可选)\n * @returns 绑定了cookie的快手API对象,调用时不需要再传递cookie\n */\nexport const createBoundKuaishouApi = (cookie: string, requestConfig: RequestConfig) => {\n return {\n /**\n * 获取单个视频作品数据\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n getWorkInfo: createBoundKuaishouApiMethod('单个视频作品数据', cookie),\n\n /**\n * 获取评论数据\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n getComments: createBoundKuaishouApiMethod('评论数据', cookie),\n\n /**\n * 获取 Emoji 数据\n * @param options 请求参数\n * @returns 统一格式的API响应\n */\n getEmojiList: createBoundKuaishouApiMethod('Emoji数据', cookie)\n }\n}\n\n/**\n * 绑定cookie的快手API对象类型\n */\nexport type BoundKuaishouApi = ReturnType<typeof createBoundKuaishouApi>\n","import { createKuaishouValidationMiddleware } from 'amagi/middleware/validation'\nimport { getKuaishouData } from 'amagi/model/DataFetchers'\nimport { getKuaishouDefaultConfig } from 'amagi/platform/defaultConfigs'\nimport { RequestConfig } from 'amagi/server'\nimport { KuaishouDataOptionsMap } from 'amagi/types'\nimport { handleError } from 'amagi/utils/errors'\nimport { KuaishouMethodType, Result } from 'amagi/validation'\nimport { KuaishouMethodRoutes } from 'amagi/validation/kuaishou'\nimport express from 'express'\n\n/**\n * 创建快手路由处理器\n * @param dataFetcher - 快手数据获取函数\n * @param methodType - 快手方法类型\n * @param cookie - Cookie字符串\n * @returns Express路由处理器\n */\nconst createKuaishouRouteHandler = <T extends KuaishouMethodType> (\n dataFetcher: <K extends KuaishouMethodType>(\n methodType: K,\n options?: Omit<KuaishouDataOptionsMap[K]['opt'], 'methodType'>,\n cookie?: string,\n requestConfig?: RequestConfig\n ) => Promise<Result<KuaishouDataOptionsMap[T]['data']>>,\n methodType: T,\n cookie: string,\n requestConfig: RequestConfig = getKuaishouDefaultConfig(cookie)\n) => {\n return async (req: any, res: any) => {\n try {\n const result = await dataFetcher(methodType, req.validatedParams, cookie, requestConfig)\n res.json({\n ...result,\n requestPath: req.originalUrl\n })\n } catch (error) {\n const errorResponse = handleError(error)\n res.status(errorResponse.code || 500).json({\n ...errorResponse,\n requestPath: req.originalUrl\n })\n }\n }\n}\n\n/**\n * 创建快手路由\n * @param cookie - 快手Cookie\n * @param requestConfig - 可选的请求配置\n * @returns Express路由器\n */\nexport const createKuaishouRoutes = (cookie: string, requestConfig: RequestConfig = getKuaishouDefaultConfig(cookie)): express.Router => {\n const router = express.Router()\n\n for (const [method, path] of Object.entries(KuaishouMethodRoutes)) {\n router.get(path,\n createKuaishouValidationMiddleware(method as KuaishouMethodType),\n createKuaishouRouteHandler(getKuaishouData, method as KuaishouMethodType, cookie, requestConfig)\n )\n }\n\n return router\n}\n","import { kuaishouApiUrls } from './API'\nimport { kuaishou } from './KuaishouApi'\nimport { createKuaishouRoutes } from './routes'\n\nexport * from './KuaishouApi'\nexport * from './routes'\nexport { createKuaishouRoutes, kuaishouApiUrls }\n\ntype kuaishouUtilsModel = {\n /** 该类下的所有方法只会返回拼接好参数后的 Url 地址和请求体,需要手动请求该地址以获取数据 */\n kuaishouApiUrls: typeof import('amagi/platform/kuaishou/API').kuaishouApiUrls\n\n /**\n * 封装了所有快手相关的API请求,采用对象化的方式组织。\n *\n * 提供了一系列方法,用于与抖音相关的 API 进行交互。\n *\n * 每个方法都接受参数和 Cookie,返回 Promise,解析为接口返回的原始数据。\n */\n api: typeof import('amagi/platform/kuaishou/KuaishouApi').kuaishou\n}\n\n/** 快手相关功能模块 (工具集) */\nexport const kuaishouUtils: kuaishouUtilsModel = {\n kuaishouApiUrls,\n api: kuaishou\n}\n","import { ConditionalReturnType, ExtendedXiaohongshuOptions, getXiaohongshuData, TypeMode } from 'amagi/model/DataFetchers'\nimport { RequestConfig } from 'amagi/server'\nimport {\n XiaohongshuDataOptionsMap\n} from 'amagi/types'\nimport { Result } from 'amagi/validation'\n\n/**\n * 创建小红书API方法的通用工厂函数\n * @template T - 小红书方法类型键名\n * @param methodType - 方法类型\n * @returns 返回配置好的API方法\n */\nconst createXiaohongshuApiMethod = <T extends keyof XiaohongshuDataOptionsMap> (\n methodType: T\n) => {\n return async <M extends TypeMode> (\n options: ExtendedXiaohongshuOptions<T> & { typeMode?: M },\n cookie: string,\n requestConfig?: RequestConfig\n ): Promise<Result<ConditionalReturnType<XiaohongshuDataOptionsMap[T]['data'], M>>> => {\n return await getXiaohongshuData(methodType, options, cookie, requestConfig)\n }\n}\n\n/**\n * 创建绑定cookie的小红书API方法工厂函数\n * @template T - 小红书方法类型键名\n * @param methodType - 方法类型\n * @param cookie - 绑定的cookie\n * @returns 返回绑定了cookie的API方法\n */\nconst createBoundXiaohongshuApiMethod = <T extends keyof XiaohongshuDataOptionsMap> (\n methodType: T,\n cookie: string,\n requestConfig: RequestConfig\n) => {\n return async <M extends TypeMode> (\n options: ExtendedXiaohongshuOptions<T> & { typeMode?: M }\n ): Promise<Result<ConditionalReturnType<XiaohongshuDataOptionsMap[T]['data'], M>>> => {\n return await getXiaohongshuData(methodType, options, cookie, requestConfig)\n }\n}\n\n/**\n * 封装了所有小红书相关的API请求,采用对象化的方式组织。\n *\n * 提供了一系列方法,用于与小红书相关的 API 进行交互。\n *\n * 每个方法都接受参数和 Cookie,返回 Promise,解析为统一格式的API响应。\n */\nexport const xiaohongshu = {\n /**\n * 获取首页推荐数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应,包含首页推荐笔记列表\n */\n getHomeFeed: createXiaohongshuApiMethod('首页推荐数据'),\n /**\n * 获取单个笔记数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应,包含指定笔记的详细信息\n */\n getNote: createXiaohongshuApiMethod('单个笔记数据'),\n /**\n * 获取评论数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应,包含指定笔记的评论列表\n */\n getComments: createXiaohongshuApiMethod('评论数据'),\n /**\n * 获取用户数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应,包含指定用户的详细信息\n */\n getUser: createXiaohongshuApiMethod('用户数据'),\n /**\n * 获取用户笔记数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应,包含指定用户的笔记列表\n */\n getUserNotes: createXiaohongshuApiMethod('用户笔记数据'),\n /**\n * 获取搜索笔记数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应,包含搜索到的笔记列表\n */\n getSearchNotes: createXiaohongshuApiMethod('搜索笔记'),\n /**\n * 获取表情列表数据\n * @param options 请求参数\n * @param cookie 有效的用户 Cookie\n * @returns 统一格式的API响应,包含表情列表\n */\n getEmojiList: createXiaohongshuApiMethod('表情列表')\n}\n\n/**\n * 创建绑定了cookie的小红书API对象\n * @param cookie - 要绑定的cookie\n * @returns 绑定了cookie的小红书API对象,调用时不需要再传递cookie\n */\nexport const createBoundXiaohongshuApi = (cookie: string, requestConfig: RequestConfig) => {\n return {\n /**\n * 获取首页推荐数据\n * @param options 请求参数\n * @returns 统一格式的API响应,包含首页推荐笔记列表\n */\n getHomeFeed: createBoundXiaohongshuApiMethod('首页推荐数据', cookie, requestConfig),\n /**\n * 获取单个笔记数据\n * @param options 请求参数\n * @returns 统一格式的API响应,包含指定笔记的详细信息\n */\n getNote: createBoundXiaohongshuApiMethod('单个笔记数据', cookie, requestConfig),\n /**\n * 获取评论数据\n * @param options 请求参数\n * @returns 统一格式的API响应,包含指定笔记的评论列表\n */\n getComments: createBoundXiaohongshuApiMethod('评论数据', cookie, requestConfig),\n /**\n * 获取用户数据\n * @param options 请求参数\n * @returns 统一格式的API响应,包含指定用户的详细信息\n */\n getUser: createBoundXiaohongshuApiMethod('用户数据', cookie, requestConfig),\n /**\n * 获取用户笔记数据\n * @param options 请求参数\n * @returns 统一格式的API响应,包含指定用户的笔记列表\n */\n getUserNotes: createBoundXiaohongshuApiMethod('用户笔记数据', cookie, requestConfig),\n /**\n * 获取搜索笔记数据\n * @param options 请求参数\n * @returns 统一格式的API响应,包含搜索到的笔记列表\n */\n getSearchNotes: createBoundXiaohongshuApiMethod('搜索笔记', cookie, requestConfig),\n /**\n * 获取表情列表数据\n * @param options 请求参数\n * @returns 统一格式的API响应,包含表情列表\n */\n getEmojiList: createBoundXiaohongshuApiMethod('表情列表', cookie, requestConfig)\n }\n}\n\n/**\n * 绑定cookie的小红书API对象类型\n */\nexport type BoundXiaohongshuApi = ReturnType<typeof createBoundXiaohongshuApi>\n","import { createXiaohongshuValidationMiddleware } from 'amagi/middleware/validation'\nimport { getXiaohongshuData } from 'amagi/model/DataFetchers'\nimport { getXiaohongshuDefaultConfig } from 'amagi/platform/defaultConfigs'\nimport { RequestConfig } from 'amagi/server'\nimport { XiaohongshuDataOptionsMap } from 'amagi/types'\nimport { handleError } from 'amagi/utils/errors'\nimport { Result, XiaohongshuMethodType } from 'amagi/validation'\nimport { XiaohongshuMethodRoutes } from 'amagi/validation/xiaohongshu'\nimport express from 'express'\n\n/**\n * 创建小红书路由处理器\n * @param dataFetcher - 小红书数据获取函数\n * @param methodType - 小红书方法类型\n * @param cookie - Cookie字符串\n * @param requestConfig - 可选的请求配置\n * @returns Express路由处理器\n */\nconst createXiaohongshuRouteHandler = <T extends XiaohongshuMethodType> (\n dataFetcher: <K extends XiaohongshuMethodType>(\n methodType: K,\n options?: Omit<XiaohongshuDataOptionsMap[K]['opt'], 'methodType'>,\n cookie?: string,\n requestConfig?: RequestConfig\n ) => Promise<Result<XiaohongshuDataOptionsMap[T]['data']>>,\n methodType: T,\n cookie: string,\n requestConfig: RequestConfig = getXiaohongshuDefaultConfig(cookie)\n) => {\n return async (req: any, res: any) => {\n try {\n const result = await dataFetcher(methodType, req.validatedParams, cookie, requestConfig)\n res.json({\n ...result,\n requestPath: req.originalUrl\n })\n } catch (error) {\n const errorResponse = handleError(error)\n res.status(errorResponse.code || 500).json({\n ...errorResponse,\n requestPath: req.originalUrl\n })\n }\n }\n}\n\n/**\n * 创建小红书路由\n * @param cookie - 小红书Cookie\n * @param requestConfig - 可选的请求配置\n * @returns Express路由器\n */\nexport const createXiaohongshuRoutes = (cookie: string, requestConfig: RequestConfig = getXiaohongshuDefaultConfig(cookie)): express.Router => {\n const router = express.Router()\n\n for (const [method, path] of Object.entries(XiaohongshuMethodRoutes)) {\n router.get(path,\n createXiaohongshuValidationMiddleware(method as XiaohongshuMethodType),\n createXiaohongshuRouteHandler(getXiaohongshuData, method as XiaohongshuMethodType, cookie, requestConfig)\n )\n }\n\n return router\n}\n","import { xiaohongshuApiUrls } from './API'\nimport { xiaohongshuSign } from './sign'\nimport { xiaohongshu } from './XiaohongshuApi'\n\nexport * from './routes'\nexport * from './XiaohongshuApi'\nexport { xiaohongshuApiUrls, xiaohongshuSign }\n\ntype xiaohongshuUtilsModel = {\n /** 签名算法相关 */\n sign: typeof import('amagi/platform/xiaohongshu/sign').xiaohongshuSign\n\n /**\n * 该类下的所有方法只会返回拼接好参数后的 Url 地址,需要手动请求该地址以获取数据\n */\n xiaohongshuApiUrls: typeof import('amagi/platform/xiaohongshu/API').xiaohongshuApiUrls\n\n /**\n * 封装了所有小红书相关的API请求,采用对象化的方式组织。\n *\n * 提供了一系列方法,用于与小红书相关的 API 进行交互。\n *\n * 每个方法都接受参数和 Cookie,返回 Promise,解析为接口返回的原始数据。\n */\n api: typeof import('amagi/platform/xiaohongshu/XiaohongshuApi').xiaohongshu\n}\n\n/** 小红书相关功能模块 (工具集) */\nexport const xiaohongshuUtils: xiaohongshuUtilsModel = {\n sign: xiaohongshuSign,\n xiaohongshuApiUrls,\n api: xiaohongshu\n}\n","import { initLogger, logger } from 'amagi/model'\nimport { ConditionalReturnType, ExtendedBilibiliOptions, ExtendedDouyinOptions, ExtendedKuaishouOptions, ExtendedXiaohongshuOptions, getBilibiliData, getDouyinData, getKuaishouData, getXiaohongshuData, TypeMode } from 'amagi/model/DataFetchers'\nimport { bilibiliUtils, createBilibiliRoutes, createDouyinRoutes, createKuaishouRoutes, douyinUtils, kuaishouUtils } from 'amagi/platform'\nimport { createBoundBilibiliApi } from 'amagi/platform/bilibili/BilibiliApi'\nimport { createBoundDouyinApi } from 'amagi/platform/douyin/DouyinApi'\nimport { createBoundKuaishouApi } from 'amagi/platform/kuaishou/KuaishouApi'\nimport { createBoundXiaohongshuApi, createXiaohongshuRoutes, xiaohongshuUtils } from 'amagi/platform/xiaohongshu'\nimport { BilibiliDataOptionsMap, DouyinDataOptionsMap, KuaishouDataOptionsMap, XiaohongshuDataOptionsMap } from 'amagi/types'\nimport { BilibiliMethodType, DouyinMethodType, KuaishouMethodType, Result } from 'amagi/validation'\nimport { XiaohongshuMethodType } from 'amagi/validation/xiaohongshu'\nimport { AxiosRequestConfig } from 'axios'\nimport express from 'express'\n\n/**\n * 请求配置选项接口\n */\nexport type RequestConfig = Omit<AxiosRequestConfig, 'url' | 'method' | 'data'>\n\n/**\n * Cookie配置选项接口\n */\nexport type CookieConfig = {\n /** 抖音Cookie */\n douyin?: string\n /** B站Cookie */\n bilibili?: string\n /** 快手Cookie */\n kuaishou?: string\n /** 小红书Cookie */\n xiaohongshu?: string\n}\n\n/**\n * 客户端配置选项接口\n */\nexport type Options = {\n /** Cookie配置 */\n cookies?: CookieConfig\n /** 请求配置 */\n request?: Omit<AxiosRequestConfig, 'url' | 'method' | 'data'>\n}\n\n/**\n * 创建Amagi客户端实例\n * @param options - 客户端配置选项,包含Cookie和请求配置\n * @returns 包含数据获取方法、服务器启动方法、绑定Cookie的平台工具集和API对象的对象\n */\nexport const createAmagiClient = (options?: Options) => {\n const douyinCookie = options?.cookies?.douyin ?? ''\n const bilibiliCookie = options?.cookies?.bilibili ?? ''\n const kuaishouCookie = options?.cookies?.kuaishou ?? ''\n const xiaohongshuCookie = options?.cookies?.xiaohongshu ?? ''\n const requestConfig = options?.request ?? {}\n\n /**\n * 启动本地HTTP服务\n * @param port - 监听端口,默认4567\n * @returns Express应用实例\n */\n const startServer = (port = 4567): express.Application => {\n initLogger()\n const app = express()\n\n // 解析JSON请求体\n app.use(express.json())\n app.use(express.urlencoded({ extended: true }))\n\n // 根路径重定向到文档\n app.get('/', (_req, res) => {\n res.redirect(301, 'https://amagi.apifox.cn')\n })\n\n app.get('/docs', (_req, res) => {\n res.redirect(301, 'https://amagi.apifox.cn')\n })\n\n // 注册平台路由\n app.use('/api/douyin', createDouyinRoutes(douyinCookie, requestConfig))\n app.use('/api/bilibili', createBilibiliRoutes(bilibiliCookie, requestConfig))\n app.use('/api/kuaishou', createKuaishouRoutes(kuaishouCookie, requestConfig))\n app.use('/api/xiaohongshu', createXiaohongshuRoutes(xiaohongshuCookie, requestConfig))\n\n // 启动服务\n app.listen(port, '::', () => {\n logger.mark(`Amagi server listening on ${logger.green(`http://localhost:${port}`)} ${logger.yellow('API docs: https://amagi.apifox.cn ')}`)\n })\n\n return app\n }\n\n /**\n * 获取抖音数据\n * @param methodType - 请求数据类型\n * @param options - 请求参数\n * @returns 返回包装在data字段中的数据\n */\n const getDouyinDataWithCookie = async <\n const T extends DouyinMethodType,\n const Opts extends ExtendedDouyinOptions<T>,\n M extends TypeMode = Opts extends { typeMode: infer Mode extends TypeMode } ? Mode : 'loose'\n > (\n methodType: T,\n options?: Opts\n ): Promise<Result<\n T extends '搜索数据'\n ? Opts extends { type: infer SearchType }\n ? SearchType extends '综合'\n ? import('amagi/types/ReturnDataType/Douyin/SearchInfo').SearchInfoGeneralData\n : SearchType extends '用户'\n ? import('amagi/types/ReturnDataType/Douyin/SearchInfo').SearchInfoUser\n : SearchType extends '视频'\n ? import('amagi/types/ReturnDataType/Douyin/SearchInfo').SearchInfoVideo\n : DouyinDataOptionsMap[T]['data']\n : DouyinDataOptionsMap[T]['data']\n : ConditionalReturnType<DouyinDataOptionsMap[T]['data'], M>\n >> => {\n return await getDouyinData(methodType, options, douyinCookie, requestConfig)\n }\n\n /**\n * 获取B站数据\n * @param methodType - 请求数据类型\n * @param options - 请求参数\n * @returns 返回包装在data字段中的数据\n */\n const getBilibiliDataWithCookie = async <T extends BilibiliMethodType, M extends TypeMode> (\n methodType: T,\n options?: ExtendedBilibiliOptions<T> & { typeMode?: M }\n ): Promise<Result<ConditionalReturnType<BilibiliDataOptionsMap[T]['data'], M>>> => {\n return await getBilibiliData(methodType, options, bilibiliCookie, requestConfig)\n }\n\n /**\n * 获取快手数据\n * @param methodType - 请求数据类型\n * @param options - 请求参数\n * @returns 返回包装在data字段中的数据\n */\n const getKuaishouDataWithCookie = async <T extends KuaishouMethodType, M extends TypeMode> (\n methodType: T,\n options?: ExtendedKuaishouOptions<T> & { typeMode?: M }\n ): Promise<Result<ConditionalReturnType<KuaishouDataOptionsMap[T]['data'], M>>> => {\n return await getKuaishouData(methodType, options, kuaishouCookie, requestConfig)\n }\n /**\n * 获取小红书数据\n * @param methodType - 请求数据类型\n * @param options - 请求参数\n * @returns 返回包装在data字段中的数据\n */\n const getXiaohongshuDataWithCookie = async <T extends XiaohongshuMethodType, M extends TypeMode> (\n methodType: T,\n options?: ExtendedXiaohongshuOptions<T> & { typeMode?: M }\n ): Promise<Result<ConditionalReturnType<XiaohongshuDataOptionsMap[T]['data'], M>>> => {\n return await getXiaohongshuData(methodType, options, xiaohongshuCookie, requestConfig)\n }\n\n return {\n /** 启动本地HTTP服务 */\n startServer,\n /** 获取抖音数据 */\n getDouyinData: getDouyinDataWithCookie,\n /** 获取B站数据 */\n getBilibiliData: getBilibiliDataWithCookie,\n /** 获取快手数据 */\n getKuaishouData: getKuaishouDataWithCookie,\n /** 获取小红书数据 */\n getXiaohongshuData: getXiaohongshuDataWithCookie,\n douyin: {\n ...douyinUtils,\n /** 绑定了cookie和请求配置的抖音API对象,调用时不需要传递cookie */\n api: createBoundDouyinApi(douyinCookie, requestConfig)\n },\n bilibili: {\n ...bilibiliUtils,\n /** 绑定了cookie和请求配置的B站API对象,调用时不需要传递cookie */\n api: createBoundBilibiliApi(bilibiliCookie, requestConfig)\n },\n kuaishou: {\n ...kuaishouUtils,\n /** 绑定了cookie和请求配置的快手API对象,调用时不需要传递cookie */\n api: createBoundKuaishouApi(kuaishouCookie, requestConfig)\n },\n xiaohongshu: {\n ...xiaohongshuUtils,\n /** 绑定了cookie和请求配置的小红书API对象,调用时不需要传递cookie */\n api: createBoundXiaohongshuApi(xiaohongshuCookie, requestConfig)\n }\n }\n}\n\n// 导出默认客户端创建函数\nexport default createAmagiClient\n","export interface BilibiliMethodOptionsMap {\n VideoInfoParams: {\n methodType: '单个视频作品数据'\n /** 稿件BVID */\n bvid: string\n },\n VideoStreamParams: {\n methodType: '单个视频下载信息数据'\n /** 稿件AVID */\n avid: number\n /** 稿件cid */\n cid: number\n },\n CommentParams: {\n methodType: '评论数据'\n /** 评论区类型代码,详见 [评论区类型代码](https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/comment/readme.md#%E8%AF%84%E8%AE%BA%E5%8C%BA%E7%B1%BB%E5%9E%8B%E4%BB%A3%E7%A0%81) */\n type: CommentType\n /** 稿件ID,也就是AV号去除前缀后的内容 */\n oid: string\n /**\n * 获取的评论数量,默认20\n * @defaultValue 20\n */\n number?: number\n /**\n * 排序方式\n * 默认为3\n * 0和3: 仅热度\n * 1: 按热度+按时间\n * 2: 仅时间\n * @defaultValue 3\n */\n mode?: 0 | 1 | 2 | 3\n\n /**\n * 翻页信息,用于懒加载分页\n * 首次请求时不传,后续请求使用上次响应中的 data.cursor.pagination_reply.next_offset\n */\n pagination_str?: string\n /**\n * 平台类型\n * @defaultValue 1\n */\n plat?: number\n /**\n * 当获取第一页评论时存在\n */\n seek_rpid?: string\n /**\n * web位置参数\n * @defaultValue 1315875\n */\n web_location?: string\n },\n /** 指定评论的回复 */\n CommentReplyParams: {\n methodType: '指定评论的回复'\n /** 评论区类型代码,详见 [评论区类型代码](https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/comment/readme.md#%E8%AF%84%E8%AE%BA%E5%8C%BA%E7%B1%BB%E5%9E%8B%E4%BB%A3%E7%A0%81) */\n type: CommentType\n /** 目标评论区 ID,也就是AV号去除前缀后的内容 */\n oid: string\n /** 根评论ID */\n root: string\n /**\n * 获取的评论数量,默认20\n * @defaultValue 20\n */\n number?: number\n }\n\n UserParams: {\n methodType: '用户主页数据' | '用户主页动态列表数据' | '获取UP主总播放量' | '用户空间详细信息'\n /** UP主UID */\n host_mid: number\n },\n DynamicParams: {\n methodType: '动态详情数据' | '动态卡片数据'\n /** 动态ID */\n dynamic_id: string\n },\n BangumiInfoParams: {\n methodType: '番剧基本信息数据'\n /** 稿件ep_id,其含义为 {@link https://www.bilibili.com/anime/index | 番剧索引} 或 **我的追番** 中的番剧,对应网址中包含ss号,如:{@link https://www.bilibili.com/bangumi/play/ss33802} */\n season_id?: string\n /** 稿件ep_id,番剧的某一集,对应网址中包含ep号,如:{@link https://www.bilibili.com/bangumi/play/ep330798} */\n ep_id?: string\n },\n BangumiStreamParams: {\n methodType: '番剧下载信息数据'\n /** 稿件cid */\n cid: number\n /** 稿件ep_id,番剧的某一集,对应网址中包含ep号,如:{@link https://www.bilibili.com/bangumi/play/ep330798} */\n ep_id: string\n },\n LiveRoomParams: {\n methodType: '直播间信息' | '直播间初始化信息'\n /** 直播间ID */\n room_id: string\n },\n QrcodeParams: {\n methodType: '二维码状态'\n /** 扫码登录秘钥 */\n qrcode_key: string\n },\n EmojiParams: {\n methodType: 'Emoji数据'\n },\n LoginBaseInfoParams: {\n methodType: '登录基本信息'\n },\n GetQrcodeParams: {\n methodType: '申请二维码'\n },\n Bv2AvParams: {\n methodType: 'BV转AV'\n /** 视频BV号 */\n bvid: string\n },\n Av2BvParams: {\n methodType: 'AV转BV'\n /** 视频AV号 */\n avid: number\n },\n ArticleParams: {\n methodType: '专栏正文内容'\n /**\n * 专栏ID\n * * 如:{@link https://www.bilibili.com/read/cv43496899/?jump_opus=1}\n * * 43496899 就是专栏ID\n * * API Docs {@link https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/article/view.md#获取专栏正文内容}\n */\n id: string\n },\n ArticleCardParams: {\n methodType: '专栏显示卡片信息'\n /**\n * 被查询的 id 列表\n * 可传视频 **完整** AV/BV 号, 专栏 CV 号, 直播间长短 lv 号\n * * API Docs {@link https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/article/card.md#获取专栏显示卡片信息}\n */\n ids: string[] | string\n },\n ArticleInfoParams: {\n methodType: '专栏文章基本信息'\n /**\n * 专栏ID\n * * 如:{@link https://www.bilibili.com/read/cv43496899/?jump_opus=1}\n * * 43496899 就是专栏ID\n * * API Docs {@link https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/article/view.md#获取专栏文章基本信息}\n */\n id: string\n }\n ColumnInfoParams: {\n methodType: '文集基本信息'\n /**\n * 文集rlid,这个好像也是专栏ID\n * * 如:{@link https://www.bilibili.com/read/cv208340/?jump_opus=1}\n * * 208340 就是文集rlid\n * * API Docs {@link https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/article/articles.md#获取文集基本信息}\n */\n id: string\n }\n /** 从_v_voucher_申请_captcha */\n ApplyVoucherCaptchaParams: {\n methodType: '从_v_voucher_申请_captcha'\n /** CSRF Token (位于 Cookie 的 bili_jct) */\n csrf?: string\n /** 结构为字符串 voucher_ 尾随一串以 - 为分隔符的小写 UUID */\n v_voucher: string\n }\n /** 验证验证码结果 */\n ValidateCaptchaParams: {\n methodType: '验证验证码结果'\n /** CSRF Token (位于 Cookie 的 bili_jct) */\n csrf?: string\n /** 极验3 https://www.geetest.com 的 验证码 challenge */\n challenge: string\n /** 验证码 token */\n token: string\n /**\n * 人机验证成功后的 validate 参数\n */\n validate: string\n /**\n * 人机验证成功后的 seccode 参数,{validate}|jordan\n */\n seccode: string\n }\n}\n\n/**\n * 评论区类型枚举\n * 对应 CommentParams.type 与 CommentReplyParams.type\n */\nexport enum CommentType {\n /** 视频稿件:oid 为稿件 avid */\n Video = 1,\n /** 话题:oid 为话题 id */\n Topic = 2,\n /** 活动:oid 为活动 id */\n Activity = 4,\n /** 小视频:oid 为小视频 id */\n SmallVideo = 5,\n /** 小黑屋封禁信息:oid 为封禁公示 id */\n BlockInfo = 6,\n /** 公告信息:oid 为公告 id */\n Announcement = 7,\n /** 直播活动:oid 为直播间 id */\n LiveActivity = 8,\n /** 活动稿件:oid 含义未知 */\n ActivityVideo = 9,\n /** 直播公告:oid 含义未知 */\n LiveAnnouncement = 10,\n /** 相簿(图片动态):oid 为相簿 id */\n Album = 11,\n /** 专栏:oid 为专栏 cvid */\n Article = 12,\n /** 票务:oid 含义未知 */\n Ticket = 13,\n /** 音频:oid 为音频 auid */\n Audio = 14,\n /** 风纪委员会:oid 为众裁项目 id */\n Jury = 15,\n /** 点评:oid 含义未知 */\n Review = 16,\n /** 动态(纯文字动态&分享):oid 为动态 id */\n Dynamic = 17,\n /** 播单:oid 含义未知 */\n Playlist = 18,\n /** 音乐播单:oid 含义未知 */\n MusicPlaylist = 19,\n /** 漫画:oid 含义未知 */\n Comic1 = 20,\n /** 漫画:oid 含义未知 */\n Comic2 = 21,\n /** 漫画:oid 为漫画 mcid */\n Comic = 22,\n /** 课程:oid 为课程 epid */\n Course = 33\n}\n\nexport type BilibiliMethodOptMap = {\n 单个视频作品数据: BilibiliMethodOptionsMap['VideoInfoParams']\n 单个视频下载信息数据: BilibiliMethodOptionsMap['VideoStreamParams']\n 评论数据: BilibiliMethodOptionsMap['CommentParams']\n 指定评论的回复: BilibiliMethodOptionsMap['CommentReplyParams']\n 用户主页数据: BilibiliMethodOptionsMap['UserParams']\n 用户主页动态列表数据: BilibiliMethodOptionsMap['UserParams']\n 用户空间详细信息: BilibiliMethodOptionsMap['UserParams']\n 获取UP主总播放量: BilibiliMethodOptionsMap['UserParams']\n Emoji数据: BilibiliMethodOptionsMap['EmojiParams']\n 番剧基本信息数据: BilibiliMethodOptionsMap['BangumiInfoParams']\n 番剧下载信息数据: BilibiliMethodOptionsMap['BangumiStreamParams']\n 动态详情数据: BilibiliMethodOptionsMap['DynamicParams']\n 动态卡片数据: BilibiliMethodOptionsMap['DynamicParams']\n 直播间信息: BilibiliMethodOptionsMap['LiveRoomParams']\n 直播间初始化信息: BilibiliMethodOptionsMap['LiveRoomParams']\n 登录基本信息: BilibiliMethodOptionsMap['LoginBaseInfoParams']\n 申请二维码: BilibiliMethodOptionsMap['GetQrcodeParams']\n 二维码状态: BilibiliMethodOptionsMap['QrcodeParams']\n AV转BV: BilibiliMethodOptionsMap['Av2BvParams']\n BV转AV: BilibiliMethodOptionsMap['Bv2AvParams']\n 专栏正文内容: BilibiliMethodOptionsMap['ArticleParams']\n 专栏显示卡片信息: BilibiliMethodOptionsMap['ArticleCardParams']\n 专栏文章基本信息: BilibiliMethodOptionsMap['ArticleInfoParams']\n 文集基本信息: BilibiliMethodOptionsMap['ColumnInfoParams']\n 从_v_voucher_申请_captcha: BilibiliMethodOptionsMap['ApplyVoucherCaptchaParams']\n 验证验证码结果: BilibiliMethodOptionsMap['ValidateCaptchaParams']\n}\n","export * from './DYNAMIC_TYPE_ARTICLE'\nexport * from './DYNAMIC_TYPE_AV'\nexport * from './DYNAMIC_TYPE_DRAW'\nexport * from './DYNAMIC_TYPE_FORWARD'\nexport * from './DYNAMIC_TYPE_LIVE_RCMD'\nexport * from './DYNAMIC_TYPE_WORD'\n\n/**\n * 转发动态种子动态主体类型枚举\n */\nexport enum MajorType {\n /** 动态失效 */\n NONE = 'MAJOR_TYPE_NONE',\n /** 图文动态 */\n OPUS = 'MAJOR_TYPE_OPUS',\n /** 视频 */\n ARCHIVE = 'MAJOR_TYPE_ARCHIVE',\n /** 剧集更新 */\n PGC = 'MAJOR_TYPE_PGC',\n /** 课程 */\n COURSES = 'MAJOR_TYPE_COURSES',\n /** 带图动态 */\n DRAW = 'MAJOR_TYPE_DRAW',\n /** 文章 */\n ARTICLE = 'MAJOR_TYPE_ARTICLE',\n /** 音频更新 */\n MUSIC = 'MAJOR_TYPE_MUSIC',\n /** 一般类型 */\n COMMON = 'MAJOR_TYPE_COMMON',\n /** 直播间分享 */\n LIVE = 'MAJOR_TYPE_LIVE',\n /** 媒体列表 */\n MEDIALIST = 'MAJOR_TYPE_MEDIALIST',\n /** 小程序 */\n APPLET = 'MAJOR_TYPE_APPLET',\n /** 订阅 */\n SUBSCRIPTION = 'MAJOR_TYPE_SUBSCRIPTION',\n /** 直播状态 */\n LIVE_RCMD = 'MAJOR_TYPE_LIVE_RCMD',\n /** 合集更新 */\n UGC_SEASON = 'MAJOR_TYPE_UGC_SEASON',\n /** 新订阅 */\n SUBSCRIPTION_NEW = 'MAJOR_TYPE_SUBSCRIPTION_NEW',\n /** 充电相关 */\n UPOWER_COMMON = 'MAJOR_TYPE_UPOWER_COMMON'\n}\n\n/**\n * 相关内容卡片类型枚举\n * 用于标识动态中附加的相关内容卡片的类型\n */\nexport enum AdditionalType {\n /** 无相关内容 */\n NONE = 'ADDITIONAL_TYPE_NONE',\n /** 剧集相关 */\n PGC = 'ADDITIONAL_TYPE_PGC',\n /** 商品信息 */\n GOODS = 'ADDITIONAL_TYPE_GOODS',\n /** 投票 */\n VOTE = 'ADDITIONAL_TYPE_VOTE',\n /** 一般类型 */\n COMMON = 'ADDITIONAL_TYPE_COMMON',\n /** 比赛信息 */\n MATCH = 'ADDITIONAL_TYPE_MATCH',\n /** UP主推荐 */\n UP_RCMD = 'ADDITIONAL_TYPE_UP_RCMD',\n /** 视频跳转 */\n UGC = 'ADDITIONAL_TYPE_UGC',\n /** 直播预约 */\n RESERVE = 'ADDITIONAL_TYPE_RESERVE',\n /** 充电专属抽奖 */\n UPOWER_LOTTERY = 'ADDITIONAL_TYPE_UPOWER_LOTTERY'\n}\n","import { DynamicTypeArticle, DynamicTypeAV, DynamicTypeDraw, DynamicTypeForwardUnion, DynamicTypeLiveRcmd, DynamicTypeWord } from './index'\n\nexport enum DynamicType {\n AV = 'DYNAMIC_TYPE_AV',\n DRAW = 'DYNAMIC_TYPE_DRAW',\n WORD = 'DYNAMIC_TYPE_WORD',\n LIVE_RCMD = 'DYNAMIC_TYPE_LIVE_RCMD',\n FORWARD = 'DYNAMIC_TYPE_FORWARD',\n ARTICLE = 'DYNAMIC_TYPE_ARTICLE'\n}\n\nexport type BiliDynamicInfoUnion =\n | DynamicTypeAV\n | DynamicTypeDraw\n | DynamicTypeWord\n | DynamicTypeLiveRcmd\n | DynamicTypeForwardUnion\n | DynamicTypeArticle\n\ntype DynamicTypeItemMap = {\n [DynamicType.AV]: DynamicTypeAV['data']['item']\n [DynamicType.DRAW]: DynamicTypeDraw['data']['item']\n [DynamicType.WORD]: DynamicTypeWord['data']['item']\n [DynamicType.LIVE_RCMD]: DynamicTypeLiveRcmd['data']['item']\n [DynamicType.FORWARD]: DynamicTypeForwardUnion['data']['item']\n [DynamicType.ARTICLE]: DynamicTypeArticle['data']['item']\n}\n\ntype DataData<T extends DynamicType> = {\n item: DynamicTypeItemMap[T]\n}\n\nexport type BiliDynamicInfo<T extends DynamicType> = {\n code: number\n data: DataData<T>\n message: string\n ttl: number;\n [property: string]: any\n}\n","import { getBilibiliData, getDouyinData, getKuaishouData, getXiaohongshuData } from 'amagi/model/DataFetchers'\nimport {\n bilibiliUtils,\n createBilibiliRoutes,\n createDouyinRoutes,\n createKuaishouRoutes,\n createXiaohongshuRoutes,\n douyinUtils,\n kuaishouUtils\n} from 'amagi/platform'\n\nimport { xiaohongshuUtils } from './platform/xiaohongshu'\nimport { createAmagiClient, Options } from './server'\n\n// 版本号会在构建时被替换\ndeclare const __VERSION__: string\nconst VERSION = typeof __VERSION__ !== 'undefined' ? __VERSION__ : '0.0.0'\n\nexport { getBilibiliData, getDouyinData, getKuaishouData } from './model/DataFetchers'\nexport * from './utils/errors'\nexport * from './validation'\nexport * from 'amagi/model'\nexport * from 'amagi/platform'\nexport * from 'amagi/server'\nexport * from 'amagi/types'\n\n/**\n * @deprecated 请使用 createAmagiClient 替代\n */\nexport const amagiClient: typeof createAmagiClient = createAmagiClient\n\n/** amagi 的构造函数类型 */\ntype AmagiConstructor = {\n new(options?: Options): ReturnType<typeof createAmagiClient>\n (options?: Options): ReturnType<typeof createAmagiClient>\n /** 当前版本号 */\n readonly version: string\n /** 抖音相关功能模块 (工具集) */\n douyin: typeof douyinUtils\n /** B站相关功能模块 (工具集) */\n bilibili: typeof bilibiliUtils\n /** 快手相关功能模块 (工具集) */\n kuaishou: typeof kuaishouUtils\n /** 小红书相关功能模块 (工具集) */\n xiaohongshu: typeof xiaohongshuUtils\n /**\n * 快捷获取抖音数据\n * @param type - 请求数据类型\n * @param options - 请求参数,是一个对象\n * @param cookie - 有效的用户Cookie\n * @returns 返回接口的原始数据\n */\n getDouyinData: typeof getDouyinData\n /**\n * 快捷获取B站数据\n * @param type - 请求数据类型\n * @param options - 请求参数,是一个对象\n * @param cookie - 有效的用户Cookie\n * @returns 返回接口的原始数据\n */\n getBilibiliData: typeof getBilibiliData\n /**\n * 快捷获取快手数据\n * @param type - 请求数据类型\n * @param options - 请求参数,是一个对象\n * @param cookie - 有效的用户Cookie\n * @returns 返回接口的原始数据\n */\n getKuaishouData: typeof getKuaishouData\n /**\n * 快捷获取小红书数据\n * @param type - 请求数据类型\n * @param options - 请求参数,是一个对象\n * @param cookie - 有效的用户Cookie\n * @returns 返回接口的原始数据\n */\n getXiaohongshuData: typeof getXiaohongshuData\n}\n\n/**\n * 创建一个新的 amagi 客户端实例\n * 用于创建和初始化一个新的 amagi 客户端实例,支持通过 new 关键字或函数调用方式使用\n * @param options - cookies 配置选项,用于设置客户端的 cookies 相关参数\n * @returns 返回一个新的 amagi 客户端实例\n */\nfunction CreateAmagiApp (this: any, options: Options = {}): ReturnType<typeof createAmagiClient> {\n // 是否通过 new 关键字调用\n if (!(this instanceof CreateAmagiApp)) {\n return createAmagiClient(options)\n }\n\n return createAmagiClient(options)\n}\n\n// 添加静态属性和方法\nObject.defineProperty(CreateAmagiApp, 'version', {\n value: VERSION,\n writable: false,\n enumerable: true,\n configurable: false\n})\n\nCreateAmagiApp.douyin = douyinUtils\nCreateAmagiApp.bilibili = bilibiliUtils\nCreateAmagiApp.kuaishou = kuaishouUtils\nCreateAmagiApp.xiaohongshu = xiaohongshuUtils\n\nCreateAmagiApp.getDouyinData = getDouyinData\nCreateAmagiApp.getBilibiliData = getBilibiliData\nCreateAmagiApp.getKuaishouData = getKuaishouData\nCreateAmagiApp.getXiaohongshuData = getXiaohongshuData\n\n/** After instantiation, it can interact with the specified platform API to quickly obtain data. */\nexport const CreateApp = CreateAmagiApp as AmagiConstructor\n\n/** After instantiation, it can interact with the specified platform API to quickly obtain data. */\nconst Client: typeof CreateApp = CreateApp\nconst amagi: typeof Client = Client\n\n/*!\n * @ikenxuan/amagi\n * Copyright(c) 2023 ikenxuan\n * GPL-3.0 Licensed\n */\nexport { amagi, Client as default }\n\nexport {\n createBilibiliRoutes as registerBilibiliRoutes,\n createDouyinRoutes as registerDouyinRoutes,\n createKuaishouRoutes as registerKuaishouRoutes,\n createXiaohongshuRoutes as registerXiaohongshuRoutes\n}\n"],"mappings":"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"}