mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-13 09:28:14 +08:00
fix(parser): 完善内容解析
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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?: {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 = "帖子不存在或解析失败";
|
||||
|
||||
Reference in New Issue
Block a user