Files
note2any/src/xiaohongshu/types.ts
2025-10-08 09:18:20 +08:00

376 lines
9.0 KiB
TypeScript
Raw 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.

/**
* 文件types.ts
* 作用:集中定义小红书模块使用的所有类型、接口、枚举与常量,保证模块间协作的类型安全。
*
* 内容结构:
* 1. 发布数据结构XiaohongshuPost 等)
* 2. 上传/发布响应与状态枚举
* 3. 错误码、事件类型、配置常量XIAOHONGSHU_CONSTANTS
* 4. 图片、适配、系统级通用类型
*
* 设计原则:
* - 不依赖具体实现细节api / adapter仅暴露抽象描述
* - 常量集中,方便后续接入真实平台参数调整
* - 可扩展:若后续接入更多平台,可抽象出 PlatformXxx 基础层
*
* 扩展建议:
* - 引入严格的 Branded Type例如 TitleLength / TagString提升约束
* - 增加对服务端返回结构的精准建模(若接入正式 API
*/
/**
* 小红书功能相关类型定义
*
* 说明:
* 本文件定义了小红书功能所需的所有接口、类型和常量,
* 为整个小红书模块提供类型安全保障。
*/
// ================== 基础数据类型 ==================
/**
* 小红书发布内容结构
*/
export interface XiaohongshuPost {
/** 文章标题 */
title: string;
/** 文章正文内容 */
content: string;
/** 图片列表上传后返回的图片ID或URL */
images: string[];
/** 标签列表(可选) */
tags?: string[];
/** 封面图片(可选) */
cover?: string;
}
/**
* 小红书API响应结果
*/
export interface XiaohongshuResponse {
/** 是否成功 */
success: boolean;
/** 响应消息 */
message: string;
/** 发布内容的ID成功时返回 */
postId?: string;
/** 错误代码(失败时返回) */
errorCode?: string;
/** 详细错误信息(失败时返回) */
errorDetails?: string;
}
/**
* 发布状态枚举
*/
export enum PostStatus {
/** 发布中 */
PUBLISHING = 'publishing',
/** 发布成功 */
PUBLISHED = 'published',
/** 发布失败 */
FAILED = 'failed',
/** 等待审核 */
PENDING = 'pending',
/** 已删除 */
DELETED = 'deleted'
}
/**
* 图片处理结果
*/
export interface ProcessedImage {
/** 原始文件名 */
originalName: string;
/** 处理后的Blob数据 */
blob: Blob;
/** 处理后的尺寸信息 */
dimensions: {
width: number;
height: number;
};
/** 文件大小(字节) */
size: number;
}
/**
* 小红书配置选项
*/
export interface XiaohongshuSettings {
/** 是否启用小红书功能 */
enabled: boolean;
/** 用户名(可选,用于自动登录) */
username?: string;
/** 密码(加密存储,可选) */
password?: string;
/** 默认标签 */
defaultTags: string[];
/** 图片质量设置 (1-100) */
imageQuality: number;
/** 批量发布间隔时间(毫秒) */
publishDelay: number;
/** 是否启用图片优化 */
enableImageOptimization: boolean;
/** 是否启用调试模式 */
debugMode: boolean;
}
// ================== 接口定义 ==================
/**
* 小红书API接口
*
* 基于模拟网页操作实现,提供小红书平台的核心功能
*/
export interface XiaohongshuAPI {
/**
* 检查登录状态
* @returns 是否已登录
*/
checkLoginStatus(): Promise<boolean>;
/**
* 使用用户名密码登录
* @param username 用户名
* @param password 密码
* @returns 登录是否成功
*/
loginWithCredentials(username: string, password: string): Promise<boolean>;
/**
* 发布内容到小红书
* @param content 发布内容
* @returns 发布结果
*/
createPost(content: XiaohongshuPost): Promise<XiaohongshuResponse>;
/**
* 上传图片
* @param imageBlob 图片数据
* @returns 上传后的图片ID或URL
*/
uploadImage(imageBlob: Blob): Promise<string>;
/**
* 批量上传图片
* @param imageBlobs 图片数据数组
* @returns 上传后的图片ID或URL数组
*/
uploadImages(imageBlobs: Blob[]): Promise<string[]>;
/**
* 查询发布状态
* @param postId 发布内容ID
* @returns 发布状态
*/
getPostStatus(postId: string): Promise<PostStatus>;
/**
* 注销登录
* @returns 是否成功注销
*/
logout(): Promise<boolean>;
}
/**
* 小红书内容适配器接口
*
* 负责将Obsidian内容转换为小红书格式
*/
export interface XiaohongshuAdapter {
/**
* 转换标题
* @param title 原标题
* @returns 适配后的标题
*/
adaptTitle(title: string): string;
/**
* 转换正文内容
* @param content Markdown内容
* @returns 适配后的内容
*/
adaptContent(content: string): string;
/**
* 提取并转换标签
* @param content Markdown内容
* @returns 标签数组
*/
extractTags(content: string): string[];
/**
* 处理图片引用
* @param content 内容
* @param imageUrls 图片URL映射
* @returns 处理后的内容
*/
processImages(content: string, imageUrls: Map<string, string>): string;
/**
* 验证内容是否符合小红书要求
* @param post 发布内容
* @returns 验证结果和错误信息
*/
validatePost(post: XiaohongshuPost): { valid: boolean; errors: string[] };
}
/**
* 小红书渲染器接口
*
* 提供预览和发布功能
*/
export interface XiaohongshuRender {
/**
* 渲染预览内容
* @param markdownContent Markdown内容
* @param container 预览容器
* @returns Promise
*/
renderPreview(markdownContent: string, container: HTMLElement): Promise<void>;
/**
* 获取预览内容的HTML
* @returns HTML内容
*/
getPreviewHTML(): string;
/**
* 发布到小红书
* @returns 发布结果
*/
publishToXiaohongshu(): Promise<XiaohongshuResponse>;
/**
* 上传图片到小红书
* @returns 上传结果
*/
uploadImages(): Promise<string[]>;
/**
* 复制内容到剪贴板
* @returns Promise
*/
copyToClipboard(): Promise<void>;
/**
* 获取当前适配的内容
* @returns 小红书格式的内容
*/
getAdaptedContent(): XiaohongshuPost;
}
/**
* 图片处理器接口
*/
export interface XiaohongshuImageProcessor {
/**
* 转换图片为PNG格式
* @param imageBlob 原图片数据
* @returns PNG格式的图片数据
*/
convertToPNG(imageBlob: Blob): Promise<Blob>;
/**
* 批量处理图片
* @param images 图片信息数组
* @returns 处理后的图片数组
*/
processImages(images: { name: string; blob: Blob }[]): Promise<ProcessedImage[]>;
/**
* 优化图片质量和尺寸
* @param imageBlob 图片数据
* @param quality 质量设置(1-100)
* @param maxWidth 最大宽度
* @param maxHeight 最大高度
* @returns 优化后的图片
*/
optimizeImage(
imageBlob: Blob,
quality: number,
maxWidth?: number,
maxHeight?: number
): Promise<Blob>;
}
// ================== 常量定义 ==================
/**
* 小红书相关常量
*/
export const XIAOHONGSHU_CONSTANTS = {
/** 小红书官网URL */
BASE_URL: 'https://www.xiaohongshu.com',
/** 发布页面URL */
PUBLISH_URL: 'https://creator.xiaohongshu.com',
/** 默认配置 */
DEFAULT_SETTINGS: {
enabled: false,
defaultTags: [],
imageQuality: 85,
publishDelay: 2000,
enableImageOptimization: true,
debugMode: false
} as XiaohongshuSettings,
/** 图片限制 */
IMAGE_LIMITS: {
MAX_COUNT: 9, // 最多9张图片
MAX_SIZE: 10 * 1024 * 1024, // 最大10MB
SUPPORTED_FORMATS: ['jpg', 'jpeg', 'png', 'gif', 'webp'],
RECOMMENDED_SIZE: {
width: 1080,
height: 1440
}
},
/** 内容限制 */
CONTENT_LIMITS: {
MAX_TITLE_LENGTH: 20, // 标题最多20字
MAX_CONTENT_LENGTH: 1000, // 内容最多1000字
MAX_TAGS: 5 // 最多5个标签
}
} as const;
/**
* 错误代码常量
*/
export enum XiaohongshuErrorCode {
/** 网络错误 */
NETWORK_ERROR = 'NETWORK_ERROR',
/** 认证失败 */
AUTH_FAILED = 'AUTH_FAILED',
/** 内容格式错误 */
CONTENT_FORMAT_ERROR = 'CONTENT_FORMAT_ERROR',
/** 图片上传失败 */
IMAGE_UPLOAD_FAILED = 'IMAGE_UPLOAD_FAILED',
/** 发布失败 */
PUBLISH_FAILED = 'PUBLISH_FAILED',
/** 未知错误 */
UNKNOWN_ERROR = 'UNKNOWN_ERROR'
}
/**
* 事件类型定义
*/
export interface XiaohongshuEvent {
/** 事件类型 */
type: 'login' | 'upload' | 'publish' | 'error';
/** 事件数据 */
data: any;
/** 时间戳 */
timestamp: number;
}
/**
* 发布进度回调函数类型
*/
export type PublishProgressCallback = (progress: {
current: number;
total: number;
status: string;
file?: string;
}) => void;