karin-plugin-kkk
Version:
Karin 的「抖音」「B 站」视频解析/动态推送插件
1,508 lines • 1.85 MB
JavaScript
import { i as __toESM } from "./rolldown-runtime.js";
import { $ as SiOppo, $n as zod_default, $t as MessageCircle, A as n, An as CircleAlert, At as Sparkles, B as RiPieChart2Fill, Bn as Chip, Bt as RotateCcw, C as BiImage, Cn as Clock, Ct as TriangleAlert, D as AiOutlineVideoCamera, Dn as CircleEllipsis, Dt as Star, E as AiFillStar, En as CircleFadingArrowUp, Et as Sun, F as RiHeart3Fill, Fn as Box, Ft as Share2, G as RiTiktokFill, Gn as require_react, Gt as Puzzle, H as RiStarFill, Hn as clsx, Ht as Radio, I as RiHeart3Line, In as Bot, It as Settings2, J as RiVerifiedBadgeFill, Jn as require_jpeg_js, Jt as Pencil, K as RiTrophyFill, Kn as require_png, Kt as Plus, L as RiHeartLine, Ln as Bookmark, Lt as Search, M as RiArrowRightFill, Mn as ChartColumn, Mt as ShoppingBag, N as RiGroupLine, Nn as Camera, Nt as Shield, O as m, On as CircleCheck, Ot as Square, P as RiHashtag, Pn as Calendar, Pt as ShieldCheck, Q as SiSamsung, Qn as Xhshow, Qt as Monitor, R as RiLiveLine, Rn as BellRing, Rt as ScanLine, S as FaUserGroup, Sn as Code, St as Upload, T as AiFillPushpin, Tn as CircleQuestionMark, Tt as Terminal, U as RiStarLine, Un as require_jsx_runtime, Ut as Quote, V as RiShareForwardFill, Vn as Button, Vt as RefreshCw, W as RiThumbUpFill, Wn as require_server_node, Wt as QrCode, X as SiXiaomi, Xn as require_protobufjs, Xt as Music, Y as RiVideoLine, Yn as require_heic_decode, Yt as Palette, Z as SiVivo, Zn as Chalk, Zt as Moon, _ as MdLocationOn, _n as Download, _t as Video, a as purify, an as Info, at as SiBilibili, b as FaMusic, bn as CornerDownLeft, bt as User, c as VictoryLine, cn as Hash, ct as zhCN, d as VictoryLabel, dn as Gamepad2, dt as formatDistanceToNow, en as Menu, et as SiOneplus, f as VictoryTheme, fn as FileText, ft as format, g as MdLightbulbOutline, gn as ExternalLink, gt as WandSparkles, h as MdInfoOutline, hn as EyeOff, ht as X, i as Window, in as LayoutTemplate, it as SiGithub, j as Markdown, jn as Check, jt as Smartphone, k as a, kn as CircleCheckBig, kt as SquarePen, l as VictoryChart, ln as GitBranch, lt as parse, m as MdFitScreen, mn as Eye, mt as Zap, n as require_lib, nn as MapPin, nt as SiHonor, o as VictoryScatter, on as Image$1, ot as SiApple, p as rehypeHighlight, pn as FilePlay, pt as differenceInSeconds, q as RiUserFollowLine, qn as require_jsQR, qt as Play, r as require_qr_code_styling, rn as LoaderCircle, rt as SiGooglephotos, s as VictoryPie, sn as Heart, st as SiAnthropic, t as createProxyMiddleware, tn as Maximize, tt as SiHuawei, u as VictoryAxis, un as Gift, ut as fromUnixTime, v as MdSchedule, vn as Crown, vt as Users, w as AiFillHeart, wn as Clapperboard, wt as Trash2, x as FaTiktok, xn as Copy, xt as UserPlus, y as FaCommentDots, yn as Cpu, yt as UsersRound, z as RiMessage3Fill, zn as ArrowDownToLine, zt as Save } from "./vendor.js";
import "node:module";
import fs from "node:fs";
import path, { resolve } from "node:path";
import URL$2, { fileURLToPath } from "node:url";
import os, { platform } from "node:os";
import karin$1, { BOT_CONNECT, app, authMiddleware, checkPkgUpdate, checkPort, common, components, config, copyConfigSync, createBadRequestResponse, createNotFoundResponse, createServerErrorResponse, createSuccessResponse, db, defineConfig, ffmpeg, ffprobe, filesByExt, getBot, hooks, karin, karinPathHtml, karinPathTemp, logger, logger as logger$1, logs, mkdirSync, parseChangelog, range, render, requireFileSync, restart, segment, updatePkg, watch } from "node-karin";
import _ from "node-karin/lodash";
import { EventEmitter } from "node:events";
import crypto from "node:crypto";
import axios, { AxiosError } from "node-karin/axios";
import express from "node-karin/express";
import { karinPathBase, karinPathTemp as karinPathTemp$1 } from "node-karin/root";
import sqlite3 from "node-karin/sqlite3";
import YAML from "node-karin/yaml";
import util from "node:util";
import { Transform } from "node:stream";
import { pipeline } from "node:stream/promises";
import { embedWatermarkToPngBytes } from "@ikenxuan/watermark";
import { snapka } from "@karinjs/plugin-puppeteer";
import { newInjectedPage } from "fingerprint-injector";
//#region src/index.ts
globalThis.__kkkLoadStart ??= process.hrtime.bigint();
import("./setup.js");
//#endregion
//#region src/root.ts
var resolvePluginRoot = (startUrl) => {
let dir = path.dirname(startUrl);
for (let i = 0; i < 8; i++) {
const pkgPath = path.join(dir, "package.json");
if (fs.existsSync(pkgPath)) return dir;
const parent = path.dirname(dir);
if (parent === dir) break;
dir = parent;
}
return path.resolve(startUrl, "../..");
};
var pluginPath = resolvePluginRoot(fileURLToPath(import.meta.url));
var pkg = JSON.parse(fs.readFileSync(path.join(pluginPath, "package.json"), "utf-8"));
var Root = {
pluginName: pkg.name,
pluginVersion: pkg.version,
pluginPath,
karinVersion: process.env.KARIN_VERSION,
pkg
};
//#endregion
//#region ../amagi/packages/core/src/utils/deprecation.ts
/**
* 废弃 API 注册表
* 存储所有已注册的废弃 API 配置
*/
var deprecatedApis = /* @__PURE__ */ new Map();
/**
* 注册一个废弃的 API
*
* 将 API 添加到废弃注册表中,后续可通过 checkDeprecation 检查
*
* @param config - 废弃配置对象
*
* @example
* ```typescript
* registerDeprecatedApi({
* name: 'getDouyinData',
* deprecatedIn: '6.0.0',
* removedIn: '7.0.0',
* replacement: 'douyinFetcher',
* throwError: true
* })
* ```
*/
function registerDeprecatedApi(config) {
deprecatedApis.set(config.name, config);
}
/**
* 检查 API 是否已废弃并进行相应处理
*
* 如果 API 已注册为废弃,根据配置决定是打印警告还是抛出错误
*
* @param apiName - 要检查的 API 名称
* @throws {DeprecatedApiError} 如果 API 已废弃且配置为抛出错误
*
* @example
* ```typescript
* // 在函数开头调用检查
* function getDouyinData(options) {
* checkDeprecation('getDouyinData')
* // ...
* }
* ```
*/
function checkDeprecation(apiName) {
const config = deprecatedApis.get(apiName);
if (!config) return;
const message = buildDeprecationMessage(config);
if (config.throwError) throw new DeprecatedApiError(message, config);
else console.warn(message);
}
/**
* 根据配置构建废弃提示消息
*
* @param config - 废弃配置
* @returns 格式化的废弃提示消息字符串
*/
function buildDeprecationMessage(config) {
const lines = [`[DEPRECATED] "${config.name}" 已在 v${config.deprecatedIn} 版本废弃。`];
if (config.replacement) lines.push(`请使用 "${config.replacement}" 替代。`);
else lines.push("此接口已被上游删除,无法继续使用,无可用替代方案。");
if (config.removedIn) lines.push(`此 API 将在 v${config.removedIn} 版本移除。`);
if (config.migrationGuide) lines.push(`迁移指南: ${config.migrationGuide}`);
return lines.join("\n");
}
/**
* 废弃 API 调用错误类
*
* 当调用已废弃且配置为抛出错误的 API 时抛出此错误
* 包含完整的废弃配置信息,便于调试和迁移
*/
var DeprecatedApiError = class DeprecatedApiError extends Error {
/** 废弃配置信息,包含替代方案等详细信息 */
config;
/**
* 创建废弃 API 错误实例
*
* @param message - 错误消息
* @param config - 废弃配置对象
*/
constructor(message, config) {
super(message);
this.name = "DeprecatedApiError";
this.config = config;
Error.captureStackTrace?.(this, DeprecatedApiError);
}
};
registerDeprecatedApi({
name: "getDouyinData",
deprecatedIn: "6.0.0",
removedIn: "7.0.0",
replacement: "douyinFetcher 或 client.douyin.fetcher",
migrationGuide: "https://github.com/ikenxuan/amagi/blob/main/packages/core/MIGRATION-v6.md",
throwError: true
});
registerDeprecatedApi({
name: "getBilibiliData",
deprecatedIn: "6.0.0",
removedIn: "7.0.0",
replacement: "bilibiliFetcher 或 client.bilibili.fetcher",
migrationGuide: "https://github.com/ikenxuan/amagi/blob/main/packages/core/MIGRATION-v6.md",
throwError: true
});
registerDeprecatedApi({
name: "getKuaishouData",
deprecatedIn: "6.0.0",
removedIn: "7.0.0",
replacement: "kuaishouFetcher 或 client.kuaishou.fetcher",
migrationGuide: "https://github.com/ikenxuan/amagi/blob/main/packages/core/MIGRATION-v6.md",
throwError: true
});
registerDeprecatedApi({
name: "getXiaohongshuData",
deprecatedIn: "6.0.0",
removedIn: "7.0.0",
replacement: "xiaohongshuFetcher 或 client.xiaohongshu.fetcher",
migrationGuide: "https://github.com/ikenxuan/amagi/blob/main/packages/core/MIGRATION-v6.md",
throwError: true
});
[
{
name: "单个视频作品数据",
replacement: "fetchVideoInfo"
},
{
name: "单个视频下载信息数据",
replacement: "fetchVideoStreamUrl"
},
{
name: "评论数据",
replacement: "fetchComments"
},
{
name: "指定评论的回复",
replacement: "fetchCommentReplies"
},
{
name: "用户主页数据",
replacement: "fetchUserCard"
},
{
name: "用户主页动态列表数据",
replacement: "fetchUserDynamicList"
},
{
name: "用户空间详细信息",
replacement: "fetchUserSpaceInfo"
},
{
name: "获取UP主总播放量",
replacement: "fetchUploaderTotalViews"
},
{
name: "Emoji数据",
replacement: "fetchEmojiList"
},
{
name: "番剧基本信息数据",
replacement: "fetchBangumiInfo"
},
{
name: "番剧下载信息数据",
replacement: "fetchBangumiStreamUrl"
},
{
name: "动态详情数据",
replacement: "fetchDynamicDetail"
},
{
name: "直播间信息",
replacement: "fetchLiveRoomInfo"
},
{
name: "直播间初始化信息",
replacement: "fetchLiveRoomInitInfo"
},
{
name: "登录基本信息",
replacement: "fetchLoginStatus"
},
{
name: "申请二维码",
replacement: "requestLoginQrcode"
},
{
name: "二维码状态",
replacement: "checkQrcodeStatus"
},
{
name: "AV转BV",
replacement: "convertAvToBv"
},
{
name: "BV转AV",
replacement: "convertBvToAv"
},
{
name: "专栏正文内容",
replacement: "fetchArticleContent"
},
{
name: "专栏显示卡片信息",
replacement: "fetchArticleCards"
},
{
name: "专栏文章基本信息",
replacement: "fetchArticleInfo"
},
{
name: "文集基本信息",
replacement: "fetchArticleListInfo"
},
{
name: "实时弹幕",
replacement: "fetchVideoDanmaku"
},
{
name: "从_v_voucher_申请_captcha",
replacement: "requestCaptchaFromVoucher"
},
{
name: "验证验证码结果",
replacement: "validateCaptchaResult"
},
{
name: "视频作品数据",
replacement: "fetchVideoWork"
},
{
name: "图集作品数据",
replacement: "fetchImageAlbumWork"
},
{
name: "合辑作品数据",
replacement: "fetchSlidesWork"
},
{
name: "文字作品数据",
replacement: "fetchTextWork"
},
{
name: "聚合解析",
replacement: "parseWork"
},
{
name: "指定评论回复数据",
replacement: "fetchCommentReplies"
},
{
name: "用户主页视频列表数据",
replacement: "fetchUserVideoList"
},
{
name: "热点词数据",
replacement: "fetchSuggestWords"
},
{
name: "搜索数据",
replacement: "searchContent"
},
{
name: "音乐数据",
replacement: "fetchMusicInfo"
},
{
name: "直播间信息数据",
replacement: "fetchLiveRoomInfo"
},
{
name: "申请二维码数据",
replacement: "requestLoginQrcode"
},
{
name: "动态表情数据",
replacement: "fetchDynamicEmojiList"
},
{
name: "弹幕数据",
replacement: "fetchDanmakuList"
},
{
name: "单个视频作品数据",
replacement: "fetchVideoWork"
},
{
name: "首页推荐数据",
replacement: "fetchHomeFeed"
},
{
name: "单个笔记数据",
replacement: "fetchNoteDetail"
},
{
name: "用户数据",
replacement: "fetchUserProfile"
},
{
name: "用户笔记数据",
replacement: "fetchUserNoteList"
},
{
name: "表情列表",
replacement: "fetchEmojiList"
},
{
name: "搜索笔记",
replacement: "searchNotes"
}
].forEach(({ name, replacement }) => {
registerDeprecatedApi({
name: `methodType: '${name}'`,
deprecatedIn: "6.0.0",
removedIn: "7.0.0",
replacement: `fetcher.${replacement}()`,
throwError: true
});
});
registerDeprecatedApi({
name: `methodType: '动态卡片数据'`,
deprecatedIn: "6.0.0",
removedIn: "7.0.0",
migrationGuide: "https://amagi-docs.vercel.app/docs/changelog/6.1.3",
throwError: false
});
registerDeprecatedApi({
name: "fetchDynamicCard",
deprecatedIn: "6.1.3",
removedIn: "7.0.0",
migrationGuide: "https://amagi-docs.vercel.app/docs/changelog/6.1.3",
throwError: false
});
//#endregion
//#region ../amagi/packages/core/src/model/DataFetchers.ts
/**
* 数据获取器模块 (已废弃)
*
* 此模块中的 getXXXData 函数已在 v6 版本废弃并移除
* 请使用新的 fetcher API 替代
*
* @module model/DataFetchers
* @deprecated v6 已废弃,请使用 fetcher API 替代
*/
/**
* 获取抖音数据
*
* @deprecated v6 已废弃,请使用 douyinFetcher 或 client.douyin.fetcher 替代
* @throws {DeprecatedApiError} 调用时抛出废弃错误
*
* @example
* ```typescript
* // 旧用法 (已废弃,会抛出错误)
* const data = await getDouyinData('videoWork', { aweme_id: '123' }, cookie)
*
* // 新用法
* import { douyinFetcher } from '@ikenxuan/amagi'
* const data = await douyinFetcher.fetchVideoWork({ aweme_id: '123' }, cookie)
*
* // 或使用客户端实例
* const client = createAmagiClient({ cookies: { douyin: cookie } })
* const data = await client.douyin.fetcher.fetchVideoWork({ aweme_id: '123' })
* ```
*/
function getDouyinData(..._args) {
checkDeprecation("getDouyinData");
throw new Error("getDouyinData 已废弃");
}
/**
* 获取B站数据
*
* @deprecated v6 已废弃,请使用 bilibiliFetcher 或 client.bilibili.fetcher 替代
* @throws {DeprecatedApiError} 调用时抛出废弃错误
*
* @example
* ```typescript
* // 旧用法 (已废弃,会抛出错误)
* const data = await getBilibiliData('videoInfo', { bvid: 'BV123' }, cookie)
*
* // 新用法
* import { bilibiliFetcher } from '@ikenxuan/amagi'
* const data = await bilibiliFetcher.fetchVideoInfo({ bvid: 'BV123' }, cookie)
*
* // 或使用客户端实例
* const client = createAmagiClient({ cookies: { bilibili: cookie } })
* const data = await client.bilibili.fetcher.fetchVideoInfo({ bvid: 'BV123' })
* ```
*/
function getBilibiliData(..._args) {
checkDeprecation("getBilibiliData");
throw new Error("getBilibiliData 已废弃");
}
/**
* 获取快手数据
*
* @deprecated v6 已废弃,请使用 kuaishouFetcher 或 client.kuaishou.fetcher 替代
* @throws {DeprecatedApiError} 调用时抛出废弃错误
*
* @example
* ```typescript
* // 旧用法 (已废弃,会抛出错误)
* const data = await getKuaishouData('videoWork', { photoId: '123' }, cookie)
*
* // 新用法
* import { kuaishouFetcher } from '@ikenxuan/amagi'
* const data = await kuaishouFetcher.fetchVideoWork({ photoId: '123' }, cookie)
*
* // 或使用客户端实例
* const client = createAmagiClient({ cookies: { kuaishou: cookie } })
* const data = await client.kuaishou.fetcher.fetchVideoWork({ photoId: '123' })
* ```
*/
function getKuaishouData(..._args) {
checkDeprecation("getKuaishouData");
throw new Error("getKuaishouData 已废弃");
}
/**
* 获取小红书数据
*
* @deprecated v6 已废弃,请使用 xiaohongshuFetcher 或 client.xiaohongshu.fetcher 替代
* @throws {DeprecatedApiError} 调用时抛出废弃错误
*
* @example
* ```typescript
* // 旧用法 (已废弃,会抛出错误)
* const data = await getXiaohongshuData('noteDetail', { note_id: '123' }, cookie)
*
* // 新用法
* import { xiaohongshuFetcher } from '@ikenxuan/amagi'
* const data = await xiaohongshuFetcher.fetchNoteDetail({ note_id: '123' }, cookie)
*
* // 或使用客户端实例
* const client = createAmagiClient({ cookies: { xiaohongshu: cookie } })
* const data = await client.xiaohongshu.fetcher.fetchNoteDetail({ note_id: '123' })
* ```
*/
function getXiaohongshuData(..._args) {
checkDeprecation("getXiaohongshuData");
throw new Error("getXiaohongshuData 已废弃");
}
//#endregion
//#region ../amagi/packages/core/src/platform/bilibili/API.ts
/**
* B站 API URL 构建类
*
* 提供所有 B站 API 的 URL 构建方法
*/
var BilibiliAPI = class {
/** 获取登录基本信息 */
getLoginStatus() {
return "https://api.bilibili.com/x/web-interface/nav";
}
/** 获取视频详细信息 */
getVideoInfo(data) {
return `https://api.bilibili.com/x/web-interface/view?bvid=${data.bvid}`;
}
/** 获取视频流信息 */
getVideoStream(data) {
return `https://api.bilibili.com/x/player/playurl?avid=${data.avid}&cid=${data.cid}`;
}
/**
* 获取评论区明细
* @see https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/comment/readme.md#评论区类型代码
*/
getComments(data) {
const params = new URLSearchParams({
oid: data.oid.toString(),
type: data.type.toString(),
mode: (data.mode ?? 3).toString(),
plat: "1",
seek_rpid: "",
web_location: "1315875"
});
if (data.pagination_str) params.append("pagination_str", JSON.stringify({ offset: data.pagination_str }));
else params.append("pagination_str", JSON.stringify({ offset: "" }));
return `https://api.bilibili.com/x/v2/reply/wbi/main?${params.toString()}`;
}
/** 获取评论区状态 */
getCommentStatus(data) {
return `https://api.bilibili.com/x/v2/reply/subject/description?type=${data.type}&oid=${data.oid}`;
}
/** 获取指定评论的回复 */
getCommentReplies(data) {
return `https://api.bilibili.com/x/v2/reply/reply?type=${data.type}&oid=${data.oid}&root=${data.root}&ps=${data.number}`;
}
/** 获取表情列表 */
getEmojiList() {
return "https://api.bilibili.com/x/emote/user/panel/web?business=reply&web_location=0.0";
}
/** 获取番剧明细 */
getBangumiInfo(data) {
if (data.ep_id) return `https://api.bilibili.com/pgc/view/web/season?ep_id=${data.ep_id}`;
else if (data.season_id) return `https://api.bilibili.com/pgc/view/web/season?season_id=${data.season_id}`;
else throw new Error("Missing required parameter: ep_id or season_id");
}
/** 获取番剧视频流信息 */
getBangumiStream(data) {
return `https://api.bilibili.com/pgc/player/web/playurl?cid=${data.cid}&ep_id=${data.ep_id}`;
}
/** 获取用户空间动态 */
getUserDynamicList(data) {
return `https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/space?${new URLSearchParams({
host_mid: data.host_mid.toString(),
offset: "",
platform: "web",
features: "itemOpusStyle,listOnlyfans,opusBigCover,onlyfansVote,forwardListHidden,decorationCard,commentsNewVersion,onlyfansAssetsV2,ugcDelete,onlyfansQaCard,avatarAutoTheme,sunflowerStyle,eva3CardOpus,eva3CardVideo,eva3CardComment"
}).toString()}`;
}
/** 获取动态详情 */
getDynamicDetail(data) {
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`;
}
/**
* 获取动态卡片信息
*
* @deprecated B站官方已于 `2025-08-09` 删除原 `dynamic_svr` 接口,该接口已停用。
* 调用将返回错误信息,请使用 {@link getDynamicDetail} 替代。
*/
getDynamicCard(data) {
return this.getDynamicDetail(data);
}
/** 获取用户名片信息 */
getUserCard(data) {
return `https://api.bilibili.com/x/web-interface/card?mid=${data.host_mid}&photo=true`;
}
/** 获取直播间信息 */
getLiveRoomInfo(data) {
return `https://api.live.bilibili.com/room/v1/Room/get_info?room_id=${data.room_id}`;
}
/** 获取直播间初始化信息 */
getLiveRoomInit(data) {
return `https://api.live.bilibili.com/room/v1/Room/room_init?id=${data.room_id}`;
}
/** 申请登录二维码 */
getLoginQrcode() {
return "https://passport.bilibili.com/x/passport-login/web/qrcode/generate";
}
/** 查询二维码状态 */
getQrcodeStatus(data) {
return `https://passport.bilibili.com/x/passport-login/web/qrcode/poll?qrcode_key=${data.qrcode_key}`;
}
/** 获取UP主总播放量 */
getUploaderTotalViews(data) {
return `https://api.bilibili.com/x/space/upstat?mid=${data.host_mid}`;
}
/** 获取专栏正文内容 */
getArticleContent(data) {
return `https://api.bilibili.com/x/article/view?id=${data.id}`;
}
/** 获取专栏显示卡片信息 */
getArticleCards(data) {
return `https://api.bilibili.com/x/article/cards?ids=${Array.isArray(data.ids) ? data.ids.join(",") : data.ids}`;
}
/** 获取专栏文章基本信息 */
getArticleInfo(data) {
return `https://api.bilibili.com/x/article/viewinfo?id=${data.id}`;
}
/** 获取文集基本信息 */
getArticleListInfo(data) {
return `https://api.bilibili.com/x/article/list/web/articles?id=${data.id}`;
}
/** 获取用户空间详细信息 */
getUserSpaceInfo(data) {
return `https://api.bilibili.com/x/space/wbi/acc/info?mid=${data.host_mid}`;
}
/** 从 v_voucher 申请验证码 */
getCaptchaFromVoucher(data) {
return {
Url: "https://api.bilibili.com/x/gaia-vgate/v1/register",
Body: {
...data.csrf !== void 0 && { csrf: data.csrf },
v_voucher: data.v_voucher
}
};
}
/** 验证验证码结果 */
validateCaptcha(data) {
return {
Url: "https://api.bilibili.com/x/gaia-vgate/v1/validate",
Body: {
challenge: data.challenge,
token: data.token,
validate: data.validate,
seccode: data.seccode,
...data.csrf !== void 0 && { csrf: data.csrf }
}
};
}
/**
* 获取实时弹幕(web端 protobuf 接口)
* @see https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/danmaku/danmaku_proto.md
*/
getVideoDanmaku(data) {
return `https://api.bilibili.com/x/v2/dm/web/seg.so?${new URLSearchParams({
type: "1",
oid: data.cid.toString(),
segment_index: (data.segment_index ?? 1).toString()
}).toString()}`;
}
};
/** B站 API URL 构建器实例 */
var bilibiliApiUrls = new BilibiliAPI();
//#endregion
//#region ../amagi/packages/core/src/platform/bilibili/BilibiliApi.ts
/**
* 创建废弃的 API 存根函数
*/
var createDeprecatedStub$3 = (methodName) => {
return (..._args) => {
checkDeprecation("getBilibiliData");
throw new Error(`bilibili.${methodName} 已废弃,请使用 bilibiliFetcher 替代`);
};
};
/**
* B站相关 API 的命名空间。
*
* @deprecated v6 已废弃,请使用 bilibiliFetcher 或 client.bilibili.fetcher 替代
*/
var bilibili$1 = {
/** @deprecated 请使用 bilibiliFetcher.fetchVideoInfo 替代 */
getVideoInfo: createDeprecatedStub$3("getVideoInfo"),
/** @deprecated 请使用 bilibiliFetcher.fetchVideoStreamUrl 替代 */
getVideoStream: createDeprecatedStub$3("getVideoStream"),
/** @deprecated 请使用 bilibiliFetcher.fetchComments 替代 */
getComments: createDeprecatedStub$3("getComments"),
/** @deprecated 请使用 bilibiliFetcher.fetchCommentReplies 替代 */
getCommentReply: createDeprecatedStub$3("getCommentReply"),
/** @deprecated 请使用 bilibiliFetcher.fetchUserCard 替代 */
getUserProfile: createDeprecatedStub$3("getUserProfile"),
/** @deprecated 请使用 bilibiliFetcher.fetchUserDynamicList 替代 */
getUserDynamic: createDeprecatedStub$3("getUserDynamic"),
/** @deprecated 请使用 bilibiliFetcher.fetchEmojiList 替代 */
getEmojiList: createDeprecatedStub$3("getEmojiList"),
/** @deprecated 请使用 bilibiliFetcher.fetchBangumiInfo 替代 */
getBangumiInfo: createDeprecatedStub$3("getBangumiInfo"),
/** @deprecated 请使用 bilibiliFetcher.fetchBangumiStreamUrl 替代 */
getBangumiStream: createDeprecatedStub$3("getBangumiStream"),
/** @deprecated 请使用 bilibiliFetcher.fetchDynamicDetail 替代 */
getDynamicInfo: createDeprecatedStub$3("getDynamicInfo"),
/** @deprecated 请使用 bilibiliFetcher.fetchDynamicCard 替代 */
getDynamicCard: createDeprecatedStub$3("getDynamicCard"),
/** @deprecated 请使用 bilibiliFetcher.fetchLiveRoomInfo 替代 */
getLiveRoomDetail: createDeprecatedStub$3("getLiveRoomDetail"),
/** @deprecated 请使用 bilibiliFetcher.fetchLiveRoomInitInfo 替代 */
getLiveRoomInitInfo: createDeprecatedStub$3("getLiveRoomInitInfo"),
/** @deprecated 请使用 bilibiliFetcher.fetchLoginStatus 替代 */
getLoginBasicInfo: createDeprecatedStub$3("getLoginBasicInfo"),
/** @deprecated 请使用 bilibiliFetcher.requestLoginQrcode 替代 */
getLoginQrcode: createDeprecatedStub$3("getLoginQrcode"),
/** @deprecated 请使用 bilibiliFetcher.checkQrcodeStatus 替代 */
checkQrcodeStatus: createDeprecatedStub$3("checkQrcodeStatus"),
/** @deprecated 请使用 bilibiliFetcher.fetchUploaderTotalViews 替代 */
getUserTotalPlayCount: createDeprecatedStub$3("getUserTotalPlayCount"),
/** @deprecated 请使用 bilibiliFetcher.convertAvToBv 替代 */
convertAvToBv: createDeprecatedStub$3("convertAvToBv"),
/** @deprecated 请使用 bilibiliFetcher.convertBvToAv 替代 */
convertBvToAv: createDeprecatedStub$3("convertBvToAv"),
/** @deprecated 请使用 bilibiliFetcher.fetchArticleContent 替代 */
getArticleContent: createDeprecatedStub$3("getArticleContent"),
/** @deprecated 请使用 bilibiliFetcher.fetchArticleCards 替代 */
getArticleCard: createDeprecatedStub$3("getArticleCard"),
/** @deprecated 请使用 bilibiliFetcher.fetchArticleInfo 替代 */
getArticleInfo: createDeprecatedStub$3("getArticleInfo"),
/** @deprecated 请使用 bilibiliFetcher.fetchArticleListInfo 替代 */
getColumnInfo: createDeprecatedStub$3("getColumnInfo"),
/** @deprecated 请使用 bilibiliFetcher.fetchUserSpaceInfo 替代 */
getUserProfileDetail: createDeprecatedStub$3("getUserProfileDetail"),
/** @deprecated 请使用 bilibiliFetcher.requestCaptchaFromVoucher 替代 */
applyVoucherCaptcha: createDeprecatedStub$3("applyVoucherCaptcha"),
/** @deprecated 请使用 bilibiliFetcher.validateCaptchaResult 替代 */
validateCaptcha: createDeprecatedStub$3("validateCaptcha"),
/** @deprecated 请使用 bilibiliFetcher.fetchVideoDanmaku 替代 */
getDanmaku: createDeprecatedStub$3("getDanmaku")
};
/**
* 创建绑定了cookie的B站API对象
*
* @deprecated v6 已废弃,请使用 createBoundBilibiliFetcher 替代
*/
var createBoundBilibiliApi = (_cookie, _requestConfig) => {
return { ...bilibili$1 };
};
//#endregion
//#region ../amagi/packages/core/src/model/events.ts
/**
* Amagi 事件系统
* @module model/events
* @description 提供类型安全的事件发射器,用于日志、HTTP、网络和 API 事件的监听与触发
*/
/**
* 类型安全的事件发射器
* @description 继承自 Node.js EventEmitter,提供泛型约束确保事件名称与数据类型匹配
*/
var TypedEventEmitter = class extends EventEmitter {
/**
* 触发事件
* @param event - 事件名称
* @param data - 事件数据
* @returns 是否有监听器处理了该事件
*/
emit(event, data) {
return super.emit(event, data);
}
/**
* 注册事件监听器
* @param event - 事件名称
* @param listener - 事件处理函数
* @returns this (支持链式调用)
*/
on(event, listener) {
return super.on(event, listener);
}
/**
* 注册一次性事件监听器
* @param event - 事件名称
* @param listener - 事件处理函数 (只触发一次)
* @returns this (支持链式调用)
*/
once(event, listener) {
return super.once(event, listener);
}
/**
* 移除事件监听器
* @param event - 事件名称
* @param listener - 要移除的事件处理函数
* @returns this (支持链式调用)
*/
off(event, listener) {
return super.off(event, listener);
}
};
/**
* Amagi 全局事件发射器实例
* @description 单例模式,所有模块共享同一个事件总线
* @example
* ```typescript
* import { amagiEvents } from 'amagi/model/events'
*
* // 监听 API 成功事件
* amagiEvents.on('api:success', (data) => {
* console.log(`[${data.platform}] ${data.methodType} 耗时 ${data.duration}ms`)
* })
* ```
*/
var amagiEvents = new TypedEventEmitter();
/**
* 发射日志事件
* @param level - 日志级别
* @param message - 日志消息
* @param args - 附加参数
*/
var emitLog = (level, message, ...args) => {
amagiEvents.emit(`log:${level}`, {
level,
message,
args: args.length > 0 ? args : void 0,
timestamp: /* @__PURE__ */ new Date()
});
};
/**
* 发射 HTTP 请求事件
* @param data - 请求数据 (不含 timestamp)
*/
var emitHttpRequest = (data) => {
amagiEvents.emit("http:request", {
...data,
timestamp: /* @__PURE__ */ new Date()
});
};
/**
* 发射 HTTP 响应事件
* @param data - 响应数据 (不含 timestamp)
*/
var emitHttpResponse = (data) => {
amagiEvents.emit("http:response", {
...data,
timestamp: /* @__PURE__ */ new Date()
});
};
/**
* 发射网络重试事件
* @param data - 重试数据 (不含 timestamp)
*/
var emitNetworkRetry = (data) => {
amagiEvents.emit("network:retry", {
...data,
timestamp: /* @__PURE__ */ new Date()
});
};
/**
* 发射网络错误事件
* @param data - 错误数据 (不含 timestamp)
*/
var emitNetworkError = (data) => {
amagiEvents.emit("network:error", {
...data,
timestamp: /* @__PURE__ */ new Date()
});
};
/**
* 发射 API 成功事件
* @param data - 成功数据 (不含 timestamp)
*/
var emitApiSuccess = (data) => {
amagiEvents.emit("api:success", {
...data,
timestamp: /* @__PURE__ */ new Date()
});
};
/**
* 发射 API 错误事件
* @param data - 错误数据 (不含 timestamp)
*/
var emitApiError = (data) => {
amagiEvents.emit("api:error", {
...data,
timestamp: /* @__PURE__ */ new Date()
});
};
/**
* 发射 info 级别日志
* @param message - 日志消息
* @param args - 附加参数
*/
var emitLogInfo = (message, ...args) => {
emitLog("info", message, ...args);
};
/**
* 发射 warn 级别日志
* @param message - 日志消息
* @param args - 附加参数
*/
var emitLogWarn = (message, ...args) => {
emitLog("warn", message, ...args);
};
/**
* 发射 error 级别日志
* @param message - 日志消息
* @param args - 附加参数
*/
var emitLogError = (message, ...args) => {
emitLog("error", message, ...args);
};
/**
* 发射 debug 级别日志
* @param message - 日志消息
* @param args - 附加参数
*/
var emitLogDebug = (message, ...args) => {
emitLog("debug", message, ...args);
};
/**
* 发射 mark 级别日志 (用于重要标记)
* @param message - 日志消息
* @param args - 附加参数
*/
var emitLogMark = (message, ...args) => {
emitLog("mark", message, ...args);
};
//#endregion
//#region ../amagi/packages/core/src/validation/utils.ts
function smartNumber(errorMessage, minValue = 1, isInteger = false) {
if (isInteger) return zod_default.coerce.number({ error: errorMessage }).int({ error: `${errorMessage.replace("不能为空", "")}必须是整数,不能包含小数` }).min(minValue, { error: `${errorMessage.replace("不能为空", "")}必须大于等于${minValue}` });
else return zod_default.coerce.number({ error: errorMessage }).min(minValue, { error: `${errorMessage.replace("不能为空", "")}必须大于等于${minValue}` });
}
/**
* 智能正整数转换器 - 专门用于正整数类型的转换
* @param errorMessage - 自定义错误信息
* @returns Zod正整数验证器
*/
var smartPositiveInteger = (errorMessage) => {
return smartNumber(errorMessage, 1, true);
};
/**
* 从页面HTML中提取用户信息
* @param html - 包含用户页面HTML的字符串
* @returns 提取到的用户信息对象或null
*/
var extractCreatorInfoFromHtml = (html) => {
const match = html.match(/<script>window\.__INITIAL_STATE__=(.+)<\/script>/m);
if (!match) return null;
try {
const jsonStr = match[1].replace(/:undefined/g, ":null");
return JSON.parse(jsonStr)?.user?.userPageData ?? null;
} catch (error) {
console.error("解析用户信息失败:", error);
return null;
}
};
//#endregion
//#region ../amagi/packages/core/src/validation/bilibili.ts
/** 视频信息参数验证 */
var BilibiliVideoParamsSchema = zod_default.object({
methodType: zod_default.literal("videoInfo", { error: "方法类型必须是\"videoInfo\"" }),
bvid: zod_default.string({ error: "BVID必须是字符串" }).min(1, { error: "BVID不能为空" })
});
/** 视频流参数验证 */
var BilibiliVideoDownloadParamsSchema = zod_default.object({
methodType: zod_default.literal("videoStream", { error: "方法类型必须是\"videoStream\"" }),
avid: smartNumber("AVID不能为空", 1, true),
cid: smartNumber("CID不能为空", 1, true)
});
/** 评论参数验证 */
var BilibiliCommentParamsSchema = zod_default.object({
methodType: zod_default.literal("comments", { error: "方法类型必须是\"comments\"" }),
oid: zod_default.string({ error: "OID必须是字符串" }).min(1, { error: "OID不能为空" }),
type: smartNumber("评论类型不能为空", 1, true).refine((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), { error: "无效的评论区类型" }),
number: zod_default.coerce.number({ error: "评论数量必须是数字" }).int({ error: "评论数量必须是整数" }).positive({ error: "评论数量必须是正数" }).default(20).optional(),
pn: zod_default.coerce.number({ error: "页码必须是数字" }).int({ error: "页码必须是整数" }).positive({ error: "页码必须是正数" }).default(1).optional()
});
/** 评论回复参数验证 */
var BilibiliCommentReplyParamsSchema = zod_default.object({
methodType: zod_default.literal("commentReplies", { error: "方法类型必须是\"commentReplies\"" }),
oid: zod_default.string({ error: "OID必须是字符串" }).min(1, { error: "OID不能为空" }),
type: smartNumber("评论类型不能为空", 1, true).refine((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), { error: "无效的评论区类型" }),
root: zod_default.string({ error: "根评论ID必须是字符串" }).min(1, { error: "根评论ID不能为空" }),
number: zod_default.coerce.number({ error: "评论数量必须是数字" }).int({ error: "评论数量必须是整数" }).positive({ error: "评论数量必须是正数" }).default(20).optional(),
pn: zod_default.coerce.number({ error: "页码必须是数字" }).int({ error: "页码必须是整数" }).positive({ error: "页码必须是正数" }).default(1).optional()
});
/** 用户参数验证 */
var BilibiliUserParamsSchema = zod_default.object({
methodType: zod_default.enum([
"userCard",
"userDynamicList",
"uploaderTotalViews",
"userSpaceInfo"
], { error: "方法类型必须是指定的枚举值之一" }),
host_mid: smartNumber("UP主UID不能为空", 1, true)
});
/** 表情参数验证 */
var BilibiliEmojiParamsSchema = zod_default.object({ methodType: zod_default.literal("emojiList", { error: "方法类型必须是\"emojiList\"" }) });
/** 番剧信息参数验证 */
var BilibiliBangumiInfoParamsSchema = zod_default.object({
methodType: zod_default.literal("bangumiInfo", { error: "方法类型必须是\"bangumiInfo\"" }),
ep_id: zod_default.string({ error: "番剧EP ID必须是字符串" }).min(1, { error: "番剧EP ID不能为空" }).optional(),
season_id: zod_default.string({ error: "番剧季度ID必须是字符串" }).optional()
}).refine((data) => data.ep_id ?? data.season_id, {
error: "ep_id 和 season_id 至少需要提供一个",
path: ["ep_id"]
});
/** 番剧流参数验证 */
var BilibiliBangumiStreamParamsSchema = zod_default.object({
methodType: zod_default.literal("bangumiStream", { error: "方法类型必须是\"bangumiStream\"" }),
cid: smartNumber("CID不能为空", 1, true),
ep_id: zod_default.string({ error: "番剧EP ID必须是字符串" }).min(1, { error: "番剧EP ID不能为空" })
});
/** 动态参数验证 */
var BilibiliDynamicParamsSchema = zod_default.object({
methodType: zod_default.enum(["dynamicDetail", "dynamicCard"], { error: "方法类型必须是\"dynamicDetail\"或\"dynamicCard\"" }),
dynamic_id: zod_default.string({ error: "动态ID必须是字符串" }).min(1, { error: "动态ID不能为空" })
});
/** 直播间参数验证 */
var BilibiliLiveParamsSchema = zod_default.object({
methodType: zod_default.enum(["liveRoomInfo", "liveRoomInit"], { error: "方法类型必须是\"liveRoomInfo\"或\"liveRoomInit\"" }),
room_id: zod_default.string({ error: "直播间ID必须是字符串" }).min(1, { error: "直播间ID不能为空" })
});
/** 登录状态参数验证 */
var BilibiliLoginParamsSchema = zod_default.object({ methodType: zod_default.literal("loginStatus", { error: "方法类型必须是\"loginStatus\"" }) });
/** 申请二维码参数验证 */
var BilibiliQrcodeParamsSchema = zod_default.object({ methodType: zod_default.literal("loginQrcode", { error: "方法类型必须是\"loginQrcode\"" }) });
/** 二维码状态参数验证 */
var BilibiliQrcodeStatusParamsSchema = zod_default.object({
methodType: zod_default.literal("qrcodeStatus", { error: "方法类型必须是\"qrcodeStatus\"" }),
qrcode_key: zod_default.string({ error: "二维码key必须是字符串" }).min(1, { error: "二维码key不能为空" })
});
/** AV转BV参数验证 */
var BilibiliAv2BvParamsSchema = zod_default.object({
methodType: zod_default.literal("avToBv", { error: "方法类型必须是\"avToBv\"" }),
avid: zod_default.coerce.number({ error: "AVID必须是数字" }).int({ error: "AVID必须是整数" }).positive({ error: "AVID必须是正数" })
});
/** BV转AV参数验证 */
var BilibiliBv2AvParamsSchema = zod_default.object({
methodType: zod_default.literal("bvToAv", { error: "方法类型必须是\"bvToAv\"" }),
bvid: zod_default.string({ error: "BVID必须是字符串" }).min(1, { error: "BVID不能为空" })
});
/** 专栏内容参数验证 */
var BilibiliArticleParamsSchema = zod_default.object({
methodType: zod_default.literal("articleContent", { error: "方法类型必须是\"articleContent\"" }),
id: zod_default.string({ error: "专栏ID必须是字符串" }).min(1, { error: "专栏ID不能为空" })
});
/** 专栏卡片参数验证 */
var BilibiliArticleCardParamsSchema = zod_default.object({
methodType: zod_default.literal("articleCards", { error: "方法类型必须是\"articleCards\"" }),
ids: zod_default.union([zod_default.array(zod_default.string({ error: "被查询的 id 列表必须是字符串数组" })).min(1, { error: "被查询的 id 列表不能为空" }), zod_default.string({ error: "被查询的 id 列表必须是字符串" }).min(1, { error: "被查询的 id 列表不能为空" })])
});
/** 专栏信息参数验证 */
var BilibiliArticleInfoParamsSchema = zod_default.object({
methodType: zod_default.literal("articleInfo", { error: "方法类型必须是\"articleInfo\"" }),
id: zod_default.string({ error: "专栏ID必须是字符串" }).min(1, { error: "专栏ID不能为空" })
});
/** 文集信息参数验证 */
var BilibiliColumnInfoParamsSchema = zod_default.object({
methodType: zod_default.literal("articleListInfo", { error: "方法类型必须是\"articleListInfo\"" }),
id: zod_default.string({ error: "文集ID必须是字符串" }).min(1, { error: "文集ID不能为空" })
});
/** 验证码申请参数验证 */
var BilibiliApplyCaptchaParamsSchema = zod_default.object({
methodType: zod_default.literal("captchaFromVoucher", { error: "方法类型必须是\"captchaFromVoucher\"" }),
csrf: zod_default.string({ error: "CSRF Token必须是字符串" }).optional(),
v_voucher: zod_default.string({ error: "验证码ID必须是字符串" }).min(1, { error: "验证码ID不能为空" })
});
/** 验证码验证参数验证 */
var BilibiliValidateCaptchaParamsSchema = zod_default.object({
methodType: zod_default.literal("validateCaptcha", { error: "方法类型必须是\"validateCaptcha\"" }),
csrf: zod_default.string({ error: "CSRF Token必须是字符串" }).optional(),
challenge: zod_default.string({ error: "验证码challenge必须是字符串" }).min(1, { error: "验证码challenge不能为空" }),
token: zod_default.string({ error: "验证码token必须是字符串" }).min(1, { error: "验证码token不能为空" }),
validate: zod_default.string({ error: "验证码validate必须是字符串" }).min(1, { error: "验证码validate不能为空" }),
seccode: zod_default.string({ error: "验证码seccode必须是字符串" }).min(1, { error: "验证码seccode不能为空" })
});
/** 弹幕参数验证 */
var BilibiliDanmakuParamsSchema = zod_default.object({
methodType: zod_default.literal("videoDanmaku", { error: "方法类型必须是\"videoDanmaku\"" }),
cid: smartNumber("CID不能为空", 1, true),
segment_index: zod_default.coerce.number({ error: "分段序号必须是数字" }).int({ error: "分段序号必须是整数" }).positive({ error: "分段序号必须是正数" }).default(1).optional()
});
/** B站参数验证模式映射 */
var BilibiliValidationSchemas = {
videoInfo: BilibiliVideoParamsSchema,
videoStream: BilibiliVideoDownloadParamsSchema,
comments: BilibiliCommentParamsSchema,
commentReplies: BilibiliCommentReplyParamsSchema,
userCard: BilibiliUserParamsSchema,
userDynamicList: BilibiliUserParamsSchema,
userSpaceInfo: BilibiliUserParamsSchema,
emojiList: BilibiliEmojiParamsSchema,
bangumiInfo: BilibiliBangumiInfoParamsSchema,
bangumiStream: BilibiliBangumiStreamParamsSchema,
dynamicDetail: BilibiliDynamicParamsSchema,
dynamicCard: BilibiliDynamicParamsSchema,
liveRoomInfo: BilibiliLiveParamsSchema,
liveRoomInit: BilibiliLiveParamsSchema,
loginStatus: BilibiliLoginParamsSchema,
loginQrcode: BilibiliQrcodeParamsSchema,
qrcodeStatus: BilibiliQrcodeStatusParamsSchema,
uploaderTotalViews: BilibiliUserParamsSchema,
avToBv: BilibiliAv2BvParamsSchema,
bvToAv: BilibiliBv2AvParamsSchema,
articleContent: BilibiliArticleParamsSchema,
articleCards: BilibiliArticleCardParamsSchema,
articleInfo: BilibiliArticleInfoParamsSchema,
articleListInfo: BilibiliColumnInfoParamsSchema,
captchaFromVoucher: BilibiliApplyCaptchaParamsSchema,
validateCaptcha: BilibiliValidateCaptchaParamsSchema,
videoDanmaku: BilibiliDanmakuParamsSchema
};
/** B站方法路由映射 */
var BilibiliMethodRoutes = {
videoInfo: "/fetch_one_video",
videoStream: "/fetch_video_playurl",
comments: "/fetch_work_comments",
commentReplies: "/fetch_comment_reply",
userCard: "/fetch_user_profile",
userDynamicList: "/fetch_user_dynamic",
userSpaceInfo: "/fetch_user_space_info",
emojiList: "/fetch_emoji_list",
bangumiInfo: "/fetch_bangumi_video_info",
bangumiStream: "/fetch_bangumi_video_playurl",
dynamicDetail: "/fetch_dynamic_info",
dynamicCard: "/fetch_dynamic_card",
liveRoomInfo: "/fetch_live_room_detail",
liveRoomInit: "/fetch_liveroom_def",
loginStatus: "/login_basic_info",
loginQrcode: "/new_login_qrcode",
qrcodeStatus: "/check_qrcode",
uploaderTotalViews: "/fetch_user_full_view",
avToBv: "/av_to_bv",
bvToAv: "/bv_to_av",
articleContent: "/fetch_article_content",
articleCards: "/fetch_article_card",
articleInfo: "/fetch_article_info",
articleListInfo: "/fetch_column_info",
captchaFromVoucher: "/apply_captcha",
validateCaptcha: "/validate_captcha",
videoDanmaku: "/fetch_danmaku"
};
//#endregion
//#region ../amagi/packages/core/src/validation/douyin.ts
/** 作品参数验证 */
var DouyinWorkParamsSchema = zod_default.object({
methodType: zod_default.enum([
"videoWork",
"imageAlbumWork",
"slidesWork",
"parseWork",
"textWork"
], { error: "方法类型必须是指定的枚举值之一" }),
aweme_id: zod_default.string({ error: "视频ID必须是字符串" }).min(1, { error: "视频ID不能为空" })
});
/** 评论参数验证 */
var DouyinCommentParamsSchema = zod_default.object({
methodType: zod_default.literal("comments", { error: "方法类型必须是\"comments\"" }),
aweme_id: zod_default.string({ error: "视频ID必须是字符串" }).min(1, { error: "视频ID不能为空" }),
number: smartPositiveInteger("评论数量必须是正整数").optional().default(50),
cursor: zod_default.coerce.number({ error: "游标必须是数字" }).int({ error: "游标必须是整数" }).min(0, { error: "游标不能小于0" }).default(0).optional()
});
/** 热点词参数验证 */
var DouyinHotWordsParamsSchema = zod_default.object({
methodType: zod_default.literal("suggestWords", { error: "方法类型必须是\"suggestWords\"" }),
query: zod_default.string({ error: "搜索词必须是字符串" }).min(1, { error: "搜索词不能为空" })
});
/** 搜索参数验证 */
var DouyinSearchParamsSchema = zod_default.object({
methodType: zod_default.literal("search", { error: "方法类型必须是\"search\"" }),
query: zod_default.string({ error: "搜索词必须是字符串" }).min(1, { error: "搜索词不能为空" }),
type: zod_default.enum([
"general",
"user",
"video"
], { error: "搜索类型必须是\"general\"、\"user\"或\"video\"" }).optional().default("general"),
number: smartPositiveInteger("搜索数量必须是正整数").optional().default(10),
search_id: zod_default.string({ error: "搜索ID必须是字符串" }).optional()
});
/** 评论回复参数验证 */
var DouyinCommentReplyParamsSchema = zod_default.object({
methodType: zod_default.literal("commentReplies", { error: "方法类型必须是\"commentReplies\"" }),
aweme_id: zod_default.string({ error: "视频ID必须是字符串" }).min(1, { error: "视频ID不能为空" }),
comment_id: zod_default.string({ error: "评论ID必须是字符串" }).min(1, { error: "评论ID不能为空" }),
number: smartPositiveInteger("评论数量必须是正整数").optional().default(5),
cursor: zod_default.coerce.number({ error: "游标必须是数字" }).int({ error: "游标必须是整数" }).min(0, { error: "游标不能小于0" }).default(0).optional()
});
/** 用户参数验证 */
var DouyinUserParamsSchema = zod_default.object({
methodType: zod_default.literal("userProfile", { error: "方法类型必须是\"userProfile\"" }),
sec_uid: zod_default.string({ error: "用户ID必须是字符串" }).min(1, { error: "用户ID不能为空" })
});
/** 用户列表参数验证(视频列表、喜欢列表、推荐列表) */
var DouyinUserListParamsSchema = zod_default.object({
methodType: zod_default.enum([
"userVideoList",
"userFavoriteList",
"userRecommendList"
], { error: "方法类型必须是指定的枚举值之一" }),
sec_uid: zod_default.string({ error: "用户ID必须是字符串" }).min(1, { error: "用户ID不能为空" }),
number: smartPositiveInteger("获取数量必须是正整数").optional().default(18),
max_cursor: zod_default.string({ error: "游标必须是字符串" }).optional()
});
/** 音乐参数验证 */
var DouyinMusicParamsSchema = zod_default.object({
methodType: zod_default.literal("musicInfo", { error: "方法类型必须是\"musicInfo\"" }),
music_id: zod_default.string({ error: "音乐ID必须是字符串" }).min(1, { error: "音乐ID不能为空" })
});
/** 直播间参数验证 */
var DouyinLiveRoomParamsSchema = zod_default.object({
methodType: zod_default.literal("liveRoomInfo", { error: "方法类型必须是\"liveRoomInfo\"" }),
web_rid: zod_default.string({ error: "直播间ID必须是字符串" }).min(1, { error: "直播间ID不能为空" }),
room_id: zod_default.string({ error: "直播间ID必须是字符串" }).min(1, { error: "直播间ID不能为空" })
});
/** 二维码参数验证 */
var DouyinQrcodeParamsSchema = zod_default.object({
methodType: zod_default.literal("loginQrcode", { error: "方法类型必须是\"loginQrcode\"" }),
verify_fp: zod_default.string({ error: "fp指纹必须是字符串" }).min(1, { error: "fp指纹不能为空" })
});
/** 表情列表参数验证 */
var DouyinEmojiListParamsSchema = zod_default.object({ methodType: zod_default.literal("emojiList", { error: "方法类型必须是\"emojiList\"" }) });
/** 动态表情参数验证 */
var DouyinEmojiProParamsSchema = zod_default.object({ methodType: zod_default.literal("dynamicEmojiList", { error: "方法类型必须是\"dynamicEmojiList\"" }) });
/** 弹幕参数验证 */
var DouyinDanmakuParamsSchema = zod_default.object({
methodType: zod_default.literal("danmakuList", { error: "方法类型必须是\"danmakuList\"" }),
aweme_id: zod_default.string({ error: "视频ID必须是字符串" }).min(1, { error: "视频ID不能为空" }),
start_time: zod_default.coerce.number({ error: "开始时间必须是数字" }).int({ error: "开始时间必须是整数" }).min(0, { error: "开始时间不能小于0" }).optional(),
end_time: zod_default.coerce.number({ error: "结束时间必须是数字" }).int({ error: "结束时间必须是整数" }).min(0, { error: "结束时间不能小于0" }).optional(),
duration: zod_default.coerce.number({ error: "视频时长必须是数字" }).int({ error: "视频时长必须是整数" }).min(0, { error: "视频时长不能小于0" })
}).refine((data) => {
if (data.end_time !== void 0) return data.end_time <= data.duration;
return true;
}, {
error: "获取弹幕区间的结束时间不能超过视频总时长",
path: ["end_time"]
}).refine((data) => {
if (data.start_time !== void 0 && data.end_time !== void 0) return data.start_time < data.end_time;
return true;
}, {
error: "获取弹幕区间的开始时间必须小于结束时间",
path: ["start_time"]
});
/** 抖音参数验证模式映射 */
var DouyinValidationSchemas = {
textWork: DouyinWorkParamsSchema,
parseWork: DouyinWorkParamsSchema,
videoWork: DouyinWorkParamsSchema,
imageAlbumWork: DouyinWorkParamsSchema,
slidesWork: DouyinWorkParamsSchema,
comments: DouyinCommentParamsSchema,
userProfile: DouyinUserParamsSchema,
userVideoList: DouyinUserListParamsSchema,
userFavoriteList: DouyinUserListParamsSchema,
userRecommendList: DouyinUserListParamsSchema,
suggestWords: DouyinHotWordsParamsSchema,
search: DouyinSearchParamsSchema,
musicInfo: DouyinMusicParamsSchema,
liveRoomInfo: DouyinLiveRoomParamsSchema,
loginQrcode: DouyinQrcodeParamsSchema,
emojiList: DouyinEmojiListParamsSchema,
dynamicEmojiList: DouyinEmojiProParamsSchema,
commentReplies: DouyinCommentReplyParamsSchema,
danmakuList: DouyinDanmakuParamsSchema
};
/** 抖音方法路由映射 */
var DouyinMethodRoutes = {
parseWork: "/fetch_one_work",
textWork: "/fetch_one_work",
videoWork: "/fetch_one_work",
imageAlbumWork: "/fetch_one_work",
slidesWork: "/fetch_one_work",
comments: "/fetch_work_comments",
commentReplies: "/fetch_video_comment_replies",
userProfile: "/fetch_user_info",
userVideoList: "/fetch_user_post_videos",
userFavoriteList: "/fetch_user_favorite_list",
userRecommendList: "/fetch_user_recommend_list",
search: "/fetch_search_info",
suggestWords: "/fetch_suggest_words",
musicInfo: "/fetch_music_work",
emojiList: "/fetch_emoji_list",
dynamicEmojiList: "/fetch_emoji_pro_list",
liveRoomInfo: "/fetch_user_live_videos",
danmakuList: "/fetch_work_danmaku",
loginQrcode: "/fetch_login_qrcode"
};
//#endregion
//#region ../amagi/packages/core/src/validation/kuaishou.ts
/**
* 快手视频参数验证模式
*/
var KuaishouVideoParamsSchema = zod_default.object({
methodType: zod_default.literal("videoWork", { error: "methodType must be \"videoWork\"" }),
photoId: zod_default.string({ error: "photoId must be a string" }).min(1, { error: "photoId cannot be empty" })
});
/**
* 快手评论参数验证模式
*/
var KuaishouCommentParamsSchema = zod_default.object({
methodType: zod_default.literal("comments", { error: "methodType must be \"comments\"" }),
photoId: zod_default.string({ error: "photoId must be a string" }).min(1, { error: "photoId cannot be empty" })
});
/**
* 快手用户主页参数验证模式
*/
var KuaishouUserProfileParamsSchema = zod_default.object({
methodType: zod_default.literal("userProfile", { error: "methodType must be \"userProfile\"" }),
principalId: zod_default.string({ error: "principalId must be a string" }).min(1, { error: "principalId cannot be empty" })
});
/**
* 快手用户作品列表参数验证模式
*/
var KuaishouUserWorkListParamsSchema = zod_default.object({
methodType: zod_default.literal("userWorkList", { error: "methodType must be \"userWorkList\"" }),
principalId: zod_default.string({ error: "principalId must be a string" }).min(1, { error: "principalId cannot be empty" }),
pcursor: zod_default.string({ error: "pcursor must be a string" }).optional(),
count: zod_default.number({ error: "count must be a number" }).int({ error: "count must be an integer" }).positive({ error: "count must be positive" }).max(100, { error: "count must be less than or equal to 100" }).optional()
});
/**
* 快手直播间信息参数验证模式
*/
var KuaishouLiveRoomInfoParamsSchema = zod_default.object({
methodType: zod_default.literal("liveRoomInfo", { error: "methodType must be \"liveRoomInfo\"" }),
principalId: zod_default.string({ error: "principalId must be a string" }).min(1, { error: "principalId cannot be empty" })
});
/**
* 快手表情参数验证模式
*/
var KuaishouEmojiParamsSchema = zod_default.object({ methodType: zod_default.literal("emojiList", { error: "methodType must be \"emojiList\"" }) });
/**
* 快手参数验证模式映射
*/
var KuaishouValidationSchemas = {
videoWork: KuaishouVideoParamsSchema,
comments: KuaishouCommentParamsSchema,
userProfile: KuaishouUserProfileParamsSchema,
userWorkList: KuaishouUserWorkListParamsSchema,
liveRoomInfo: KuaishouLiveRoomInfoParamsSchema,
emojiList: KuaishouEmojiParamsSchema
};
/**
* 快手方法路由映射
*/
var KuaishouMethodRoutes = {
videoWork: "/fetch_one_work",
comments: "/fetch_work_comments",
userProfile: "/fetch_user_profile",
userWorkList: "/fetch_user_work_list",
liveRoomInfo: "/fetch_live_room_info",
emojiList: "/fetch_emoji_list"
};
//#endregion
//#region ../amagi/packages/core/src/platform/xiaohongshu/sign/index.ts
/**
* 小红书签名算法类
*/
var xiaohongshuSign = class {
static client = new Xhshow();
/**
* 生成GET请求的X-S签名
* @param path - API路径
* @param a1Cookie - a1 cookie值
* @param clientType - 客户端类型,默认为 'xhs-pc-web'
* @param params - 查询参数对象
* @returns X-S签名
*/
static generateXSGet(path, a1Cookie, clientType = "xhs-pc-web", params = {}) {
return this.client.signXsGet(path, a1Cookie, clientType, params);
}
/**
* 生成POST请求的X-S签名
* @param path - API路径
* @param a1Cookie - a1 cookie值
* @param clientType - 客户端类型,默认为 'xhs-pc-web'
* @param body - 请求体对象
* @returns X-S签名
*/
static generateXSPost(path, a1Cookie, clientType = "xhs-pc-web", body = {}) {
return this.client.signXsPost(path, a1Cookie, clientType, body);
}
/**
* 生成X-S-Common参数
* @param cookies - cookie字符串
* @returns Base64编码的随机字符串
*/
static generateXSCommon(cookies) {
return this.client.signXsCommon(cookies);
}
/**
* 生成X-T时间戳
* @returns 当前时间戳字符串
*/
static generateXT() {
return this.client.getXT();
}
/**
* 生成X-B3-Traceid
* @returns 16位随机字符串
*/
static generateXB3Traceid() {
return this.client.getB3TraceId();
}
/**
* 从cookie字符串中提取a1值
* @param cookieString - 完整的cookie字符串
* @returns a1 cookie值
*/
static extractA1FromCookie(cookieString) {
const match = cookieString.match(/a1=([^;]+)/);
return match ? match[1] : "";
}
/**
* 生成搜索ID
* @returns 搜索ID字符串
*/
static getSearchId = () => (BigInt(Date.now()) << 64n) + BigInt(Math.floor(Math.random() * 2147483646)).toString(36);
};
//#endregion
//#region ../amagi/packages/core/src/platform/xiaohongshu/API.ts
/**
* 搜索排序类型枚举
*/
var SearchSortType = /* @__PURE__ */ function(SearchSortType) {
/**
* 默认排序
*/
SearchSortType["GENERAL"] = "general";
/**
* 最受欢迎(按热度降序)
*/
SearchSortType["MOST_POPULAR"] = "popularity_descending";
/**
* 最新发布(按时间降序)
*/
SearchSortType["LATEST"] = "time_descending";
return SearchSortType;
}({});
/**
* 搜索笔记类型枚举
*/
var SearchNoteType = /* @__PURE__ */ function(SearchNoteType) {
/**
* 默认(全部类型)
*/
SearchNoteType[SearchNoteType["ALL"] = 0] = "ALL";
/**
* 仅视频
*/
SearchNoteType[SearchNoteType["VIDEO"] = 1] = "VIDEO";
/**
* 仅图片
*/
SearchNoteType[SearchNoteType["IMAGE"] = 2] = "IMAGE";
return SearchNoteType;
}({});
/**
* 构建查询字符串
* @param params - 参数对象
* @returns 查询字符串
*/
var buildQueryString$1 = (params) => {
return Object.entries(params).filter(([_, value]) => value !== void 0 && value !== null).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&");
};
/**
* 小红书API地址配置
*/
var xiaohongshuApiUrls = {
/**
* 获取首页推荐数据的接口地址
* @param data - 请求参数
* @returns 完整的接口URL
*/
homeFeed(data = {}) {
return {
apiPath: "/api/sns/web/v1/homefeed",
Url: "https://edith.xiaohongshu.com/api/sns/web/v1/homefeed",
Body: {
cursor_score: data.cursor_score ?? "1.7599348899670024E9",
num: data.num ?? 33,
refresh_type: data.refresh_type ?? 3,
note_index: d