Files
天天的鸟蛋蛋 b9655a5ab1 SnowCat 雪猫底层全源码:NapCat 4.18.28 底座 + SnowLuma 能力移植 + V8 通道适配 9.9.37
26 包 monorepo(TS 全源码):
- snowcat-core: NT 内核 API 封装 + listener(含 9.9.37 六回调适配)+ Packet 发包
- snowcat-onebot: OneBot v11 全动作 + MCP Streamable HTTP 适配器 + 稳定线
- snowcat-webui-frontend/backend: 雪猫控制台(React+HeroUI)
- snowcat-shell: 单文件 bundle 出口(vite inlineDynamicImports)
- snowcat-native: napi2native / MoeHoo / ffmpeg / pty 运行时
- 56 项 SnowLuma 独门动作移植(qzone 全家桶/群相册/装扮/闪照/收藏)
- 工具件: 解包器/启动器/便携制作器/doctor

GitHub 关联已全量指向 DandanLLab/SnowCatQQ
2026-11-12 06:27:36 +08:00

323 lines
15 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* SnowCat · QQ空间公共空间(空友推荐)13 动作
*
* 底层:snowcat-core/apis/qzone-public-web.ts(SnowLuma qzone-public.ts 移植)
* 动作约定:feed/comment/reply 等复杂对象由调用方从 get_qzone_public_feeds /
* get_qzone_public_feed_detail 的返回中原样回传(透明通道,不做二次建模)。
*/
import { OneBotAction } from '@/snowcat-onebot/action/OneBotAction';
import { ActionName } from '@/snowcat-onebot/action/router';
import { Static, Type } from '@sinclair/typebox';
const FeedObject = Type.Any({ description: '完整动态对象(来自 get_qzone_public_feeds/feed_detail,原样回传)' });
const CommentObject = Type.Any({ description: '评论对象(原样回传)' });
const ReplyObject = Type.Optional(Type.Any({ description: '回复对象(原样回传)' }));
const UserObject = Type.Any({ description: '用户身份对象(详情/列表响应里的 user 形态)' });
/** 公共动作共用的 WebApi 快捷取凭证。 */
function publicApi (action: OneBotAction<unknown, unknown>) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (action as any).core.apis.WebApi;
}
// 1. get_qzone_public_capabilities —— 查询账号空友入口白名单
const CapPayload = Type.Object({});
export class GetQzonePublicCapabilities extends OneBotAction<Static<typeof CapPayload>, unknown> {
override actionName = ActionName.GetQzonePublicCapabilities;
override actionSummary = '查询空友入口能力';
override actionDescription = '查询当前账号在 QQ 空间公共空间(空友)各入口的白名单能力';
override actionTags = ['扩展接口'];
override payloadExample = {};
override returnExample = { entrance1: true, entrance15: false };
override payloadSchema = CapPayload;
override returnSchema = Type.Any();
async _handle () {
const api = publicApi(this);
const { uin, g_tk, cookie } = await api.getQzoneAuth();
return api.getQzonePublicCapabilities(cookie, g_tk, uin);
}
}
// 2. get_qzone_public_feeds —— 空友推荐动态流
const FeedsPayload = Type.Object({
cursor: Type.Optional(Type.String({ description: '上次返回的 next_cursor,续翻用' })),
});
export class GetQzonePublicFeeds extends OneBotAction<Static<typeof FeedsPayload>, unknown> {
override actionName = ActionName.GetQzonePublicFeeds;
override actionSummary = '获取空友推荐动态';
override actionDescription = '读取QQ空间公共空间(空友)推荐动态流,cursor 续翻';
override actionTags = ['扩展接口'];
override payloadExample = {};
override returnExample = { feeds: [], has_more: false, next_cursor: null };
override payloadSchema = FeedsPayload;
override returnSchema = Type.Any();
async _handle (payload: Static<typeof FeedsPayload>) {
const { uin, g_tk, cookie } = await publicApi(this).getQzoneAuth();
return publicApi(this).getQzonePublicFeeds(cookie, g_tk, uin, payload.cursor);
}
}
// 3. get_qzone_public_feed_detail —— 空友单条动态详情
const DetailPayload = Type.Object({ feed: FeedObject });
export class GetQzonePublicFeedDetail extends OneBotAction<Static<typeof DetailPayload>, unknown> {
override actionName = ActionName.GetQzonePublicFeedDetail;
override actionSummary = '获取空友动态详情';
override actionDescription = '获取一条空友推荐动态的完整详情(含评论首屏)';
override actionTags = ['扩展接口'];
override payloadExample = { feed: {} };
override returnExample = {};
override payloadSchema = DetailPayload;
override returnSchema = Type.Any();
async _handle (payload: Static<typeof DetailPayload>) {
const { g_tk, cookie } = await publicApi(this).getQzoneAuth();
return publicApi(this).getQzonePublicFeedDetail(cookie, g_tk, payload.feed);
}
}
// 4. get_qzone_public_comments —— 空友评论分页
const CommentsPayload = Type.Object({
feed: FeedObject,
cursor: Type.String({ description: '详情/上页返回的评论 attach_info' }),
});
export class GetQzonePublicComments extends OneBotAction<Static<typeof CommentsPayload>, unknown> {
override actionName = ActionName.GetQzonePublicComments;
override actionSummary = '获取空友评论分页';
override actionDescription = '分页读取一条空友动态的评论';
override actionTags = ['扩展接口'];
override payloadExample = { feed: {}, cursor: '' };
override returnExample = {};
override payloadSchema = CommentsPayload;
override returnSchema = Type.Any();
async _handle (payload: Static<typeof CommentsPayload>) {
const { g_tk, cookie } = await publicApi(this).getQzoneAuth();
return publicApi(this).getQzonePublicComments(cookie, g_tk, payload.feed, payload.cursor);
}
}
// 5. get_qzone_public_replies —— 空友楼中楼分页
const RepliesPayload = Type.Object({
feed: FeedObject,
comment: CommentObject,
cursor: Type.Optional(Type.String({ description: '回复 attach_info,省略用 comment 自带' })),
page_size: Type.Optional(Type.Union([Type.Number(), Type.String()], { default: 20, description: '每页条数' })),
});
export class GetQzonePublicReplies extends OneBotAction<Static<typeof RepliesPayload>, unknown> {
override actionName = ActionName.GetQzonePublicReplies;
override actionSummary = '获取空友楼中楼分页';
override actionDescription = '分页读取一条空友评论的楼中楼回复';
override actionTags = ['扩展接口'];
override payloadExample = { feed: {}, comment: {}, cursor: '', page_size: 20 };
override returnExample = {};
override payloadSchema = RepliesPayload;
override returnSchema = Type.Any();
async _handle (payload: Static<typeof RepliesPayload>) {
const { g_tk, cookie } = await publicApi(this).getQzoneAuth();
return publicApi(this).getQzonePublicReplies(
cookie, g_tk, payload.feed, payload.comment,
payload.cursor ?? '', payload.page_size !== undefined ? +payload.page_size : 20,
);
}
}
// 6. set_qzone_public_upvote —— 空友动态点赞/取消(UFO Upvote)
const UpvotePayload = Type.Object({ feed: FeedObject, enable: Type.Boolean({ default: true }) });
export class SetQzonePublicUpvote extends OneBotAction<Static<typeof UpvotePayload>, unknown> {
override actionName = ActionName.SetQzonePublicUpvote;
override actionSummary = '空友动态点赞/取消';
override actionDescription = '对一条空友推荐动态点赞或取消点赞(UFO Upvote/Downvote)';
override actionTags = ['扩展接口'];
override payloadExample = { feed: {}, enable: true };
override returnExample = {};
override payloadSchema = UpvotePayload;
override returnSchema = Type.Any();
async _handle (payload: Static<typeof UpvotePayload>) {
const { g_tk, cookie } = await publicApi(this).getQzoneAuth();
return publicApi(this).setQzonePublicUpvote(cookie, g_tk, payload.feed, payload.enable);
}
}
// 7. set_qzone_public_like —— 空友动态点赞(DoLike 系)
const LikePayload = Type.Object({ feed: FeedObject, enable: Type.Boolean({ default: true }) });
export class SetQzonePublicLike extends OneBotAction<Static<typeof LikePayload>, unknown> {
override actionName = ActionName.SetQzonePublicLike;
override actionSummary = '空友动态点赞(DoLike)';
override actionDescription = '对一条空友动态点赞/取消赞(DoLike/UnLike,key 取 cur_like_key)';
override actionTags = ['扩展接口'];
override payloadExample = { feed: {}, enable: true };
override returnExample = {};
override payloadSchema = LikePayload;
override returnSchema = Type.Any();
async _handle (payload: Static<typeof LikePayload>) {
const { g_tk, cookie } = await publicApi(this).getQzoneAuth();
return publicApi(this).setQzonePublicLike(cookie, g_tk, payload.feed, payload.enable);
}
}
// 8. set_qzone_public_comment_like —— 空友评论/回复点赞
const CommentLikePayload = Type.Object({
feed: FeedObject,
comment: CommentObject,
reply: ReplyObject,
enable: Type.Boolean({ default: true }),
});
export class SetQzonePublicCommentLike extends OneBotAction<Static<typeof CommentLikePayload>, unknown> {
override actionName = ActionName.SetQzonePublicCommentLike;
override actionSummary = '空友评论/回复点赞';
override actionDescription = '给空友评论点赞(like_type=2)或给楼中楼回复点赞(like_type=3)';
override actionTags = ['扩展接口'];
override payloadExample = { feed: {}, comment: {}, enable: true };
override returnExample = {};
override payloadSchema = CommentLikePayload;
override returnSchema = Type.Any();
async _handle (payload: Static<typeof CommentLikePayload>) {
const { g_tk, cookie } = await publicApi(this).getQzoneAuth();
return publicApi(this).setQzonePublicCommentLike(
cookie, g_tk, payload.feed, payload.comment, payload.enable,
payload.reply as Record<string, unknown> | undefined,
);
}
}
// 9. comment_qzone_public_feed —— 空友发评论
const CommentPayload = Type.Object({
feed: FeedObject,
user: UserObject,
content: Type.Union([Type.String(), Type.Array(Type.Any())], { description: '评论内容:纯文本或富内容数组' }),
});
export class CommentQzonePublicFeed extends OneBotAction<Static<typeof CommentPayload>, unknown> {
override actionName = ActionName.CommentQzonePublicFeed;
override actionSummary = '空友发评论';
override actionDescription = '给一条空友推荐动态发评论';
override actionTags = ['扩展接口'];
override payloadExample = { feed: {}, user: {}, content: '说得好' };
override returnExample = {};
override payloadSchema = CommentPayload;
override returnSchema = Type.Any();
async _handle (payload: Static<typeof CommentPayload>) {
const { g_tk, cookie } = await publicApi(this).getQzoneAuth();
return publicApi(this).commentQzonePublicFeed(
cookie, g_tk, payload.feed,
payload.user as Record<string, unknown>,
payload.content as string | Record<string, unknown>[],
);
}
}
// 10. reply_qzone_public_feed —— 空友回复评论/楼中楼
const ReplyPayload = Type.Object({
feed: FeedObject,
user: UserObject,
comment: CommentObject,
content: Type.Union([Type.String(), Type.Array(Type.Any())], { description: '回复内容' }),
reply: ReplyObject,
});
export class ReplyQzonePublicFeed extends OneBotAction<Static<typeof ReplyPayload>, unknown> {
override actionName = ActionName.ReplyQzonePublicFeed;
override actionSummary = '空友回复评论';
override actionDescription = '在空友动态的评论线程里回复(可点名楼中楼目标)';
override actionTags = ['扩展接口'];
override payloadExample = { feed: {}, user: {}, comment: {}, content: '同意' };
override returnExample = {};
override payloadSchema = ReplyPayload;
override returnSchema = Type.Any();
async _handle (payload: Static<typeof ReplyPayload>) {
const { g_tk, cookie } = await publicApi(this).getQzoneAuth();
return publicApi(this).replyQzonePublicFeed(
cookie, g_tk, payload.feed,
payload.user as Record<string, unknown>,
payload.comment as Record<string, unknown>,
payload.content as string | Record<string, unknown>[],
payload.reply as Record<string, unknown> | undefined,
);
}
}
// 11. delete_qzone_public_comment —— 删空友评论
const DelCommentPayload = Type.Object({ feed: FeedObject, comment: CommentObject });
export class DeleteQzonePublicComment extends OneBotAction<Static<typeof DelCommentPayload>, unknown> {
override actionName = ActionName.DeleteQzonePublicComment;
override actionSummary = '删空友评论';
override actionDescription = '删除一条空友动态的评论(自己的评论)';
override actionTags = ['扩展接口'];
override payloadExample = { feed: {}, comment: {} };
override returnExample = {};
override payloadSchema = DelCommentPayload;
override returnSchema = Type.Any();
async _handle (payload: Static<typeof DelCommentPayload>) {
const { g_tk, cookie } = await publicApi(this).getQzoneAuth();
return publicApi(this).deleteQzonePublicComment(
cookie, g_tk, payload.feed, payload.comment as Record<string, unknown>,
);
}
}
// 12. delete_qzone_public_reply —— 删空友楼中楼
const DelReplyPayload = Type.Object({ feed: FeedObject, comment: CommentObject, reply: Type.Any({ description: '回复对象(原样回传)' }) });
export class DeleteQzonePublicReply extends OneBotAction<Static<typeof DelReplyPayload>, unknown> {
override actionName = ActionName.DeleteQzonePublicReply;
override actionSummary = '删空友楼中楼';
override actionDescription = '删除一条空友评论的楼中楼回复(自己的回复)';
override actionTags = ['扩展接口'];
override payloadExample = { feed: {}, comment: {}, reply: {} };
override returnExample = {};
override payloadSchema = DelReplyPayload;
override returnSchema = Type.Any();
async _handle (payload: Static<typeof DelReplyPayload>) {
const { g_tk, cookie } = await publicApi(this).getQzoneAuth();
return publicApi(this).deleteQzonePublicReply(
cookie, g_tk, payload.feed,
payload.comment as Record<string, unknown>,
payload.reply as Record<string, unknown>,
);
}
}
// 13. set_qzone_public_follow —— 空友关注/取关
const FollowPayload = Type.Object({ feed: FeedObject, enable: Type.Boolean({ default: true }) });
export class SetQzonePublicFollow extends OneBotAction<Static<typeof FollowPayload>, unknown> {
override actionName = ActionName.SetQzonePublicFollow;
override actionSummary = '空友关注/取关';
override actionDescription = '关注/取关一条空友动态的作者';
override actionTags = ['扩展接口'];
override payloadExample = { feed: {}, enable: true };
override returnExample = {};
override payloadSchema = FollowPayload;
override returnSchema = Type.Any();
async _handle (payload: Static<typeof FollowPayload>) {
const { g_tk, cookie } = await publicApi(this).getQzoneAuth();
return publicApi(this).setQzonePublicFollow(cookie, g_tk, payload.feed, payload.enable);
}
}
// 14. forward_qzone_public_feed —— 转发空友动态
const ForwardPayload = Type.Object({ feed: FeedObject, reason: Type.String({ description: '转发理由/附言' }) });
export class ForwardQzonePublicFeed extends OneBotAction<Static<typeof ForwardPayload>, unknown> {
override actionName = ActionName.ForwardQzonePublicFeed;
override actionSummary = '转发空友动态';
override actionDescription = '转发一条空友推荐动态到自己的空间';
override actionTags = ['扩展接口'];
override payloadExample = { feed: {}, reason: '转发' };
override returnExample = {};
override payloadSchema = ForwardPayload;
override returnSchema = Type.Any();
async _handle (payload: Static<typeof ForwardPayload>) {
const { g_tk, cookie } = await publicApi(this).getQzoneAuth();
return publicApi(this).forwardQzonePublicFeed(cookie, g_tk, payload.feed, payload.reason);
}
}