fix(parser): 完善内容解析

This commit is contained in:
BTMuli
2023-04-01 15:32:39 +08:00
parent e2aee5185d
commit 3cc71a8921
4 changed files with 139 additions and 31 deletions

View File

@@ -53,6 +53,14 @@
height: 450px;
}
.mys-post-iframe {
width: 800px;
height: 450px;
overflow: hidden;
border: 0;
border-radius: 10px;
}
.mys-post-link-card {
width: 800px;
height: 200px;
@@ -62,6 +70,17 @@
background: #faf7e8;
}
.mys-post-unknown {
width: 800px;
background: #5b738f;
color: #faf7e8;
font-family: Consolas, monospace;
border-radius: 10px;
padding: 10px;
margin: 10px auto;
border: 2px solid #485466;
}
.mys-post-link-card-cover {
width: auto;
height: 180px;
@@ -69,6 +88,7 @@
}
.mys-post-link-card-cover img {
max-width: 320px;
width: auto;
height: 180px;
border-radius: 10px;

View File

@@ -2,7 +2,7 @@
* @file plugins Mys interface post.ts
* @description Mys 插件帖子接口
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha
* @since Alpha v0.1.1
*/
import { MysResponse } from "./base";
@@ -226,6 +226,20 @@ export interface PostStat {
forward_num: number;
}
/**
* @description 帖子内容-结构化
* @description 当用户发帖时,解析内容用这个,为 post.content 的反序列化
* @since Alpha v0.1.1
* @interface PostContent
* @property {string} describe 描述
* @property {string[]} imgs 图片 URL
* @return {PostContent}
*/
export interface PostContent {
describe: string;
imgs?: string[];
}
/**
* @description 帖子结构化内容
* @since Alpha v0.1.1
@@ -233,6 +247,7 @@ export interface PostStat {
* @property {string|object} insert 插入内容
* @property {string} insert.image 图片 URL
* @property {PostStructuredContentVod} insert.vod 视频信息
* @property {string} insert.video 外部视频 URL
* @property {string} insert.backup_text 折叠文本
* @property {object} insert.lottery 抽奖,当 backup_text 为 [抽奖]
* @property {string} insert.lottery.id 抽奖 ID
@@ -256,6 +271,7 @@ export interface PostStructuredContent {
insert:
| {
image?: string;
video?: string;
vod?: PostStructuredContentVod;
backup_text?: string;
lottery?: {

View File

@@ -4,7 +4,7 @@
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha v0.1.1
*/
import { PostStructuredContent } from "../interface/post";
import { PostContent, PostData, PostStructuredContent } from "../interface/post";
/**
* @description 检测链接是否是米游社帖子
@@ -19,16 +19,60 @@ export function IsMysPost(url: string): boolean {
);
}
/**
* @description 解析用户帖子,将其转换为 PostStructContent
* @since Alpha v0.1.1
* @see PostContent
* @param {string} content 帖子内容
* @returns {string} 解析后的内容
*/
export function contentParser(content: string): string {
const data = JSON.parse(content);
const result: PostStructuredContent[] = [];
// 遍历 data 属性,值
Object.keys(data).forEach(key => {
switch (key) {
case "describe":
result.push({
insert: data.describe,
});
break;
case "imgs":
for (const image of data.imgs) {
result.push({
insert: {
image: image,
},
});
}
break;
default:
// 如果是其他属性,就直接插入
result.push({
insert: JSON.stringify(data[key]),
});
}
});
return JSON.stringify(result);
}
/**
* @description 解析Mys数据
* @since Alpha v0.1.1
* @param {string} data Mys数据
* @param {PostData} post Mys数据
* @description 为了安全考虑,不会解析所有的属性,只会解析几个常用的属性
* @returns {string} 解析后的HTML可作为 v-html 使用
*/
export function PostParser(data: string): string {
export function PostParser(post: PostData): string {
const postContent = post.post.content;
let parserData;
if (postContent.startsWith("<")) {
parserData = post.post.structured_content;
} else {
parserData = contentParser(postContent);
}
// Json 化
let jsonData: PostStructuredContent[] = JSON.parse(data);
let jsonData: PostStructuredContent[] = JSON.parse(parserData);
// 创建 div
const doc = document.createElement("div");
// 遍历 Json 数据
@@ -54,6 +98,8 @@ function ParserTransfer(data: PostStructuredContent): HTMLDivElement | HTMLSpanE
return ImageParser(data);
} else if (data.insert.vod) {
return VideoParser(data);
} else if (data.insert.video) {
return VideoParser(data);
} else if (data.insert.backup_text) {
return BackupTextParser(data);
} else if (data.insert.link_card) {
@@ -61,11 +107,29 @@ function ParserTransfer(data: PostStructuredContent): HTMLDivElement | HTMLSpanE
} else if (data.insert.divider) {
return DividerParser(data);
} else {
console.log(data);
throw new Error("Unknown data.insert type");
return UnknownParser(data);
}
}
/**
* @description 解析未知数据
* @since Alpha v0.1.1
* @param {PostStructuredContent} data Mys数据
* @returns {HTMLDivElement} 解析后的未知数据
*/
function UnknownParser(data: PostStructuredContent): HTMLDivElement {
// 创建 div
const div = document.createElement("div");
div.classList.add("mys-post-unknown");
// 创建 code将数据放入 code
const code = document.createElement("code");
code.innerText = JSON.stringify(data);
// 插入 code
div.appendChild(code);
// 返回 div
return div;
}
/**
* @description 解析文本
* @since Alpha
@@ -222,34 +286,42 @@ function VideoParser(data: PostStructuredContent): HTMLDivElement {
if (typeof data.insert === "string") {
throw new Error("data.insert is a string");
}
if (!data.insert.vod) {
if (!data.insert.vod && !data.insert.video) {
throw new Error("data.insert.vod is not defined");
}
// 创建 div
const div = document.createElement("div");
// 创建视频
const video = document.createElement("video");
// 获取 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
// 添加 class
video.classList.add("mys-post-vod");
// 添加 source
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);
// 添加 class
div.classList.add("mys-post-div");
// 返回 div
if (data.insert.vod) {
// 创建视频
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
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);
} else if (data.insert.video) {
// 创建 iframe
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;
}

View File

@@ -33,7 +33,7 @@ onMounted(async () => {
try {
const postData = await MysOper.Post.get(post_id);
loadingTitle.value = "正在渲染数据...";
postHtml.value = MysOper.Post.parser(postData.post.structured_content);
postHtml.value = MysOper.Post.parser(postData);
} catch (error) {
loadingEmpty.value = true;
loadingTitle.value = "帖子不存在或解析失败";