fix(parser): 完善数据解析

This commit is contained in:
BTMuli
2023-03-29 13:53:47 +08:00
parent d6112c573c
commit 988f595435
5 changed files with 152 additions and 78 deletions

View File

@@ -62,9 +62,10 @@ import TLoading from "../components/t-loading.vue";
import { fs, http } from "@tauri-apps/api";
// store
import useAppStore from "../store/modules/app";
// plugin
import Mys_Oper from "../plugins/Mys";
// utils
import { createTGWindow } from "../utils/TGWindow";
import { StructuredPostParser } from "../plugins/Mys/utils/parser";
// interface
import {
GachaResponse,
@@ -180,7 +181,7 @@ async function toPost(post_id: string) {
return res.data.post.post;
});
// 结构化渲染
const parseDoc = StructuredPostParser(post.structured_content);
const parseDoc = Mys_Oper.PostParser(post.structured_content);
// 将解析后的 doc 保存到 文件
await fs.writeTextFile(
`${appStore.dataPath.temp}\\${post_id}_home.html`,

View File

@@ -132,9 +132,10 @@ import useAppStore from "../store/modules/app";
// tools
// @ts-ignore
import "../tools/svg-inject.js";
// plugin
import Mys_Oper from "../plugins/Mys";
// utils
import { createTGWindow } from "../utils/TGWindow";
import { StructuredPostParser } from "../plugins/Mys/utils/parser";
// interface
import {
Post,
@@ -215,7 +216,7 @@ async function toPost(post_id: string) {
// 获取渲染模式
if (renderMode.value) {
// 结构化渲染
parseDoc = StructuredPostParser(post.structured_content);
parseDoc = Mys_Oper.PostParser(post.structured_content);
} else {
// 原始渲染
parseDoc = new DOMParser().parseFromString(post.content, "text/html");

14
src/plugins/Mys/index.ts Normal file
View File

@@ -0,0 +1,14 @@
/**
* @file plugins Mys index.ts
* @description Mys plugin index
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha
*/
import { PostParser } from "./utils/parser";
const Mys_Oper = {
PostParser,
};
export default Mys_Oper;

View File

@@ -4,7 +4,6 @@
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha
*/
import { PostStructuredContent } from "../interface/post";
/**
@@ -13,87 +12,26 @@ import { PostStructuredContent } from "../interface/post";
* @description 为了安全考虑,不会解析所有的属性,只会解析几个常用的属性
* @returns {Document} 解析后的 HTML 文档
*/
export function StructuredPostParser(data: string): Document {
export function PostParser(data: string): Document {
// Json 化
let jsonData: PostStructuredContent[] = JSON.parse(data);
// 创建 HTML 文档
const doc = document.implementation.createHTMLDocument();
// 遍历 Json 数据
jsonData.forEach((item: any) => {
if (item.insert.image) {
// 创建 div
const div = document.createElement("div");
// 创建图片
const img = document.createElement("img");
img.src = item.insert.image;
// 设置图片属性
img.height = item.attributes.height; // 设置高度
img.width = item.attributes.width; // 设置宽度
// 如果宽度超过 800将其设置为 800图片自适应
if (img.width > 800) img.width = 800;
// 高度自适应
img.style.height = "auto";
// 插入图片
div.appendChild(img);
// 设置 div 属性
div.style.display = "center"; // 居中
div.style.margin = "20px auto"; // 设置 margin
// 插入 div
doc.body.appendChild(div);
if (typeof item.insert === "string") {
const text = TextParser(item);
doc.body.appendChild(text);
} else if (item.insert.image) {
const img = ImageParser(item);
doc.body.appendChild(img);
} else if (item.insert.vod) {
// 创建 div
const div = document.createElement("div");
// 创建视频
const video = document.createElement("video");
// 获取最高分辨率的视频
let resolution;
// 获取 resolutions中definition="1080P"的视频
resolution = item.insert.vod.resolutions.find(
(resolution: any) => resolution.definition === "1080P"
);
if (!resolution) {
// 如果没有找到就获取720P的视频
resolution = item.insert.vod.resolutions.find(
(resolution: any) => resolution.definition === "720P"
);
}
if (!resolution) {
// 如果还是没有找到,就获取第一个
resolution = item.insert.vod.resolutions[0];
}
// 设置一些属性
video.poster = item.insert.vod.cover; // 设置封面
video.width = resolution.width > 800 ? 800 : resolution.width; // 设置宽度(取最高分辨率的宽度)
video.height = resolution.width > 800 ? 450 : resolution.height; // 设置高度(取最高分辨率的高度)
video.controls = true; // 设置 controls
// 添加 source
const source = document.createElement("source");
source.src = resolution.url;
source.type = resolution.format === ".mp4" ? "video/mp4" : "video/webm";
video.appendChild(source);
// 添加 controls
video.controls = true;
// 插入 video
div.appendChild(video);
// 设置 div 属性
div.style.display = "center"; // 居中
div.style.margin = "20px auto"; // 设置 margin
const video = VideoParser(item);
// 插入 div
doc.body.appendChild(div);
} else if (typeof item.insert === "string") {
// 创建文本
const text = document.createElement("span");
// 设置文本属性
// 创建 style string
if (item.attributes) {
let styleString = "";
if (item.attributes.color) styleString += `color: ${item.attributes.color};`;
// 设置 style
text.style.cssText = styleString;
}
text.innerText = item.insert; // 设置文本
// 插入文本
doc.body.appendChild(text);
doc.body.appendChild(video);
} else if (item.insert.backup_text) {
// TODO: 折叠内容
}
});
// doc 宽度设为 800,居中
@@ -101,3 +39,123 @@ export function StructuredPostParser(data: string): Document {
doc.body.style.margin = "20px auto";
return doc;
}
/**
* @description 解析文本
* @since Alpha
* @param {PostStructuredContent} data Mys数据
* @returns {HTMLSpanElement} 解析后的文本
*/
function TextParser(data: PostStructuredContent): HTMLSpanElement {
// 检查数据
if (typeof data.insert !== "string") {
throw new Error("data.insert is not a string");
}
// 创建文本
const text = document.createElement("span");
// 设置文本属性
if (data.attributes) {
if (data.attributes.bold) text.style.fontWeight = "bold";
if (data.attributes.color) text.style.color = data.attributes.color;
if (data.attributes.link) {
const a = document.createElement("a");
a.href = data.attributes.link;
a.target = "_blank";
a.innerText = data.insert;
return a;
}
}
// 行间距
text.style.lineHeight = "2";
// 设置 span 内容
text.innerText = data.insert;
// 返回文本
return text;
}
/**
* @description 解析图片
* @since Alpha
* @param {PostStructuredContent} data Mys数据
* @returns {HTMLDivElement} 解析后的图片
*/
function ImageParser(data: PostStructuredContent): HTMLDivElement {
// 检查数据
if (typeof data.insert === "string") {
throw new Error("data.insert is a string");
}
if (!data.insert.image) {
throw new Error("data.insert.image is not defined");
}
if (!data.attributes) {
throw new Error("data.attributes is not defined");
}
if (!data.attributes.width) {
throw new Error("data.attributes.width is not defined");
}
if (!data.attributes.height) {
throw new Error("data.attributes.height is not defined");
}
const div = document.createElement("div");
// 创建图片
const img = document.createElement("img");
img.src = data.insert.image;
// 设置图片属性,窗口宽度 900页面宽度 800
img.style.height = "auto"; // 高度自适应
img.width = 800; // 设置宽度
// 判断是否是 cover
if (data.attributes.width === 690 && data.attributes.height === 320) {
// 添加 border-radius
img.style.borderRadius = "10px";
}
// 插入图片
div.appendChild(img);
// 设置 div 属性
div.style.display = "center"; // 居中
div.style.margin = "20px auto"; // 设置 margin
// 返回 div
return div;
}
/**
* @description 解析视频
* @since Alpha
* @param {PostStructuredContent} data Mys数据
* @returns {HTMLDivElement} 解析后的视频
*/
function VideoParser(data: PostStructuredContent): HTMLDivElement {
// 检查数据
if (typeof data.insert === "string") {
throw new Error("data.insert is a string");
}
if (!data.insert.vod) {
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.width = 800; // 设置宽度
video.height = 450; // 设置高度
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);
// 设置 div 属性
div.style.display = "center"; // 居中
div.style.margin = "20px auto"; // 设置 margin
// 返回 div
return div;
}