mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-15 09:48:14 +08:00
fix(parser): 完善数据解析
This commit is contained in:
@@ -62,9 +62,10 @@ import TLoading from "../components/t-loading.vue";
|
|||||||
import { fs, http } from "@tauri-apps/api";
|
import { fs, http } from "@tauri-apps/api";
|
||||||
// store
|
// store
|
||||||
import useAppStore from "../store/modules/app";
|
import useAppStore from "../store/modules/app";
|
||||||
|
// plugin
|
||||||
|
import Mys_Oper from "../plugins/Mys";
|
||||||
// utils
|
// utils
|
||||||
import { createTGWindow } from "../utils/TGWindow";
|
import { createTGWindow } from "../utils/TGWindow";
|
||||||
import { StructuredPostParser } from "../plugins/Mys/utils/parser";
|
|
||||||
// interface
|
// interface
|
||||||
import {
|
import {
|
||||||
GachaResponse,
|
GachaResponse,
|
||||||
@@ -180,7 +181,7 @@ async function toPost(post_id: string) {
|
|||||||
return res.data.post.post;
|
return res.data.post.post;
|
||||||
});
|
});
|
||||||
// 结构化渲染
|
// 结构化渲染
|
||||||
const parseDoc = StructuredPostParser(post.structured_content);
|
const parseDoc = Mys_Oper.PostParser(post.structured_content);
|
||||||
// 将解析后的 doc 保存到 文件
|
// 将解析后的 doc 保存到 文件
|
||||||
await fs.writeTextFile(
|
await fs.writeTextFile(
|
||||||
`${appStore.dataPath.temp}\\${post_id}_home.html`,
|
`${appStore.dataPath.temp}\\${post_id}_home.html`,
|
||||||
|
|||||||
@@ -132,9 +132,10 @@ import useAppStore from "../store/modules/app";
|
|||||||
// tools
|
// tools
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import "../tools/svg-inject.js";
|
import "../tools/svg-inject.js";
|
||||||
|
// plugin
|
||||||
|
import Mys_Oper from "../plugins/Mys";
|
||||||
// utils
|
// utils
|
||||||
import { createTGWindow } from "../utils/TGWindow";
|
import { createTGWindow } from "../utils/TGWindow";
|
||||||
import { StructuredPostParser } from "../plugins/Mys/utils/parser";
|
|
||||||
// interface
|
// interface
|
||||||
import {
|
import {
|
||||||
Post,
|
Post,
|
||||||
@@ -215,7 +216,7 @@ async function toPost(post_id: string) {
|
|||||||
// 获取渲染模式
|
// 获取渲染模式
|
||||||
if (renderMode.value) {
|
if (renderMode.value) {
|
||||||
// 结构化渲染
|
// 结构化渲染
|
||||||
parseDoc = StructuredPostParser(post.structured_content);
|
parseDoc = Mys_Oper.PostParser(post.structured_content);
|
||||||
} else {
|
} else {
|
||||||
// 原始渲染
|
// 原始渲染
|
||||||
parseDoc = new DOMParser().parseFromString(post.content, "text/html");
|
parseDoc = new DOMParser().parseFromString(post.content, "text/html");
|
||||||
|
|||||||
14
src/plugins/Mys/index.ts
Normal file
14
src/plugins/Mys/index.ts
Normal 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;
|
||||||
@@ -4,7 +4,6 @@
|
|||||||
* @author BTMuli<bt-muli@outlook.com>
|
* @author BTMuli<bt-muli@outlook.com>
|
||||||
* @since Alpha
|
* @since Alpha
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { PostStructuredContent } from "../interface/post";
|
import { PostStructuredContent } from "../interface/post";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -13,87 +12,26 @@ import { PostStructuredContent } from "../interface/post";
|
|||||||
* @description 为了安全考虑,不会解析所有的属性,只会解析几个常用的属性
|
* @description 为了安全考虑,不会解析所有的属性,只会解析几个常用的属性
|
||||||
* @returns {Document} 解析后的 HTML 文档
|
* @returns {Document} 解析后的 HTML 文档
|
||||||
*/
|
*/
|
||||||
export function StructuredPostParser(data: string): Document {
|
export function PostParser(data: string): Document {
|
||||||
// Json 化
|
// Json 化
|
||||||
let jsonData: PostStructuredContent[] = JSON.parse(data);
|
let jsonData: PostStructuredContent[] = JSON.parse(data);
|
||||||
// 创建 HTML 文档
|
// 创建 HTML 文档
|
||||||
const doc = document.implementation.createHTMLDocument();
|
const doc = document.implementation.createHTMLDocument();
|
||||||
// 遍历 Json 数据
|
// 遍历 Json 数据
|
||||||
jsonData.forEach((item: any) => {
|
jsonData.forEach((item: any) => {
|
||||||
if (item.insert.image) {
|
if (typeof item.insert === "string") {
|
||||||
// 创建 div
|
const text = TextParser(item);
|
||||||
const div = document.createElement("div");
|
doc.body.appendChild(text);
|
||||||
// 创建图片
|
} else if (item.insert.image) {
|
||||||
const img = document.createElement("img");
|
const img = ImageParser(item);
|
||||||
img.src = item.insert.image;
|
doc.body.appendChild(img);
|
||||||
// 设置图片属性
|
|
||||||
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);
|
|
||||||
} else if (item.insert.vod) {
|
} else if (item.insert.vod) {
|
||||||
// 创建 div
|
// 创建 div
|
||||||
const div = document.createElement("div");
|
const video = VideoParser(item);
|
||||||
// 创建视频
|
|
||||||
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
|
|
||||||
// 插入 div
|
// 插入 div
|
||||||
doc.body.appendChild(div);
|
doc.body.appendChild(video);
|
||||||
} else if (typeof item.insert === "string") {
|
} else if (item.insert.backup_text) {
|
||||||
// 创建文本
|
// TODO: 折叠内容
|
||||||
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 宽度设为 800,居中
|
// doc 宽度设为 800,居中
|
||||||
@@ -101,3 +39,123 @@ export function StructuredPostParser(data: string): Document {
|
|||||||
doc.body.style.margin = "20px auto";
|
doc.body.style.margin = "20px auto";
|
||||||
return doc;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user