diff --git a/src/plugins/Mys/types/Post.d.ts b/src/plugins/Mys/types/Post.d.ts index 7c9fa200..f452ae4b 100644 --- a/src/plugins/Mys/types/Post.d.ts +++ b/src/plugins/Mys/types/Post.d.ts @@ -1,12 +1,12 @@ /** * @file plugins/Mys/types/post.d.ts * @description Mys 插件帖子类型定义文件 - * @since Beta v0.3.3 + * @since Beta v0.3.4 */ /** * @description Mys 插件帖子类型 - * @since Alpha v0.2.1 + * @since Beta v0.3.4 * @namespace TGApp.Plugins.Mys.Post * @memberof TGApp.Plugins.Mys */ @@ -103,7 +103,7 @@ declare namespace TGApp.Plugins.Mys.Post { * @property {string} reply_time 最后回复时间 // "2023-03-05 20:26:54" * @property {number} is_deleted 是否删除 * @property {boolean} is_interactive 是否互动 - * @property {string} structured_content 结构化内容 // 反序列化后为 PostStructuredContent + * @property {string} structured_content 结构化内容 // 反序列化后为 TGApp.Plugins.Mys.SctPost.Common[] * @property {string[]} structured_content_rows 结构化内容原始数据 * @property {number} review_id 审核ID * @property {boolean} is_profit 是否盈利 @@ -298,172 +298,4 @@ declare namespace TGApp.Plugins.Mys.Post { describe: string; images?: string[]; } - - /** - * @description 帖子结构化内容 - * @since Beta v0.3.3 - * @todo 重构 - * @interface StructuredContent - * @property {string|object} insert 插入内容 - * @property {string} insert.image 图片 URL - * @property {StructuredVod} insert.vod 视频信息 - * @property {string} insert.video 外部视频 URL - * @property {string} insert.backup_text 折叠文本 - * @property {object} insert.lottery 抽奖,当 backup_text 为 [抽奖] - * @property {string} insert.lottery.id 抽奖 ID - * @property {string} insert.lottery.toast 抽奖提示 - * @property {object} insert.fold 折叠内容 - * @property {string} insert.fold.title 折叠标题,反序列化后为 PostStructuredContent[] - * @property {string} insert.fold.content 折叠文本,反序列化后为 PostStructuredContent[] - * @property {StructuredLinkCard} insert.link_card 链接卡片 - * @property {string} insert.divider 分割线 - * @property {object} insert.mention 提及 - * @property {string} insert.mention.uid 用户 ID - * @property {string} insert.mention.nickname 用户昵称 - * @property {StructuredVillaCard} insert.villa_card 大别野卡片 - * @property {object} attributes 属性 - * @property {number} attributes.height 高度 - * @property {number} attributes.width 宽度 - * @property {number} attributes.size 大小 - * @property {string} attributes.ext 扩展名 - * @property {boolean} attributes.bold 是否加粗 - * @property {string} attributes.color 颜色 - * @property {string} attributes.link 链接 - * @return StructuredContent - */ - interface StructuredContent { - insert: - | { - image?: string; - video?: string; - vod?: StructuredVod; - backup_text?: string; - lottery?: { - id: string; - toast: string; - }; - fold?: { - title: string; - content: string; - }; - link_card?: StructuredLinkCard; - divider?: string; - mention?: { - uid: string; - nickname: string; - }; - villa_card?: StructuredVillaCard; - } - | string; - attributes?: { - height?: number; - width?: number; - size?: number; - ext?: string; - bold?: boolean; - color?: string; - link?: string; - }; - } - - /** - * @description 帖子结构化内容-视频 - * @since Alpha v0.2.2 - * @interface StructuredVod - * @property {number} id 视频 ID - * @property {number} duration 时长 - * @property {string} cover 封面图 URL - * @property {object[]} resolutions 分辨率 - * @property {string} resolutions.url URL - * @property {string} resolutions.definition 清晰度 - * @property {number} resolutions.height 高度 - * @property {number} resolutions.width 宽度 - * @property {number} resolutions.bitrate 比特率 - * @property {number} resolutions.size 大小 - * @property {string} resolutions.format 格式 - * @property {string} resolutions.label 标签 - * @property {number} view_num 浏览数 - * @property {number} transcode_status 转码状态 - * @property {number} review_status 审核状态 - * @return StructuredVod - */ - interface StructuredVod { - id: number; - duration: number; - cover: string; - resolutions: Array<{ - url: string; - definition: string; - height: number; - width: number; - bitrate: number; - size: number; - format: string; - label: string; - }>; - view_num: number; - transcode_status: number; - review_status: number; - } - - /** - * @description 帖子结构化内容-链接卡片 - * @since Alpha v0.2.1 - * @interface StructuredLinkCard - * @property {number} link_type 链接类型 // 1: 帖子,2:商品 - * @property {string} origin_url 原始链接 - * @property {string} landing_url 落地页链接 - * @property {string} cover 封面图 URL - * @property {string} title 标题 - * @property {string} card_id 卡片 ID - * @property {number} card_status 卡片状态 - * @property {string} market_price 市场价 - * @property {string} price 价格 - * @property {string} button_text 按钮文本 - * @property {number} landing_url_type 落地链接类型 - * @return StructuredLinkCard - */ - interface StructuredLinkCard { - link_type: number; - origin_url: string; - landing_url: string; - cover: string; - title: string; - card_id: string; - card_status: number; - market_price: string; - price: string; - button_text: string; - landing_url_type: number; - } - - /** - * @description 帖子结构化内容-大别野卡片 - * @since Beta v0.3.3 - * @interface StructuredVillaCard - * @property {string} villa_id 大别野房间 ID - * @property {string} villa_name 大别野房间 名称 - * @property {string} villa_avatar_url 大别野房间 头像图 URL - * @property {string} villa_cover 大别野房间 封面图 URL - * @property {string} owner_uid 大别野房间 房主 UID - * @property {string} owner_nickname 大别野房间 房主昵称 - * @property {string} owner_avatar_url 大别野房间 房主头像图 URL - * @property {string} villa_introduce 大别野房间 介绍 - * @property {string[]} tag_list 大别野房间 标签列表 - * @property {string} villa_member_num 大别野房间 成员数 - * @property {boolean} is_available 大别野房间 是否可用 - * @return StructuredVillaCard - */ - interface StructuredVillaCard { - villa_id: string; - villa_name: string; - villa_avatar_url: string; - villa_cover: string; - owner_uid: string; - owner_nickname: string; - owner_avatar_url: string; - villa_introduce: string; - tag_list: string[]; - villa_member_num: string; - } } diff --git a/src/plugins/Mys/types/SctPost.d.ts b/src/plugins/Mys/types/SctPost.d.ts new file mode 100644 index 00000000..b86a9a26 --- /dev/null +++ b/src/plugins/Mys/types/SctPost.d.ts @@ -0,0 +1,319 @@ +/** + * @file plugins/Mys/types/SctPost.d.ts + * @description Mys 插件 结构化帖子类型声明文件 + * @todo 完善类型 + * @since Beta v0.3.4 + */ + +/** + * @description 结构化帖子类型命名空间 + * @since Beta v0.3.4 + * @namespace TGApp.Plugins.Mys.SctPost + * @memberof TGApp.Plugins.Mys + */ +declare namespace TGApp.Plugins.Mys.SctPost { + /** + * @description 帖子结构化数据-基础类型 + * @since Beta v0.3.4 + * @interface Base + * @property {unknown} insert - 帖子内容 + * @property {unknown} attributes - 帖子属性 + * @return Base + */ + interface Base { + insert: never; + attributes: never; + } + + /** + * @description 帖子结构化数据-联合类型 + * @since Beta v0.3.4 + * @interface Common + * @return Common + */ + type Common = + | Backup + | Divider + | Image + | Link + | LinkCard + | Mention + | Text + | Video + | VillaCard + | Vod; + + /** + * @description 帖子结构化数据-其他类型 + * @since Beta v0.3.4 + * @property {string} describe - 描述 + * @property {string[]} imgs - 图片链接 + * @return Other + */ + interface Other { + describe: string; + imgs: string[]; + [key: string]: unknown; + } + + /** + * @description 帖子结构化数据-折叠文本 + * @since Beta v0.3.4 + * @interface Backup + * @extends Base + * @property {string} insert.backup_text - 折叠文本 + * @property {string} insert.fold.title - 折叠标题 + * @property {string} insert.fold.content - 折叠内容 + * @return Backup + */ + interface Backup extends Base { + insert: { + backup_text: string; + fold: { + title: string; + content: string; + }; + }; + } + + /** + * @description 帖子结构化数据-分割线 + * @since Beta v0.3.4 + * @interface Divider + * @extends Base + * @property {string} insert.divider - 分割线 + * @return Divider + */ + interface Divider extends Base { + insert: { + divider: string; + }; + } + + /** + * @description 帖子结构化数据-图片类型 + * @since Beta v0.3.4 + * @interface Image + * @extends Base + * @property {string} insert.image - 图片链接 + * @property {number} attributes.width - 图片宽度 + * @property {number} attributes.height - 图片高度 + * @property {number} [attributes.size] - 图片大小 + * @property {string} [attributes.ext] - 图片格式 + * @return Image + */ + interface Image extends Base { + insert: { + image: string; + }; + attributes?: { + width: number; + height: number; + size: number | undefined; + ext: string | undefined; + }; + } + + /** + * @description 帖子结构化数据-文本链接 + * @since Beta v0.3.4 + * @interface Link + * @extends Base + * @property {string} insert - 帖子内容 + * @property {string} attributes.link - 链接 + * @return Link + */ + interface Link extends Base { + insert: string; + attributes: { + link: string; + }; + } + + /** + * @description 帖子结构化数据-链接卡片 + * @since Beta v0.3.4 + * @interface LinkCard + * @extends Base + * @property {number} insert.link_card.link_type - 链接类型 + * @property {string} insert.link_card.origin_url - 原始链接 + * @property {string} insert.link_card.landing_url - 落地页链接 + * @property {string} insert.link_card.cover - 封面 + * @property {string} insert.link_card.title - 标题 + * @property {string} insert.link_card.card_id - 卡片ID + * @property {number} insert.link_card.card_status - 卡片状态 + * @property {string} insert.link_card.market_price - 市场价 + * @property {string} insert.link_card.price - 价格 + * @property {string} insert.link_card.button_text - 按钮文本 + * @property {number} insert.link_card.landing_url_type - 落地页类型 + * @return LinkCard + */ + interface LinkCard extends Base { + insert: { + link_card: { + link_type: number; + origin_url: string; + landing_url: string; + cover: string; + title: string; + card_id: string; + card_status: number; + market_price: string; + price?: string; + button_text?: string; + landing_url_type: number; + }; + }; + } + + /** + * @description 帖子结构化数据-抽奖 + * @since Beta v0.3.4 + * @interface Lottery + * @extends Base + * @property {"[抽奖]"} insert.backup_text - 抽奖文本 + * @property {string} insert.lottery.id - 抽奖ID + * @property {string} insert.lottery.toast - 抽奖提示 + * @return Lottery + */ + interface Lottery extends Base { + insert: { + backup_text: "[抽奖]"; + lottery: { + id: string; + toast: string; + }; + }; + } + + /** + * @description 帖子结构化数据-提及用户 + * @since Beta v0.3.4 + * @interface Mention + * @extends Base + * @property {string} insert.mention.uid - 用户ID + * @property {string} insert.mention.nickname - 用户昵称 + * @return Mention + */ + interface Mention extends Base { + insert: { + mention: { + uid: string; + nickname: string; + }; + }; + } + + /** + * @description 帖子结构化数据-文本类型 + * @since Beta v0.3.4 + * @interface Text + * @extends Base + * @property {string} insert - 帖子内容 + * @property {boolean} [attributes.bold] - 是否加粗 + * @property {string} [attributes.color] - 文本颜色 + * @property {string} [attributes.link] - 链接 + * @return Text + */ + interface Text extends Base { + insert: string; + attributes?: { + bold?: boolean; + color?: string; + align?: string; + }; + } + + /** + * @description 帖子结构化数据-视频类型-站外视频 + * @since Beta v0.3.4 + * @interface Video + * @extends Base + * @property {string} insert.video - 视频链接 + * @return Video + */ + interface Video extends Base { + insert: { + video: string; + }; + } + + /** + * @description 帖子结构化数据-大别野卡片 + * @since Beta v0.3.4 + * @interface VillaCard + * @extends Base + * @property {string} insert.villa_card.villa_id - 别墅ID + * @property {string} insert.villa_card.villa_name - 别墅名称 + * @property {string} insert.villa_card.villa_avatar_url - 别墅头像 + * @property {string} insert.villa_card.villa_cover - 别墅封面 + * @property {string} insert.villa_card.owner_uid - 别墅主人ID + * @property {string} insert.villa_card.owner_nickname - 别墅主人昵称 + * @property {string} insert.villa_card.owner_avatar_url - 别墅主人头像 + * @property {string} insert.villa_card.villa_introduce - 别墅介绍 + * @property {string[]} insert.villa_card.tag_list - 别墅标签 + * @property {string} insert.villa_card.villa_member_num - 别墅成员数量 + * @return VillaCard + */ + interface VillaCard extends Base { + insert: { + villa_card: { + villa_id: string; + villa_name: string; + villa_avatar_url: string; + villa_cover: string; + owner_uid: string; + owner_nickname: string; + owner_avatar_url: string; + villa_introduce: string; + tag_list: string[]; + villa_member_num: string; + }; + }; + } + + /** + * @description 帖子结构化数据-视频类型-站内视频 + * @since Beta v0.3.4 + * @interface Vod + * @extends Base + * @property {number} insert.vod.id - 视频ID + * @property {number} insert.vod.duration - 视频时长 + * @property {string} insert.vod.cover - 视频封面 + * @property {Array} insert.vod.resolutions - 视频分辨率 + * @property {string} insert.vod.resolutions.url - 视频链接 + * @property {string} insert.vod.resolutions.definition - 视频清晰度 + * @property {number} insert.vod.resolutions.height - 视频高度 + * @property {number} insert.vod.resolutions.width - 视频宽度 + * @property {number} insert.vod.resolutions.bitrate - 视频码率 + * @property {number} insert.vod.resolutions.size - 视频大小 + * @property {string} insert.vod.resolutions.format - 视频格式 + * @property {string} insert.vod.resolutions.label - 视频标签 + * @property {number} insert.vod.view_num - 观看次数 + * @property {number} insert.vod.transcode_status - 转码状态 + * @property {number} insert.vod.review_status - 审核状态 + * @return Vod + */ + interface Vod extends Base { + insert: { + vod: { + id: number; + duration: number; + cover: string; + resolutions: Array<{ + url: string; + definition: string; + height: number; + width: number; + bitrate: number; + size: number; + format: string; + label: string; + }>; + view_num: number; + transcode_status: number; + review_status: number; + }; + }; + } +} diff --git a/src/plugins/Mys/utils/parsePost.ts b/src/plugins/Mys/utils/parsePost.ts index c46865df..bef8ecdf 100644 --- a/src/plugins/Mys/utils/parsePost.ts +++ b/src/plugins/Mys/utils/parsePost.ts @@ -1,15 +1,16 @@ /** * @file plugins Mys utils parsePost.ts * @description 用于解析Mys数据的工具 - * @since Beta v0.3.3 + * @since Beta v0.3.4 */ import * as colorConvert from "color-convert"; +import type { KEYWORD } from "color-convert/conversions"; import { score } from "wcag-color"; /** * @description 给定两个16进制颜色值,确认两者是否相近 - * @since Beta v0.3.0 + * @since Beta v0.3.4 * @param {string} colorBg 背景颜色 * @param {string} colorFg 前景颜色 * @returns {boolean} 是否相近 @@ -17,9 +18,9 @@ import { score } from "wcag-color"; function isColorSimilar(colorBg: string, colorFg: string): boolean { let hexBg, hexFg; if (colorBg.startsWith("#")) hexBg = colorBg; - else hexBg = colorConvert.keyword.hex(colorBg); + else hexBg = colorConvert.keyword.hex(colorBg); if (colorFg.startsWith("#")) hexFg = colorFg; - else hexFg = colorConvert.keyword.hex(colorFg); + else hexFg = colorConvert.keyword.hex(colorFg); const contrast = score(hexFg, hexBg); return contrast === "Fail"; } @@ -72,16 +73,16 @@ function getVodTime(duration: number): string { /** * @description 解析用户帖子,将其转换为 StructContent - * @since Alpha v0.1.2 + * @since Beta v0.3.4 * @see PostContent * @param {string} content 帖子内容 * @returns {string} 解析后的内容 */ function parseContent(content: string): string { - const data = JSON.parse(content); - const result: TGApp.Plugins.Mys.Post.StructuredContent[] = []; - // 遍历 data 属性,值 - Object.keys(data).forEach((key) => { + const data: TGApp.Plugins.Mys.SctPost.Other = JSON.parse(content); + const result: TGApp.Plugins.Mys.SctPost.Common[] = []; + const keys = Object.keys(data); + keys.forEach((key) => { switch (key) { case "describe": result.push({ @@ -89,19 +90,20 @@ function parseContent(content: string): string { }); break; case "imgs": - for (const image of data.imgs) { + data.imgs.forEach((item) => { result.push({ insert: { - image, + image: item, }, }); - } + }); break; default: - // 如果是其他属性,就直接插入 + console.warn(`[MysPostParser] Unknown key: ${key}`); result.push({ insert: JSON.stringify(data[key]), }); + break; } }); return JSON.stringify(result); @@ -126,7 +128,7 @@ function parsePost(post: TGApp.Plugins.Mys.Post.FullData): string { parserData = post.post.structured_content; } } - const jsonData: TGApp.Plugins.Mys.Post.StructuredContent[] = JSON.parse(parserData); + const jsonData: TGApp.Plugins.Mys.SctPost.Common[] = JSON.parse(parserData); const doc = document.createElement("div"); jsonData.forEach((item: any) => { const parsed = transferParser(item); @@ -138,42 +140,39 @@ function parsePost(post: TGApp.Plugins.Mys.Post.FullData): string { /** * @description 解析中转 * @since Beta v0.3.3 - * @param {TGApp.Plugins.Mys.Post.StructuredContent} data Mys数据 + * @param {TGApp.Plugins.Mys.SctPost.Common} data Mys数据 * @returns {HTMLDivElement | HTMLSpanElement} 解析后的中转 */ -function transferParser( - data: TGApp.Plugins.Mys.Post.StructuredContent, -): HTMLDivElement | HTMLSpanElement { +function transferParser(data: TGApp.Plugins.Mys.SctPost.Common): HTMLDivElement | HTMLSpanElement { if (typeof data.insert === "string") { - return parseText(data); - } else if (data.insert.image) { - return parseImage(data); - } else if (data.insert.vod != null) { - return parseVideo(data); - } else if (data.insert.video) { - return parseVideo(data); - } else if (data.insert.backup_text) { - return parseBackup(data); - } else if (data.insert.link_card != null) { - return parseLinkCard(data); - } else if (data.insert.divider) { - return parseDivider(data); - } else if (data.insert.mention != null) { - return parseMention(data); - } else if (data.insert.villa_card != null) { - return parseVillaCard(data); - } else { - return parseUnknown(data); + return parseText(data); + } else if ("image" in data.insert) { + return parseImage(data); + } else if ("vod" in data.insert) { + return parseVideo(data); + } else if ("video" in data.insert) { + return parseVideo(data); + } else if ("backup_text" in data.insert) { + return parseBackup(data); + } else if ("link_card" in data.insert) { + return parseLinkCard(data); + } else if ("divider" in data.insert) { + return parseDivider(data); + } else if ("mention" in data.insert) { + return parseMention(data); + } else if ("villa_card" in data.insert) { + return parseVillaCard(data); } + return parseUnknown(data); } /** * @description 解析未知数据 - * @since Beta v0.3.3 - * @param {TGApp.Plugins.Mys.Post.StructuredContent} data Mys数据 + * @since Beta v0.3.4 + * @param {TGApp.Plugins.Mys.SctPost.Base} data Mys数据 * @returns {HTMLDivElement} 解析后的未知数据 */ -function parseUnknown(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLDivElement { +function parseUnknown(data: TGApp.Plugins.Mys.SctPost.Base): HTMLDivElement { const div = document.createElement("div"); div.classList.add("mys-post-unknown"); const code = document.createElement("code"); @@ -186,63 +185,43 @@ function parseUnknown(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLDivEl /** * @description 解析文本 * @since Beta v0.3.0 - * @param {TGApp.Plugins.Mys.Post.StructuredContent} data Mys数据 + * @param {TGApp.Plugins.Mys.SctPost.Text |TGApp.Plugins.Mys.SctPost.Link} data Mys数据 * @returns {HTMLSpanElement} 解析后的文本 */ -function parseText(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLSpanElement { - // 检查数据 - if (typeof data.insert !== "string") { - throw new Error(`[ParseText] data.insert is not a string: ${JSON.stringify(data)}`); +function parseText( + data: TGApp.Plugins.Mys.SctPost.Text | TGApp.Plugins.Mys.SctPost.Link, +): HTMLSpanElement { + if (data.attributes && "link" in data.attributes) { + return LinkTextParser(data); } - // 创建文本 const text = document.createElement("span"); - // 设置文本属性 - if (data.attributes != null) { + if (data.attributes) { if (data.attributes.bold) text.style.fontWeight = "bold"; if (data.attributes.color) { let colorGet = data.attributes.color; - // 如果 colorGet 在 darkColorList 中,就设置为对应的颜色 if (isColorSimilar("#1E1E1E", colorGet)) { colorGet = "var(--app-page-content)"; } text.style.color = colorGet; } - if (data.attributes.link) { - return LinkTextParser(data); - } } if (data.insert.startsWith("_(") && data.insert.endsWith(")")) { - return emojiParser(data); + return emojiParser(data); } - // 添加 class text.classList.add("mys-post-span"); - // 设置 span 内容 text.innerText = data.insert; - // 返回文本 return text; } /** * @description 解析链接 - * @since Beta v0.3.0 - * @param {TGApp.Plugins.Mys.Post.StructuredContent} data Mys数据 + * @since Beta v0.3.4 + * @param {TGApp.Plugins.Mys.SctPost.Link} data Mys数据 * @returns {HTMLSpanElement} 解析后的链接 */ -function LinkTextParser(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLSpanElement { - // 检查数据 - if (typeof data.insert !== "string") { - throw new Error(`[LinkTextParser] data.insert is not a string: ${JSON.stringify(data)}`); - } - if (data.attributes == null) { - throw new Error("[LinkTextParser] data.attributes is not defined"); - } - if (!data.attributes.link) { - throw new Error("[LinkTextParser] data.attributes.link is not defined"); - } - // 创建图标 +function LinkTextParser(data: TGApp.Plugins.Mys.SctPost.Link): HTMLSpanElement { const icon = document.createElement("i"); icon.classList.add("mdi", "mdi-link-variant"); - // 创建链接 const link = document.createElement("a"); const linkUrl = data.attributes.link; link.classList.add("mys-post-link"); @@ -255,114 +234,72 @@ function LinkTextParser(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLSpa link.target = "view_window"; } link.innerText = data.insert; - // 插入图标作为链接前缀 link.prepend(icon); - // 返回链接 return link; } /** * @description 解析分割线 - * @since Beta v0.3.0 - * @param {TGApp.Plugins.Mys.Post.StructuredContent} data Mys数据 + * @since Beta v0.3.4 + * @param {TGApp.Plugins.Mys.SctPost.Divider} data Mys数据 * @returns {HTMLDivElement} 解析后的分割线 */ -function parseDivider(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLDivElement { - // 数据检查 - if (typeof data.insert === "string") { - throw new Error(`[ParseDivider] data.insert is a string: ${data.insert}`); - } - if (!data.insert.divider) { - throw new Error("[ParseDivider] data.insert.divider is not defined"); - } - // 创建分割线 +function parseDivider(data: TGApp.Plugins.Mys.SctPost.Divider): HTMLDivElement { const div = document.createElement("div"); div.classList.add("mys-post-divider"); - // 创建 img const img = document.createElement("img"); - if (data.insert.divider === "line_1") { - img.src = "/source/post/divider_line_1.webp"; - } else if (data.insert.divider === "line_2") { - img.src = "/source/post/divider_line_2.webp"; - } else if (data.insert.divider === "line_3") { - img.src = "/source/post/divider_line_3.webp"; - } else if (data.insert.divider === "line_4") { - img.src = "/source/post/divider_line_4.webp"; - } else { + const dividerList = ["line_1", "line_2", "line_3", "line_4"]; + if (!dividerList.includes(data.insert.divider)) { console.error("Unknown divider type", data); - return parseUnknown(data); + return parseUnknown(data); } - // 插入 img + img.src = `/source/post/divider_${data.insert.divider}.webp`; div.appendChild(img); - // 返回分割线 return div; } /** * @description 解析图片 - * @since Beta v0.3.0 - * @param {TGApp.Plugins.Mys.Post.StructuredContent} data Mys数据 + * @since Beta v0.3.4 + * @param {TGApp.Plugins.Mys.SctPost.Image} data Mys数据 * @returns {HTMLDivElement} 解析后的图片 */ -function parseImage(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLDivElement { - // 检查数据 - if (typeof data.insert === "string") { - throw new Error(`[ParseImage] data.insert is a string: ${data.insert}`); - } - if (!data.insert.image) { - throw new Error("[ParseImage] data.insert.image is not defined"); - } +function parseImage(data: TGApp.Plugins.Mys.SctPost.Image): HTMLDivElement { const div = document.createElement("div"); - // 创建图片 const img = document.createElement("img"); img.src = data.insert.image; - // 添加 class img.classList.add("mys-post-img"); - // 插入图片 div.appendChild(img); - // 添加 class div.classList.add("mys-post-div"); - // 返回 div return div; } /** * @description 解析视频 * @since Beta v0.3.3 - * @param {TGApp.Plugins.Mys.Post.StructuredContent} data Mys数据 + * @todo 分开解析 Vod 和 Video + * @param {TGApp.Plugins.Mys.SctPost.Vod|TGApp.Plugins.Mys.SctPost.Video} data Mys数据 * @returns {HTMLDivElement} 解析后的视频 */ -function parseVideo(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLDivElement { - // 检查数据 - if (typeof data.insert === "string") { - throw new Error(`[ParseVideo] data.insert is a string: ${data.insert}`); - } - if (data.insert.vod == null && !data.insert.video) { - throw new Error("[ParseVideo] data.insert.vod and data.insert.video is not defined"); - } - // 创建 div +function parseVideo( + data: TGApp.Plugins.Mys.SctPost.Vod | TGApp.Plugins.Mys.SctPost.Video, +): HTMLDivElement { const div = document.createElement("div"); div.classList.add("mys-post-div"); - if (data.insert.vod != null) { - // 创建视频 + if ("vod" in data.insert) { const video = document.createElement("video"); video.classList.add("mys-post-vod"); - // 获取 resolutions中size最大的视频 const resolution = data.insert.vod.resolutions.reduce((prev: any, curr: any) => { if (prev.size > curr.size) return prev; return curr; }); - video.poster = data.insert.vod.cover; // 设置封面 - video.controls = true; // 设置 controls - // 添加 source + video.poster = data.insert.vod.cover; + video.controls = true; const source = document.createElement("source"); source.src = resolution.url; source.type = resolution.format === ".mp4" ? "video/mp4" : "video/webm"; - // 插入 source video.appendChild(source); - // 插入 video div.appendChild(video); - // 创建视频封面图 const coverDiv = document.createElement("div"); const cover = document.createElement("img"); cover.classList.add("mys-post-vod-cover"); @@ -378,15 +315,12 @@ function parseVideo(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLDivElem coverDiv.appendChild(playTime); coverDiv.classList.add("mys-post-vod-cover-div"); div.appendChild(coverDiv); - } else if (data.insert.video) { - // 创建 iframe + } else { const video = document.createElement("iframe"); video.classList.add("mys-post-iframe"); - // 设置 iframe 属性 video.src = data.insert.video; video.allowFullscreen = true; video.sandbox.add("allow-top-navigation", "allow-same-origin", "allow-forms", "allow-scripts"); - // 插入 video div.appendChild(video); } return div; @@ -394,40 +328,27 @@ function parseVideo(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLDivElem /** * @description 解析折叠内容 - * @since Beta v0.3.0 - * @param {TGApp.Plugins.Mys.Post.StructuredContent} data Mys数据 + * @since Beta v0.3.4 + * @param {TGApp.Plugins.Mys.SctPost.Backup} data Mys数据 * @returns {HTMLDivElement} 解析后的折叠内容 */ -function parseBackup(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLDivElement { - // 检查数据 - if (typeof data.insert === "string") { - throw new Error(`[ParseBackup] data.insert is a string: ${data.insert}`); +function parseBackup( + data: TGApp.Plugins.Mys.SctPost.Backup | TGApp.Plugins.Mys.SctPost.Lottery, +): HTMLDivElement { + if ("lottery" in data.insert) { + return LotteryParser(data); } - if (data.insert.backup_text === "[抽奖]") { - return LotteryParser(data); - } - if (data.insert.fold == null) { - throw new Error("[ParseBackup] data.insert.fold is not defined"); - } - // 转换 - const titleJson: TGApp.Plugins.Mys.Post.StructuredContent[] = JSON.parse(data.insert.fold.title); - const contentJson: TGApp.Plugins.Mys.Post.StructuredContent[] = JSON.parse( - data.insert.fold.content, - ); - // 创建 div + const titleJson: TGApp.Plugins.Mys.SctPost.Base[] = JSON.parse(data.insert.fold.title); + const contentJson: TGApp.Plugins.Mys.SctPost.Base[] = JSON.parse(data.insert.fold.content); const div = document.createElement("div"); div.classList.add("mys-post-div"); - // 创建折叠内容 const details = document.createElement("details"); details.classList.add("mys-post-details"); - // 创建标题 const title = document.createElement("summary"); - // 解析标题 titleJson.forEach((item) => { const parsed = transferParser(item); title.appendChild(parsed); }); - // 创建内容 const content = document.createElement("div"); contentJson.forEach((item) => { const parsed = transferParser(item); @@ -436,82 +357,47 @@ function parseBackup(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLDivEle details.appendChild(title); details.appendChild(content); div.appendChild(details); - // 返回 div return div; } /** * @description 解析抽奖 - * @since Beta v0.3.0 - * @param {TGApp.Plugins.Mys.Post.StructuredContent} data Mys数据 + * @since Beta v0.3.4 + * @param {TGApp.Plugins.Mys.SctPost.Lottery} data Mys数据 * @returns {HTMLDivElement} 解析后的抽奖 */ -function LotteryParser(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLDivElement { - // 检查数据 - if (typeof data.insert === "string") { - throw new Error(`[LotteryParser] data.insert is a string: ${data.insert}`); - } - if (!data.insert.backup_text) { - throw new Error("[LotteryParser] data.insert.backup_text is not defined"); - } - if (data.insert.backup_text !== "[抽奖]") { - throw new Error("[LotteryParser] data.insert.backup_text is not [抽奖]"); - } - if (data.insert.lottery == null) { - throw new Error("[LotteryParser] data.insert.lottery is not defined"); - } - // 创建 div +function LotteryParser(data: TGApp.Plugins.Mys.SctPost.Lottery): HTMLDivElement { const div = document.createElement("div"); - // 创建图标 const icon = document.createElement("i"); icon.classList.add("mdi", "mdi-gift"); - // 创建标题 const title = document.createElement("a"); title.classList.add("mys-post-link"); title.href = `/lottery/${data.insert.lottery.id}`; title.innerText = data.insert.lottery.toast; - // 插入图标 title.prepend(icon); - // 插入标题 div.appendChild(title); - // 返回 div return div; } /** * @description 解析链接卡片 - * @since Beta v0.3.0 - * @param {TGApp.Plugins.Mys.Post.StructuredContent} data Mys数据 + * @since Beta v0.3.4 + * @param {TGApp.Plugins.Mys.SctPost.LinkCard} data Mys数据 * @returns {HTMLDivElement} 解析后的链接卡片 */ -function parseLinkCard(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLDivElement { - // 检查数据 - if (typeof data.insert === "string") { - throw new Error(`[ParseLinkCard] data.insert is a string: ${data.insert}`); - } - if (data.insert.link_card == null) { - throw new Error("[ParseLinkCard] data.insert.link_card is not defined"); - } - // 创建 div +function parseLinkCard(data: TGApp.Plugins.Mys.SctPost.LinkCard): HTMLDivElement { const div = document.createElement("div"); - // 创建 cover const cover = document.createElement("div"); cover.classList.add("mys-post-link-card-cover"); - // 创建 img const img = document.createElement("img"); img.src = data.insert.link_card.cover; - // 插入 img cover.appendChild(img); - // 插入 cover div.appendChild(cover); - // 创建 content const content = document.createElement("div"); content.classList.add("mys-post-link-card-content"); - // 创建标题 const title = document.createElement("div"); title.classList.add("mys-post-link-card-title"); title.innerHTML = data.insert.link_card.title; - // 插入 title content.appendChild(title); if (data.insert.link_card.price) { const price = document.createElement("div"); @@ -519,10 +405,9 @@ function parseLinkCard(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLDivE price.innerHTML = data.insert.link_card.price; content.appendChild(price); } - // 创建 button const button = document.createElement("a"); button.classList.add("mys-post-link-card-btn"); - button.innerHTML = (data.insert.link_card.button_text || "详情") + " >"; + button.innerHTML = (data.insert.link_card.button_text ?? "详情") + " >"; const linkUrl = data.insert.link_card.origin_url; if (isMysPost(linkUrl)) { const postId = getPostId(linkUrl); @@ -532,54 +417,37 @@ function parseLinkCard(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLDivE button.href = linkUrl; button.target = "view_window"; } - // 插入 button content.appendChild(button); - // 插入 content div.appendChild(content); - // 添加 class div.classList.add("mys-post-link-card"); return div; } /** * @description 解析 Mention - * @since Beta v0.3.0 - * @param {TGApp.Plugins.Mys.Post.StructuredContent} data Mys数据 + * @since Beta v0.3.4 + * @param {TGApp.Plugins.Mys.SctPost.Mention} data Mys数据 * @returns {HTMLAnchorElement} 解析后的 Mention */ -function parseMention(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLAnchorElement { - // 检查数据 - if (typeof data.insert === "string") { - throw new Error(`[ParseMention] data.insert is a string: ${data.insert}`); - } - if (data.insert.mention == null) { - throw new Error("[ParseMention] data.insert.mention is not defined"); - } - // 创建图标 +function parseMention(data: TGApp.Plugins.Mys.SctPost.Mention): HTMLAnchorElement { const icon = document.createElement("i"); icon.classList.add("mdi", "mdi-account-circle-outline"); - // 创建链接 const link = document.createElement("a"); link.classList.add("mys-post-link"); link.href = `https://www.miyoushe.com/ys/accountCenter/postList?id=${data.insert.mention.uid}`; link.target = "_blank"; link.innerText = data.insert.mention.nickname; - // 插入图标 link.prepend(icon); return link; } /** * @description 解析 Emoji - * @since Beta v0.3.2 - * @param {TGApp.Plugins.Mys.Post.StructuredContent} data Mys数据 + * @since Beta v0.3.4 + * @param {TGApp.Plugins.Mys.SctPost.Text} data Mys数据 * @returns {HTMLSpanElement} 解析后的 Emoji */ -function emojiParser(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLImageElement { - // 检查数据 - if (typeof data.insert !== "string") { - throw new Error(`[EmojiParser] data.insert is not a string: ${JSON.stringify(data)}`); - } +function emojiParser(data: TGApp.Plugins.Mys.SctPost.Text): HTMLImageElement { const emojis = localStorage.getItem("emojis"); if (!emojis) { throw new Error("[EmojiParser] emojis is not defined"); @@ -590,29 +458,21 @@ function emojiParser(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLImageE if (!emoji) { throw new Error(`[EmojiParser] emoji is not defined: ${emojiName}`); } - // 创建图片 const img = document.createElement("img"); img.classList.add("mys-post-emoji"); img.src = emoji; img.alt = emojiName; img.title = emojiName; - // 获取图片地址 return img; } /** - * @description 解析大别野房间卡片 - * @since Beta v0.3.3 - * @param {TGApp.Plugins.Mys.Post.StructuredContent} data Mys数据 - * @returns {HTMLDivElement} 解析后的大别野房间卡片 + * @description 解析大别野房间的卡片 + * @since Beta v0.3.4 + * @param {TGApp.Plugins.Mys.SctPost.VillaCard} data Mys数据 + * @returns {HTMLDivElement} 解析后的大别野房间的卡片 */ -function parseVillaCard(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLDivElement { - if (typeof data.insert === "string") { - throw new Error(`[parseVillaCard] data.insert is a string: ${data.insert}`); - } - if (data.insert.villa_card == null) { - throw new Error("[parseVillaCard] data.insert.villa_card is not defined"); - } +function parseVillaCard(data: TGApp.Plugins.Mys.SctPost.VillaCard): HTMLDivElement { const div = document.createElement("div"); div.classList.add("mys-post-div"); const villaCard = document.createElement("div");