<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文字之墙:博客随笔 - 藤原的数字空间</title>
<style>
/* ================= 全局样式 ================= */
@import url("https://fonts.cdnfonts.com/css/satoshi");
@import url("https://fonts.googleapis.com/css2?family=Quicksand:wght@300..700&display=swap");
* {
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
scroll-behavior: smooth;
}
html, body {
min-height: 100%;
}
body {
margin: 0;
font-family: "Satoshi", sans-serif, monospace;
color: #eee;
font-size: 18px;
line-height: 161.8%;
background: #212431;
interpolate-size: allow-keywords;
}
/* 滚动条样式 */
::-webkit-scrollbar {
width: 14px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: #ea5c1f;
border: 4px solid #212431;
cursor: pointer;
}
::-webkit-scrollbar-thumb:hover {
background: #ea5c1f77;
}
/* ================= 文章容器 ================= */
article {
max-width: 618px;
padding: 8px 24px;
margin: auto;
margin-top: 100px;
margin-bottom: 100px;
font-weight: 100;
position: relative;
overflow: hidden;
border-bottom: 4px solid #d6d7d711;
border-left: 4px solid #d6d7d711;
background: linear-gradient(90deg, #46506433 0%, #4f5d7533);
border-top-right-radius: 64px;
}
/* ================= 顶部区域 ================= */
article h1 {
position: absolute;
margin: 0;
top: 0;
padding: 16px 22px 16px 0px;
background: #292f3e;
border-bottom-right-radius: 24px;
z-index: 2;
line-height: 100%;
color: #ea5c1f;
font-size: 1.8em;
}
article .date {
position: absolute;
margin: 0;
bottom: -28px;
padding: 0px 24px 8px 0px;
border-bottom-right-radius: 22px;
z-index: 2;
color: #fff;
font-size: 16px;
font-weight: 400;
background: #292f3e;
}
/* 特色图片区域 */
.featured-image {
width: 100%;
height: 324px;
background: url("https://picsum.photos/600/400?grayscale");
background-size: cover;
background-position: 50% 16.18%;
margin-top: 16px;
border-top-right-radius: 42px;
border-bottom: 4px solid #ea5c1f;
position: relative;
z-index: 1;
}
.featured-image .expand {
position: absolute;
right: 0px;
bottom: -4px;
color: #fff;
cursor: pointer;
background: #292f3e;
border-top-left-radius: 32px;
width: 64px;
height: 64px;
border-left: 4px solid #ea5c1f;
border-top: 4px solid #ea5c1f;
}
.featured-image .expand::before {
content: "+";
display: flex;
position: absolute;
width: 100%;
height: 100%;
align-items: center;
justify-content: center;
font-size: 2em;
font-weight: bold;
color: #ea5c1f;
transition: all 0.4s ease-in-out;
}
.featured-image .expand.close::before {
content: "-";
}
.featured-image .expand:hover::before {
transform: rotate(90deg);
}
.featured-image .expand.close:hover::before {
transform: rotate(0deg);
}
/* ================= 中部内容区域 ================= */
article .content {
transition: height 1s ease-out;
visibility: visible;
height: 0;
overflow: clip;
}
article:has(.expand.close) .content {
transition: height 1s ease-in;
height: auto;
}
article aside {
border-left: 4px solid #ea5c1f;
padding-left: 16px;
margin-bottom: 16px;
line-height: 124%;
}
article strong {
font-weight: 600;
}
article a {
font-weight: 500;
color: #ea5c1f;
text-decoration: none;
cursor: pointer;
}
article a:hover {
text-decoration: underline;
}
.dotmap {
width: 100%;
height: min(30vw, 200px);
background: linear-gradient(#fff0, #fff4, #fff0);
mask-image: url("https://assets.codepen.io/3421562/dotmap.svg");
position: relative;
}
.dotmap::before {
scale: 0;
opacity: 0;
transition: all 0.2s ease-out;
content: "";
display: block;
position: absolute;
width: 100px;
height: 100px;
border-radius: 200px;
background: #ea5c1f;
filter: blur(40px);
top: var(--y);
left: var(--x);
translate: -50% -50%;
}
.dotmap:hover::before {
scale: 1;
opacity: 1;
}
.dotmap::after {
content: "";
display: block;
position: absolute;
width: 100%;
height: 100%;
background: url("https://assets.codepen.io/3421562/dotmap_h.svg");
top: 0;
left: 0;
}
.planet {
width: 100%;
height: min(30vw, 216px);
overflow: hidden;
position: relative;
background: url("https://assets.codepen.io/3421562/stars.svg");
background-size: contain;
background-blend-mode: color-burn;
box-shadow: 4px 6px 0 0 #212431, 0 8px 16px 0 #0000;
}
.planet::after {
display: block;
content: "";
width: min(60vw, 500px);
height: min(60vw, 500px);
box-shadow: -2px 0 12px 1px #ea5c1f44, inset 42px -142px 64px 1px #ea5c1faa,
inset -2px 2px 6px 1px #ea5c1f22, inset -8px 22px 16px 1px #ea5c1f22,
inset -42px 42px 42px 1px #212431, inset 0 0 100px 1px #fff3;
border-radius: 100%;
position: absolute;
right: -34%;
top: 6%;
background: #41322c;
}
.planet span {
position: absolute;
width: min(110vw, 800px);
height: min(110vw, 800px);
right: -46%;
top: -100%;
border-radius: 100%;
transform-style: preserve-3d;
transform: rotateX(75deg) rotateY(16deg) rotate3d(0, 0, 1, 0deg);
animation: pRev 20s linear infinite;
border: 2px solid #ea5c1f44;
}
@keyframes pRev {
to {
transform: rotateX(75deg) rotateY(16deg) rotate3d(0, 0, 1, 360deg);
}
}
.skyline {
width: 100%;
height: 200px;
overflow: hidden;
position: relative;
background: url("https://assets.codepen.io/3421562/skyline.svg");
background-size: max(100%, 500px);
background-position: 50% 12px;
background-repeat: no-repeat;
background-blend-mode: color-burn;
box-shadow: 0px 6px 0 0 #212431, 0 8px 16px 0 #0000;
}
/* ================= 底部区域 ================= */
article .foot {
display: flex;
gap: 24px;
align-items: center;
flex-wrap: wrap;
padding-bottom: 16px;
}
article .foot img {
max-width: 84px;
height: auto;
border: 4px solid #f5f5f5;
border-top-color: #ea5c1f;
border-right-color: #ea5c1f;
object-fit: contain;
cursor: pointer;
transition: all 0.3s ease;
}
article .foot img:hover {
transform: scale(1.05);
border-color: #ea5c1f;
box-shadow: 0 0 20px rgba(234, 92, 31, 0.3);
}
article .author a {
font-weight: 600;
}
article .author span {
font-size: 1.4em;
padding-right: 2px;
translate: 0 2px;
rotate: -33deg;
display: inline-block;
color: #eec7b7;
transition: all 0.2s ease-in-out;
}
article .author a:hover,
article .author a:hover span {
color: #ea5c1f;
rotate: 0deg;
}
/* ================= 终端样式 ================= */
:root {
--fontBody: Quicksand;
--accent: #ea5c1f;
--accentRGB: 234, 92, 31;
--support: #eec7b7;
--supportRGB: 238, 199, 183;
--feature: #a6b0b4;
--featureRGB: 166, 176, 180;
--dark: #eee;
--darkRGB: 238, 238, 238;
--darker: #292f3e;
--darkerRGB: 41, 47, 62;
--lighter: #212431;
--lighterRGB: 33, 36, 49;
--light: #46506433;
--lightRGB: 70, 80, 100;
--lightest: #ffffff;
--lightestRGB: 255, 255, 255;
--darkest: #101010;
--darkestRGB: 16, 16, 16;
--editor-bg: rgba(41, 47, 62, 0.9);
--editor-secondary-bg: rgba(70, 80, 100, 0.3);
--line-color: #ea5c1f;
--text-color: #eee;
--keyword-color: #eec7b7;
--string-color: #a6b0b4;
--comment-color: rgba(234, 92, 31, 0.7);
--number-color: #ea5c1f;
--function-color: #eec7b7;
--font-family: 'Satoshi', 'Consolas', 'Monaco', monospace;
--header-bg: rgba(41, 47, 62, 0.95);
--window-btn-close: #ff5f56;
--window-btn-min: #ffbd2e;
--window-btn-max: #27c93f;
--ai-output-color: #eee;
--user-input-color: #eec7b7;
--video-bg: #000000;
--terminal-accent-color: #ea5c1f;
--terminal-accent-hover: #eec7b7;
--box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
--border-radius: 15px;
--success-color: #4caf50;
--warning-color: #ff9800;
--error-color: #f44336;
--tool-header-height: 40px;
--tool-padding: 16px;
--terminal-border: 1px solid rgba(234, 92, 31, 0.3);
}
/* 终端容器 - 内嵌在博客中 */
#terminal-container {
width: 100%;
max-height: 0;
background: var(--editor-bg);
border-radius: var(--border-radius);
box-shadow: var(--box-shadow);
border: var(--terminal-border);
display: flex;
flex-direction: column;
overflow: hidden;
backdrop-filter: blur(5px);
margin-top: 20px;
transition: all 0.5s ease;
opacity: 0;
transform: translateY(-20px);
}
#terminal-container.show {
max-height: 600px;
opacity: 1;
transform: translateY(0);
}
/* 终端编辑器样式 */
.editor {
width: 100%;
height: 100%;
background: transparent;
display: flex;
flex-direction: column;
}
.editor-header {
background: var(--header-bg);
padding: 12px;
border-radius: var(--border-radius) var(--border-radius) 0 0;
display: flex;
align-items: center;
gap: 8px;
border-bottom: var(--terminal-border);
}
.window-btn {
width: 12px;
height: 12px;
border-radius: 50%;
position: relative;
cursor: pointer;
transition: all 0.2s ease;
}
.window-btn:hover {
transform: scale(1.1);
}
.close { background: var(--window-btn-close); }
.minimize { background: var(--window-btn-min); }
.maximize { background: var(--window-btn-max); }
.title-bar {
color: var(--line-color);
margin-left: 20px;
font-size: 0.9em;
font-family: var(--fontBody);
font-weight: 600;
}
.editor-content {
padding: 20px;
counter-reset: line;
font-size: 14px;
overflow-x: auto;
overflow-y: auto;
scrollbar-width: none;
-ms-overflow-style: none;
height: 450px;
font-family: var(--font-family);
background: transparent;
}
.editor-content::-webkit-scrollbar {
width: 8px;
}
.editor-content::-webkit-scrollbar-track {
background: transparent;
}
.editor-content::-webkit-scrollbar-thumb {
background: var(--terminal-accent-color);
border-radius: 4px;
}
.line {
display: flex;
padding: 2px 0;
position: relative;
min-height: 1.6em;
}
.line::before {
counter-increment: line;
content: counter(line);
color: var(--line-color);
width: 2em;
text-align: right;
padding-right: 1em;
position: absolute;
opacity: 0.7;
font-family: var(--font-family);
}
.line-content {
padding-left: 3em;
width: 100%;
font-family: var(--font-family);
}
.indent { margin-left: 2em; }
.indent-2 { margin-left: 4em; }
.keyword { color: var(--keyword-color); font-weight: 600; }
.string { color: var(--string-color); }
.comment { color: var(--comment-color); font-style: italic; }
.number { color: var(--number-color); }
.function { color: var(--function-color); font-weight: 600; }
.ai-output { color: var(--ai-output-color); }
.user-input { color: var(--user-input-color); font-weight: 600; }
.input-line {
display: flex;
align-items: center;
background: var(--editor-secondary-bg);
padding: 8px 10px;
border-radius: 4px;
margin: 0 20px 20px;
border-top: var(--terminal-border);
}
.input-line::before {
content: ">";
color: var(--terminal-accent-color);
width: 2em;
text-align: right;
padding-right: 1em;
font-weight: bold;
}
.input-line input {
flex: 1;
background: transparent;
border: none;
color: var(--text-color);
font-family: var(--font-family);
font-size: 14px;
outline: none;
padding: 2px 0;
}
/* 通用工具容器样式 */
.tool-container {
background: var(--editor-secondary-bg);
border-radius: var(--border-radius);
margin: 15px 0;
border: var(--terminal-border);
overflow: hidden;
backdrop-filter: blur(5px);
width: 100%;
max-width: 100%;
}
.tool-header {
background: var(--header-bg);
padding: 12px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: var(--terminal-border);
}
.tool-title {
color: var(--text-color);
font-size: 14px;
font-weight: 600;
display: flex;
align-items: center;
gap: 8px;
}
.tool-close {
background: none;
border: none;
color: var(--line-color);
cursor: pointer;
padding: 4px;
border-radius: 4px;
}
.tool-close:hover {
color: var(--text-color);
background: rgba(var(--accentRGB), 0.1);
}
.tool-content {
padding: 20px;
width: 100%;
box-sizing: border-box;
}
.tool-input {
width: 100%;
padding: 12px 50px 12px 16px;
border: var(--terminal-border);
border-radius: 8px;
background: var(--editor-secondary-bg);
color: var(--text-color);
font-size: 14px;
outline: none;
box-sizing: border-box;
}
.tool-input:focus {
border-color: var(--terminal-accent-color);
box-shadow: 0 0 0 3px rgba(var(--accentRGB), 0.2);
}
.tool-btn {
background: var(--terminal-accent-color);
color: white;
border: none;
padding: 8px 16px;
border-radius: 6px;
cursor: pointer;
font-size: 12px;
display: flex;
align-items: center;
gap: 6px;
font-weight: 500;
}
.tool-btn:hover {
background: var(--terminal-accent-hover);
transform: translateY(-1px);
}
/* 视频播放器样式 */
.video-container {
background: var(--video-bg);
border-radius: var(--border-radius);
margin: 15px 0;
overflow: hidden;
border: var(--terminal-border);
width: 100%;
}
.video-player {
position: relative;
width: 100%;
height: 300px;
background: #000;
}
.video-player video, .video-player iframe {
width: 100%;
height: 100%;
object-fit: contain;
border: none;
}
.video-controls {
background: var(--editor-secondary-bg);
padding: 10px;
display: flex;
gap: 10px;
align-items: center;
flex-wrap: wrap;
}
.video-button {
background: var(--terminal-accent-color);
color: white;
border: none;
padding: 6px 12px;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
display: flex;
align-items: center;
gap: 6px;
}
.video-button:hover {
background: var(--terminal-accent-hover);
}
/* 加载动画 */
.loader {
display: inline-block;
width: 20px;
height: 20px;
border: 3px solid rgba(var(--accentRGB), 0.3);
border-radius: 50%;
border-top-color: var(--accent);
animation: spin 1s ease-in-out infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
/* 图片转换工具样式 */
.image-converter {
display: flex;
flex-direction: column;
gap: 15px;
}
.image-upload-area {
border: 2px dashed var(--terminal-accent-color);
border-radius: 8px;
padding: 20px;
text-align: center;
cursor: pointer;
transition: all 0.3s ease;
}
.image-upload-area:hover {
background: rgba(var(--accentRGB), 0.1);
}
.image-upload-area.dragover {
background: rgba(var(--accentRGB), 0.2);
border-color: var(--terminal-accent-hover);
}
.format-selector {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.format-btn {
background: var(--editor-secondary-bg);
color: var(--text-color);
border: 1px solid var(--terminal-border);
padding: 8px 16px;
border-radius: 6px;
cursor: pointer;
font-size: 12px;
transition: all 0.2s ease;
}
.format-btn:hover, .format-btn.active {
background: var(--terminal-accent-color);
color: white;
border-color: var(--terminal-accent-color);
}
.image-preview {
max-width: 100%;
max-height: 200px;
border-radius: 8px;
margin: 10px 0;
}
/* Ping测试结果样式 */
.ping-result {
background: var(--editor-secondary-bg);
border-radius: 8px;
padding: 15px;
margin: 10px 0;
font-family: var(--font-family);
font-size: 13px;
}
.ping-success {
color: var(--success-color);
}
.ping-warning {
color: var(--warning-color);
}
.ping-error {
color: var(--error-color);
}
/* 响应式设计 */
@media screen and (max-width: 860px) {
#terminal-container {
border-radius: 8px;
}
.editor-content {
height: 350px;
padding: 15px;
}
article {
margin-top: 50px;
margin-bottom: 50px;
}
.format-selector {
justify-content: center;
}
}
</style>
</head>
<body>
<!-- ================= 文章整体结构 ================= -->
<article>
<!-- 顶部区域:标题和日期 -->
<h1>
<span id="ai-title">文字之墙:博客随笔</span>
<div class="date">2024年11月19日</div>
</h1>
<!-- 特色图片区域 -->
<div class="featured-image">
<div class="expand" onclick="this.classList.toggle('close')"></div>
</div>
<!-- 中部:主要内容区域 -->
<div class="content">
<p id="ai-content-1"></p>
<p id="ai-content-2"></p>
<!-- AI内容生成脚本 -->
<script>
function fillWithAIContent(prompt, elementId) {
const randomValue = Math.random().toString(36).substring(2, 8);
const uniquePrompt = `${prompt} unique-${randomValue}`;
fetch(`https://text.pollinations.ai/${encodeURIComponent(uniquePrompt)}`)
.then(response => response.text())
.then(data => {
const words = data.split(" ");
const wordCount = Math.min(words.length, 2);
const randomIndexes = Array.from({
length: wordCount
}, () =>
Math.floor(Math.random() * words.length)
);
randomIndexes.forEach(index => {
words[index] = `<strong>${words[index]}</strong>`;
});
document.getElementById(elementId).innerHTML = words.join(" ");
})
.catch(error => {
console.error("获取AI内容时出错:", error);
});
}
// 生成AI内容
fillWithAIContent("写一个不超过四个字的博客标题,关于日常生活中正念的好处", "ai-title");
fillWithAIContent("写一段关于日常生活中正念好处的简短介绍段落", "ai-content-1");
fillWithAIContent("写一段关于日常生活中正念好处的简短叙述段落", "ai-content-2");
</script>
<p>从前有个智者说,生活就像一本书,需要我们细细品读。当下即是永恒,每一个瞬间都值得珍惜。
<aside>
<p><strong>活在当下</strong>。正念让我们能够真正体验生活的每一个细节,不被过去困扰,不为未来焦虑。</p>
</aside>
当我们专注于呼吸,专注于此刻,心灵便得到了净化。正念不是逃避,而是更深地融入生活,感受每一刻的真实。</p>
<!-- 点阵图效果 -->
<div class="dotmap"></div>
<script>
function hoverFollow(target) {
target.addEventListener('mousemove', (event) => {
const rect = target.getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
target.style.setProperty('--x', `${x}px`);
target.style.setProperty('--y', `${y}px`);
});
}
hoverFollow(document.querySelector('.dotmap'));
</script>
<h2>文字的力量</h2>
<p>文字是人类最伟大的发明之一,它承载着思想,传递着情感。<strong>用心书写</strong>的文字能够穿越时空,触动心灵。每一篇文章都是作者心血的结晶,每一个故事都值得被认真对待。</p>
<!-- 星球动画效果 -->
<div class="planet">
<span></span>
<span></span>
<span></span>
</div>
<h2>如何让文字更有魅力</h2>
<p>好的文字需要用心雕琢,就像匠人打磨艺术品一样。首先,要有清晰的思路;其次,选择恰当的词语;最重要的是,要倾注真情实感。</p>
<!-- 天际线效果 -->
<div class="skyline"></div>
<p>在这个信息爆炸的时代,静下心来写作变得越来越珍贵。文字不仅是表达的工具,更是思考的载体。当我们放慢脚步,用心书写,文字自然会散发出独特的光芒。</p>
<p>写作是一种修行,每一篇文章都是作者与世界对话的方式。无论长短,无论题材,真诚的文字总能找到它的读者。</p>
<p>让我们珍惜文字的力量,用它记录生活,表达思想,连接心灵。在这个快速变化的世界里,文字是我们永恒的伴侣。</p>
</div>
<!-- 底部区域:作者信息 -->
<div class="foot">
<img src="https://assets.codepen.io/3421562/internal/avatars/users/default.png"
alt="作者头像"
class="profile-card"
onclick="toggleTerminal()"
title="点击打开终端">
<div class="author">作者:<br><a href="#" target="_blank"><span>@</span>TENG YUAN</a></div>
</div>
<!-- 终端容器 - 内嵌在博客中 -->
<div id="terminal-container">
<div class="editor" id="mainEditor">
<div class="editor-header">
<span class="window-btn close" onclick="toggleTerminal()"></span>
<span class="window-btn minimize"></span>
<span class="window-btn maximize"></span>
<span class="title-bar">terminal.js - 藤原的数字空间</span>
</div>
<div class="editor-content" id="editorContent">
<div class="line">
<div class="line-content">
<span class="comment">// 个人信息配置</span>
</div>
</div>
<div class="line">
<div class="line-content">
<span class="keyword">const</span>
<span class="function">profile</span> = {
</div>
</div>
<div class="line">
<div class="line-content indent">
<span class="keyword">name</span>: <span class="string">"藤原"</span>,
</div>
</div>
<div class="line">
<div class="line-content indent">
<span class="keyword">title</span>: <span class="string">"职场牛马!!!"</span>,
</div>
</div>
<div class="line">
<div class="line-content indent">
<span class="keyword">contact</span>: {
</div>
</div>
<div class="line">
<div class="line-content indent-2">
<span class="keyword">email</span>: <span class="string">
<a href="mailto:2083737075@qq.com">"2083737075@qq.com"</a>
</span>,
</div>
</div>
<div class="line">
<div class="line-content indent-2">
<span class="keyword">website</span>: <span class="string">
<a href="http://tengyuan.icu" target="_blank">"TengYuan.icu"</a>
</span>,
</div>
</div>
<div class="line">
<div class="line-content indent-2">
<span class="keyword">FileCodeBox</span>: <span class="string">
<a href="http://wp.tengyuan.icu/" target="_blank">"wp.tengyuan.icu"</a>
</span>,
</div>
</div>
<div class="line">
<div class="line-content indent">},</div>
</div>
<div class="line">
<div class="line-content indent">
<span class="keyword">links</span>: {
</div>
</div>
<div class="line">
<div class="line-content indent-2">
<span class="keyword">travel blog</span>: <span class="string">
<a href="http://blog.tengyuan.icu/" target="_blank">"blog.tengyuan.icu"</a>
</span>,
</div>
</div>
<div class="line">
<div class="line-content indent-2">
<span class="keyword">birthday</span>: <span class="string">
<a href="http://sr.0814.cn" target="_blank">"2001/11/01"</a>
</span>,
</div>
</div>
<div class="line">
<div class="line-content indent">},</div>
</div>
<div class="line">
<div class="line-content indent">
<span class="comment">// 座右铭</span>
</div>
</div>
<div class="line">
<div class="line-content indent">
<span class="keyword">motto</span>: <span class="string">"以清简代码,筑玖维数字宇宙。"</span>,
</div>
</div>
<div class="line">
<div class="line-content indent">
<span class="keyword">copyright</span>: <span class="string">"2017-<span id="year"></span> 藤原"</span>,
</div>
</div>
<div class="line">
<div class="line-content">};</div>
</div>
<div class="line">
<div class="line-content">
<span class="comment">// 终端交互</span>
</div>
</div>
<div class="line">
<div class="line-content">
<span class="function">console</span>.<span class="function">log</span>(<span class="string">"欢迎访问藤原的个人终端"</span>);
</div>
</div>
<div class="line">
<div class="line-content">
<span class="function">console</span>.<span class="function">log</span>(<span class="string">"输入 'help' 获取可用命令"</span>);
</div>
</div>
</div>
<!-- 输入行 -->
<div class="input-line">
<input type="text" id="userInput" placeholder="输入命令..." autocomplete="off">
</div>
</div>
</div>
</article>
<!-- JavaScript代码 -->
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/file-saver@2.0.5/dist/FileSaver.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jszip@3.10.1/dist/jszip.min.js"></script>
<script>
// ================ 全局变量和配置 ================
const API_CONFIG = {
id: '10003788',
key: 'ffa8afb46dce4916c5a74fd73c8de9f6',
endpoints: {
ai: 'https://cn.apihz.cn/api/ai/wxtiny.php',
ping: 'https://cn.apihz.cn/api/wangzhan/ping.php',
shortVideo: 'http://124.220.49.230/api/fun/douyin.php',
search: 'https://cn.apihz.cn/api/search/baidu.php'
}
};
// 全局状态管理
let commandHistoryArray = JSON.parse(localStorage.getItem('commandHistory') || '[]');
let historyIndex = -1;
let totalParseCount = parseInt(localStorage.getItem('totalParseCount') || '0');
let successParseCount = parseInt(localStorage.getItem('successParseCount') || '0');
let indentSize = 4;
let currentTheme = localStorage.getItem('terminalTheme') || 'default';
let fileStorage = JSON.parse(localStorage.getItem('fileStorage') || '{}');
// 设置当前年份
document.getElementById('year').textContent = new Date().getFullYear();
// 终端相关元素
const terminalContainer = document.getElementById('terminal-container');
const editorContent = document.getElementById('editorContent');
const userInput = document.getElementById('userInput');
// 支持的视频平台列表
const supportedVideoPlatforms = [
'v.qq.com', 'iqiyi.com', 'youku.com', 'mgtv.com', 'bilibili.com',
'sohu.com', 'le.com', 'pptv.com', 'wasu.cn', '1905.com',
'fun.tv', 'acfun.cn', 'douyu.com', 'huya.com', 'yy.com'
];
// 影视解析接口
const videoApis = [
{ name: "默认线路【推荐】", url: "https://www.yemu.xyz/?url=" },
{ name: "线路一【推荐】", url: "https://jx.we-vip.com/?url=" },
{ name: "线路二【推荐】", url: "https://z1.m1907.top/?jx=" },
{ name: "线路三", url: "https://www.ckplayer.vip/jiexi/?url=" },
{ name: "线路四", url: "https://jx.jsonplayer.com/player/?url=" },
{ name: "线路五", url: "https://jx.4kdv.com/?url=" },
{ name: "线路六", url: "https://api.jiexi.la/?url=" },
{ name: "线路七", url: "https://jx.qqwtt.com/?url=" },
{ name: "线路八", url: "https://www.playm3u8.cn/jiexi.php?url=" },
{ name: "线路九", url: "https://jx.xmflv.com/?url=" }
];
// 编码工具配置
const encodingTools = {
base64: {
encode: (text) => btoa(unescape(encodeURIComponent(text))),
decode: (text) => decodeURIComponent(escape(atob(text)))
},
url: {
encode: (text) => encodeURIComponent(text),
decode: (text) => decodeURIComponent(text)
},
html: {
encode: (text) => text.replace(/[&<>"']/g, (match) => {
const map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' };
return map[match];
}),
decode: (text) => text.replace(/&|<|>|"|'/g, (match) => {
const map = { '&': '&', '<': '<', '>': '>', '"': '"', ''': "'" };
return map[match];
})
}
};
// 帮助信息
const helpText = `🚀 终端命令帮助
📋 基础命令:
- help: 显示帮助信息
- clear: 清空终端
- history: 显示命令历史记录
- about: 显示关于信息
🔧 代码工具:
- format [code]: 格式化代码 (支持: json, html, css, js, sql)
例如: format {"name":"John","age":30}
- minify [code]: 压缩代码 (支持: json, html, css, js, sql)
例如: minify <div><p>Hello</p></div>
- detect [code]: 自动检测代码类型
例如: detect SELECT * FROM users
🎬 影视工具:
- video [url]: 解析影视视频(支持爱奇艺、腾讯视频等)
例如: video https://v.qq.com/x/cover/xxx.html
- shortvideo [url]: 解析短视频(支持抖音、快手、小红书)
例如: shortvideo https://v.douyin.com/xxxxxx
🌐 网络工具:
- ping [url]: 测试网站或IP的ping延迟
例如: ping www.example.com
- search [keyword]: 搜索网络内容
例如: search JavaScript教程
🤖 AI工具:
- ai [message]: 与AI助手对话
例如: ai 你好,请介绍一下JavaScript
🖼️ 图片工具:
- image: 打开图片格式转换器 (支持: jpg, png, webp, bmp)
🔐 编码工具:
- encode [type] [text]: 编码文本 (支持: base64, url, html)
例如: encode base64 Hello World
- decode [type] [text]: 解码文本 (支持: base64, url, html)
例如: decode base64 SGVsbG8gV29ybGQ=
📁 文件管理:
- files: 显示文件管理器
- save [filename] [content]: 保存文件
例如: save test.txt Hello World
- load [filename]: 加载文件内容
例如: load test.txt
- delete [filename]: 删除文件
例如: delete test.txt
⚙️ 设置:
- set indent [size]: 设置缩进大小 (1-8个空格)
例如: set indent 4
- theme [name]: 切换主题 (default, dark, blue)
例如: theme dark
📊 系统工具:
- stats: 显示系统统计信息
- time: 显示当前时间
- weather [city]: 查询天气信息
例如: weather 北京
💡 提示: 使用上下箭头键浏览命令历史,ESC键关闭终端`;
// ================ 核心功能函数 ================
// 终端切换功能
function toggleTerminal() {
if (terminalContainer.classList.contains('show')) {
terminalContainer.classList.remove('show');
} else {
terminalContainer.classList.add('show');
setTimeout(() => userInput.focus(), 300);
}
}
// 更新解析统计
function updateParseStats() {
localStorage.setItem('totalParseCount', totalParseCount.toString());
localStorage.setItem('successParseCount', successParseCount.toString());
}
// 检查URL是否属于支持的视频平台
function isSupportedVideoUrl(url) {
if (!url) return false;
try {
const domain = new URL(url).hostname.toLowerCase();
return supportedVideoPlatforms.some(platform => domain.includes(platform));
} catch (e) {
return false;
}
}
// 代码格式化工具函数
function formatCode(code, type) {
try {
code = code.trim();
switch(type.toLowerCase()) {
case 'json':
try {
const parsed = JSON.parse(code);
return JSON.stringify(parsed, null, ' '.repeat(indentSize));
} catch (e) {
throw new Error(`JSON解析错误: ${e.message}`);
}
case 'html':
let html = code;
let formatted = '';
let indent = 0;
let currentLine = '';
for (let i = 0; i < html.length; i++) {
const char = html[i];
const nextChar = html[i+1];
if (char === '<' && nextChar === '/') {
indent = Math.max(0, indent - 1);
if (currentLine.trim()) {
formatted += ' '.repeat(indent * indentSize) + currentLine + '\n';
currentLine = '';
}
currentLine += char;
} else if (char === '<') {
if (currentLine.trim()) {
formatted += ' '.repeat(indent * indentSize) + currentLine + '\n';
currentLine = '';
}
currentLine += char;
if (nextChar !== '!' && nextChar !== '?') {
indent++;
}
} else if (char === '>') {
currentLine += char;
formatted += ' '.repeat(Math.max(0, indent - 1) * indentSize) + currentLine + '\n';
currentLine = '';
} else {
currentLine += char;
}
}
return formatted.trim();
case 'css':
let css = code;
let cssIndent = 0;
let cssResult = '';
css = css.replace(/([{}])/g, '\n$1\n')
.replace(/([;])\s*/g, '$1\n')
.replace(/\n+/g, '\n');
const cssLines = css.split('\n');
for (const line of cssLines) {
const trimmed = line.trim();
if (!trimmed) continue;
if (trimmed === '}') {
cssIndent--;
}
cssResult += ' '.repeat(cssIndent * indentSize) + trimmed + '\n';
if (trimmed.endsWith('{')) {
cssIndent++;
}
}
return cssResult.trim();
case 'js':
let js = code;
let jsIndent = 0;
let jsResult = '';
js = js.replace(/([{}\[\]])/g, '\n$1\n')
.replace(/([;,])\s*/g, '$1\n')
.replace(/\n+/g, '\n');
const lines = js.split('\n');
for (const line of lines) {
const trimmed = line.trim();
if (!trimmed) continue;
if (trimmed.endsWith('}') || trimmed.endsWith(']')) {
jsIndent--;
}
jsResult += ' '.repeat(jsIndent * indentSize) + trimmed + '\n';
if (trimmed.endsWith('{') || trimmed.endsWith('[')) {
jsIndent++;
}
}
return jsResult.trim();
case 'sql':
let sql = code.toUpperCase();
const keywords = ['SELECT', 'FROM', 'WHERE', 'JOIN', 'INNER JOIN', 'LEFT JOIN', 'RIGHT JOIN', 'ORDER BY', 'GROUP BY', 'HAVING', 'INSERT', 'UPDATE', 'DELETE', 'CREATE', 'ALTER', 'DROP'];
keywords.forEach(keyword => {
const regex = new RegExp(`\\b${keyword}\\b`, 'gi');
sql = sql.replace(regex, `\n${keyword}`);
});
return sql.split('\n').map(line => line.trim()).filter(line => line).join('\n');
default:
return code;
}
} catch (e) {
return `格式化错误: ${e.message}`;
}
}
// 代码压缩工具函数
function minifyCode(code, type) {
try {
code = code.trim();
switch(type.toLowerCase()) {
case 'json':
try {
const parsed = JSON.parse(code);
return JSON.stringify(parsed);
} catch (e) {
throw new Error(`JSON解析错误: ${e.message}`);
}
case 'html':
return code.replace(/\s+/g, ' ')
.replace(/<!--[\s\S]*?-->/g, '')
.replace(/>\s+</g, '><')
.trim();
case 'css':
return code.replace(/\/\*[\s\S]*?\*\//g, '')
.replace(/\s+/g, ' ')
.replace(/\s*([{};:,])\s*/g, '$1')
.replace(/;}/g, '}')
.trim();
case 'js':
return code.replace(/\/\/.*|\/\*[\s\S]*?\*\//g, '')
.replace(/\s+/g, ' ')
.replace(/\s*([=+\-*\/%&|^~!<>?:;,{}()[\]])\s*/g, '$1')
.replace(/;}/g, '}')
.trim();
case 'sql':
return code.replace(/\s+/g, ' ')
.replace(/--.*$/gm, '')
.replace(/\/\*[\s\S]*?\*\//g, '')
.trim();
default:
return code;
}
} catch (e) {
return `压缩错误: ${e.message}`;
}
}
// 检测代码类型函数
function detectCodeType(code) {
code = code.trim();
try {
JSON.parse(code);
return 'json';
} catch (e) {}
if (code.startsWith('<') || code.match(/<[a-z][\s\S]*>/i)) {
return 'html';
}
if (code.match(/(^|\}|\{)[^{}]*\{[^{}]*\}/) ||
code.match(/\.([a-z][\w-]*)\s*\{|\#([a-z][\w-]*)\s*\{|@(media|keyframes|import)/i)) {
return 'css';
}
if (code.match(/\b(SELECT|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP|FROM|WHERE|JOIN)\b/i)) {
return 'sql';
}
if (code.match(/function\s*\(|=>|\b(let|const|var)\s+\w+\s*=|console\.log|import\s+|export\s+/)) {
return 'js';
}
return 'text';
}
// 打字机效果函数
function typeWriterEffect(element, text, speed = 10) {
return new Promise((resolve) => {
let i = 0;
const typing = () => {
if (i < text.length) {
element.textContent += text.charAt(i);
i++;
setTimeout(typing, speed);
} else {
resolve();
}
};
typing();
});
}
// 添加AI输出行
async function addAILine(text, useTypewriter = true) {
const line = document.createElement('div');
line.className = 'line';
const lineContent = document.createElement('div');
lineContent.className = 'line-content ai-output';
lineContent.textContent = '藤原: ';
line.appendChild(lineContent);
editorContent.appendChild(line);
editorContent.scrollTop = editorContent.scrollHeight;
if (useTypewriter) {
await typeWriterEffect(lineContent, text);
} else {
lineContent.textContent = '藤原: ' + text;
}
return line;
}
// 添加用户输入行
function addUserLine(text) {
const line = document.createElement('div');
line.className = 'line';
const lineContent = document.createElement('div');
lineContent.className = 'line-content user-input';
lineContent.textContent = `> ${text}`;
line.appendChild(lineContent);
editorContent.appendChild(line);
editorContent.scrollTop = editorContent.scrollHeight;
return line;
}
// 清空终端
function clearTerminal() {
const lines = document.querySelectorAll('.line');
lines.forEach(line => {
const content = line.querySelector('.line-content').textContent;
if (!content.includes('// 个人信息配置') &&
!content.includes('const profile') &&
!content.includes('name:') &&
!content.includes('title:') &&
!content.includes('contact:') &&
!content.includes('email:') &&
!content.includes('website:') &&
!content.includes('FileCodeBox:') &&
!content.includes('links:') &&
!content.includes('travel blog:') &&
!content.includes('birthday:') &&
!content.includes('motto:') &&
!content.includes('copyright:') &&
!content.includes('};') &&
!content.includes('// 终端交互') &&
!content.includes('console.log')) {
line.remove();
}
});
// 移除其他组件
const containers = document.querySelectorAll('.video-container, .tool-container, .search-results, .code-formatter-container, .ping-result, .code-result');
containers.forEach(container => container.remove());
}
// URL提取函数
function extractURL(text) {
try {
const urlRegex = /(https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*))/g;
const matches = text.match(urlRegex);
return matches ? matches[0] : null;
} catch (e) {
console.error('URL提取错误:', e);
return null;
}
}
// 保存命令历史
function saveToHistory(command) {
if (commandHistoryArray.length === 0 || commandHistoryArray[commandHistoryArray.length - 1] !== command) {
commandHistoryArray.push(command);
if (commandHistoryArray.length > 50) {
commandHistoryArray.shift();
}
localStorage.setItem('commandHistory', JSON.stringify(commandHistoryArray));
}
historyIndex = -1;
}
// 显示命令历史
function showCommandHistory() {
if (commandHistoryArray.length === 0) {
addAILine('暂无命令历史记录');
return;
}
addAILine('命令历史记录:');
commandHistoryArray.slice().reverse().forEach((cmd, index) => {
addAILine(`${commandHistoryArray.length - index}. ${cmd}`, false);
});
}
// AI对话功能
async function sendMessage(message) {
if (!message) return;
const thinkingLine = document.createElement('div');
thinkingLine.className = 'line';
const thinkingContent = document.createElement('div');
thinkingContent.className = 'line-content ai-output';
thinkingContent.innerHTML = '藤原: 正在思考中... <span class="loader"></span>';
thinkingLine.appendChild(thinkingContent);
editorContent.appendChild(thinkingLine);
editorContent.scrollTop = editorContent.scrollHeight;
try {
const endpoint = `${API_CONFIG.endpoints.ai}?id=${API_CONFIG.id}&key=${API_CONFIG.key}&words=${encodeURIComponent(message)}`;
const response = await fetch(endpoint);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
thinkingLine.remove();
if (data.code === 200 && data.msg) {
const replyLine = document.createElement('div');
replyLine.className = 'line';
const replyContent = document.createElement('div');
replyContent.className = 'line-content ai-output';
replyContent.textContent = '藤原: ';
replyLine.appendChild(replyContent);
editorContent.appendChild(replyLine);
editorContent.scrollTop = editorContent.scrollHeight;
await typeWriterEffect(replyContent, data.msg);
} else {
addAILine(`AI回复失败: ${data.msg || '未知错误'}`, false);
}
} catch (error) {
thinkingLine.remove();
addAILine(`AI服务暂时不可用: ${error.message}`, false);
console.error('AI API错误:', error);
}
}
// 视频解析功能
async function parseVideo(url) {
if (!url) {
addAILine('请提供视频URL', false);
return;
}
if (!isSupportedVideoUrl(url)) {
addAILine('不支持的视频平台,支持的平台:爱奇艺、腾讯视频、优酷、芒果TV、哔哩哔哩等', false);
return;
}
totalParseCount++;
updateParseStats();
addAILine('正在解析视频,请稍候...', false);
// 创建视频容器
const videoContainer = document.createElement('div');
videoContainer.className = 'video-container';
const videoPlayer = document.createElement('div');
videoPlayer.className = 'video-player';
const videoControls = document.createElement('div');
videoControls.className = 'video-controls';
videoContainer.appendChild(videoPlayer);
videoContainer.appendChild(videoControls);
editorContent.appendChild(videoContainer);
// 创建线路按钮
videoApis.forEach((api, index) => {
const button = document.createElement('button');
button.className = 'video-button';
button.textContent = api.name;
button.onclick = () => {
// 禁用所有按钮
videoControls.querySelectorAll('.video-button').forEach(btn => btn.disabled = true);
button.disabled = false;
const iframe = document.createElement('iframe');
iframe.src = api.url + encodeURIComponent(url);
iframe.allowFullscreen = true;
iframe.onload = () => {
videoControls.querySelectorAll('.video-button').forEach(btn => btn.disabled = false);
};
videoPlayer.innerHTML = '';
videoPlayer.appendChild(iframe);
successParseCount++;
updateParseStats();
addAILine(`已切换到${api.name}`, false);
};
videoControls.appendChild(button);
});
// 默认使用第一个线路
const defaultIframe = document.createElement('iframe');
defaultIframe.src = videoApis[0].url + encodeURIComponent(url);
defaultIframe.allowFullscreen = true;
videoPlayer.appendChild(defaultIframe);
addAILine(`视频解析完成!已为您提供${videoApis.length}条解析线路`, false);
successParseCount++;
updateParseStats();
}
// 短视频解析功能
async function parseShortVideo(url) {
if (!url) {
addAILine('请提供短视频URL', false);
return;
}
totalParseCount++;
updateParseStats();
addAILine('正在解析短视频,请稍候...', false);
try {
const endpoint = `${API_CONFIG.endpoints.shortVideo}?url=${encodeURIComponent(url)}`;
const response = await fetch(endpoint);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
if (data.code === 200 && data.data) {
const videoData = data.data;
// 创建视频容器
const videoContainer = document.createElement('div');
videoContainer.className = 'video-container';
const videoPlayer = document.createElement('div');
videoPlayer.className = 'video-player';
const videoControls = document.createElement('div');
videoControls.className = 'video-controls';
// 创建视频元素
const video = document.createElement('video');
video.src = videoData.url || videoData.video_url;
video.controls = true;
video.style.width = '100%';
video.style.height = '100%';
videoPlayer.appendChild(video);
videoContainer.appendChild(videoPlayer);
videoContainer.appendChild(videoControls);
// 添加下载按钮
const downloadBtn = document.createElement('button');
downloadBtn.className = 'video-button';
downloadBtn.textContent = '📥 下载视频';
downloadBtn.onclick = () => {
const a = document.createElement('a');
a.href = videoData.url || videoData.video_url;
a.download = videoData.title || 'video';
a.click();
};
videoControls.appendChild(downloadBtn);
// 添加复制链接按钮
const copyBtn = document.createElement('button');
copyBtn.className = 'video-button';
copyBtn.textContent = '📋 复制链接';
copyBtn.onclick = () => {
navigator.clipboard.writeText(videoData.url || videoData.video_url);
addAILine('视频链接已复制到剪贴板', false);
};
videoControls.appendChild(copyBtn);
editorContent.appendChild(videoContainer);
addAILine(`短视频解析成功!`, false);
if (videoData.title) addAILine(`标题: ${videoData.title}`, false);
if (videoData.author) addAILine(`作者: ${videoData.author}`, false);
successParseCount++;
updateParseStats();
} else {
addAILine(`短视频解析失败: ${data.msg || '未知错误'}`, false);
}
} catch (error) {
addAILine(`短视频解析失败: ${error.message}`, false);
console.error('短视频解析错误:', error);
}
}
// Ping测试功能
async function pingTest(url) {
if (!url) {
addAILine('请提供要测试的网站或IP地址', false);
return;
}
addAILine('正在进行Ping测试,请稍候...', false);
try {
const endpoint = `${API_CONFIG.endpoints.ping}?id=${API_CONFIG.id}&key=${API_CONFIG.key}&url=${encodeURIComponent(url)}`;
const response = await fetch(endpoint);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
if (data.code === 200 && data.data) {
const pingData = data.data;
// 创建ping结果容器
const pingResult = document.createElement('div');
pingResult.className = 'ping-result';
let resultClass = 'ping-success';
let statusText = '正常';
if (pingData.time > 200) {
resultClass = 'ping-warning';
statusText = '较慢';
}
if (pingData.time > 500) {
resultClass = 'ping-error';
statusText = '很慢';
}
pingResult.innerHTML = `
<div class="${resultClass}">
<strong>🌐 Ping测试结果:</strong><br>
📍 目标: ${url}<br>
⏱️ 延迟: ${pingData.time}ms<br>
📊 状态: ${statusText}<br>
🕒 测试时间: ${new Date().toLocaleString()}
</div>
`;
editorContent.appendChild(pingResult);
addAILine(`Ping测试完成!延迟: ${pingData.time}ms (${statusText})`, false);
} else {
addAILine(`Ping测试失败: ${data.msg || '未知错误'}`, false);
}
} catch (error) {
addAILine(`Ping测试失败: ${error.message}`, false);
console.error('Ping测试错误:', error);
}
}
// 搜索功能
async function searchWeb(keyword) {
if (!keyword) {
addAILine('请提供搜索关键词', false);
return;
}
addAILine('正在搜索,请稍候...', false);
try {
const endpoint = `${API_CONFIG.endpoints.search}?id=${API_CONFIG.id}&key=${API_CONFIG.key}&words=${encodeURIComponent(keyword)}`;
const response = await fetch(endpoint);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
if (data.code === 200 && data.data && data.data.length > 0) {
// 创建搜索结果容器
const searchResults = document.createElement('div');
searchResults.className = 'search-results';
data.data.slice(0, 5).forEach((item, index) => {
const searchItem = document.createElement('div');
searchItem.className = 'search-item';
searchItem.innerHTML = `
<div class="search-title">${index + 1}. ${item.title || '无标题'}</div>
<div class="search-url">${item.url || '无链接'}</div>
<div class="search-description">${item.description || '无描述'}</div>
`;
searchResults.appendChild(searchItem);
});
editorContent.appendChild(searchResults);
addAILine(`搜索完成!找到 ${data.data.length} 个相关结果`, false);
} else {
addAILine(`搜索失败: ${data.msg || '未找到相关结果'}`, false);
}
} catch (error) {
addAILine(`搜索失败: ${error.message}`, false);
console.error('搜索错误:', error);
}
}
// 图片格式转换功能
function createImageConverter() {
const container = document.createElement('div');
container.className = 'tool-container';
const header = document.createElement('div');
header.className = 'tool-header';
header.innerHTML = `
<div class="tool-title">🖼️ 图片格式转换器</div>
<button class="tool-close" onclick="this.closest('.tool-container').remove()">✕</button>
`;
const content = document.createElement('div');
content.className = 'tool-content';
const converter = document.createElement('div');
converter.className = 'image-converter';
// 上传区域
const uploadArea = document.createElement('div');
uploadArea.className = 'image-upload-area';
uploadArea.innerHTML = `
<div>📁 点击选择图片或拖拽图片到此处</div>
<div style="font-size: 12px; color: #666; margin-top: 5px;">支持 JPG, PNG, GIF, WebP, BMP 格式</div>
<input type="file" accept="image/*" style="display: none;">
`;
// 格式选择器
const formatSelector = document.createElement('div');
formatSelector.className = 'format-selector';
formatSelector.innerHTML = `
<button class="format-btn active" data-format="png">PNG</button>
<button class="format-btn" data-format="jpg">JPG</button>
<button class="format-btn" data-format="webp">WebP</button>
<button class="format-btn" data-format="bmp">BMP</button>
`;
// 预览区域
const previewArea = document.createElement('div');
previewArea.innerHTML = '<div style="text-align: center; color: #666; padding: 20px;">暂无图片</div>';
converter.appendChild(uploadArea);
converter.appendChild(formatSelector);
converter.appendChild(previewArea);
content.appendChild(converter);
container.appendChild(header);
container.appendChild(content);
// 事件处理
const fileInput = uploadArea.querySelector('input[type="file"]');
let selectedFormat = 'png';
uploadArea.addEventListener('click', () => fileInput.click());
uploadArea.addEventListener('dragover', (e) => {
e.preventDefault();
uploadArea.classList.add('dragover');
});
uploadArea.addEventListener('dragleave', () => {
uploadArea.classList.remove('dragover');
});
uploadArea.addEventListener('drop', (e) => {
e.preventDefault();
uploadArea.classList.remove('dragover');
const files = e.dataTransfer.files;
if (files.length > 0) {
handleImageFile(files[0]);
}
});
fileInput.addEventListener('change', (e) => {
if (e.target.files.length > 0) {
handleImageFile(e.target.files[0]);
}
});
formatSelector.addEventListener('click', (e) => {
if (e.target.classList.contains('format-btn')) {
formatSelector.querySelectorAll('.format-btn').forEach(btn => btn.classList.remove('active'));
e.target.classList.add('active');
selectedFormat = e.target.dataset.format;
}
});
function handleImageFile(file) {
if (!file.type.startsWith('image/')) {
addAILine('请选择有效的图片文件', false);
return;
}
const reader = new FileReader();
reader.onload = (e) => {
const img = document.createElement('img');
img.src = e.target.result;
img.className = 'image-preview';
const infoDiv = document.createElement('div');
infoDiv.style.cssText = 'font-size: 12px; color: #666; margin: 10px 0;';
infoDiv.textContent = `文件名: ${file.name} | 大小: ${(file.size / 1024).toFixed(2)} KB`;
const convertBtn = document.createElement('button');
convertBtn.className = 'tool-btn';
convertBtn.textContent = `🔄 转换为 ${selectedFormat.toUpperCase()}`;
convertBtn.style.marginTop = '10px';
convertBtn.onclick = () => convertImage(img, selectedFormat, file.name);
previewArea.innerHTML = '';
previewArea.appendChild(img);
previewArea.appendChild(infoDiv);
previewArea.appendChild(convertBtn);
};
reader.readAsDataURL(file);
}
function convertImage(img, format, originalName) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
// 如果转换为JPG,先填充白色背景
if (format === 'jpg') {
ctx.fillStyle = '#FFFFFF';
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
ctx.drawImage(img, 0, 0);
const mimeType = format === 'jpg' ? 'image/jpeg' : `image/${format}`;
const quality = format === 'jpg' ? 0.9 : undefined;
canvas.toBlob((blob) => {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
const baseName = originalName.split('.')[0];
a.download = `${baseName}_converted.${format}`;
a.click();
URL.revokeObjectURL(url);
const newSize = (blob.size / 1024).toFixed(2);
addAILine(`图片已转换为 ${format.toUpperCase()} 格式并开始下载 (${newSize} KB)`, false);
}, mimeType, quality);
}
editorContent.appendChild(container);
editorContent.scrollTop = editorContent.scrollHeight;
}
// 文件管理功能
function createFileManager() {
const container = document.createElement('div');
container.className = 'tool-container';
const header = document.createElement('div');
header.className = 'tool-header';
header.innerHTML = `
<div class="tool-title">📁 文件管理器</div>
<button class="tool-close" onclick="this.closest('.tool-container').remove()">✕</button>
`;
const content = document.createElement('div');
content.className = 'tool-content';
const manager = document.createElement('div');
manager.className = 'file-manager';
// 文件列表
const fileList = document.createElement('div');
fileList.className = 'file-list';
// 新建文件区域
const createArea = document.createElement('div');
createArea.innerHTML = `
<div style="display: flex; gap: 10px; margin-bottom: 15px;">
<input type="text" placeholder="文件名" class="tool-input" id="newFileName" style="flex: 1;">
<button class="tool-btn" onclick="createNewFile()">📄 新建</button>
</div>
`;
manager.appendChild(createArea);
manager.appendChild(fileList);
content.appendChild(manager);
container.appendChild(header);
container.appendChild(content);
// 刷新文件列表
function refreshFileList() {
fileList.innerHTML = '';
const files = Object.keys(fileStorage);
if (files.length === 0) {
fileList.innerHTML = '<div style="text-align: center; color: #666; padding: 20px;">暂无文件</div>';
return;
}
files.forEach(filename => {
const fileItem = document.createElement('div');
fileItem.className = 'file-item';
const fileInfo = fileStorage[filename];
const size = new Blob([fileInfo.content]).size;
fileItem.innerHTML = `
<div>
<div class="file-name">📄 ${filename}</div>
<div style="font-size: 11px; color: #666;">
${(size / 1024).toFixed(2)} KB | ${new Date(fileInfo.created).toLocaleString()}
</div>
</div>
<div class="file-actions">
<button class="file-action-btn" onclick="viewFile('${filename}')">👁️</button>
<button class="file-action-btn" onclick="downloadFile('${filename}')">📥</button>
<button class="file-action-btn" onclick="deleteFile('${filename}')">🗑️</button>
</div>
`;
fileList.appendChild(fileItem);
});
}
// 全局函数
window.createNewFile = function() {
const filename = document.getElementById('newFileName').value.trim();
if (!filename) {
addAILine('请输入文件名', false);
return;
}
if (fileStorage[filename]) {
addAILine('文件已存在', false);
return;
}
fileStorage[filename] = {
content: '',
created: new Date().toISOString(),
modified: new Date().toISOString()
};
localStorage.setItem('fileStorage', JSON.stringify(fileStorage));
document.getElementById('newFileName').value = '';
refreshFileList();
addAILine(`文件 ${filename} 创建成功`, false);
};
window.viewFile = function(filename) {
const fileInfo = fileStorage[filename];
if (!fileInfo) return;
addAILine(`文件内容 (${filename}):`, false);
const codeResult = document.createElement('div');
codeResult.className = 'code-result';
codeResult.textContent = fileInfo.content || '(空文件)';
editorContent.appendChild(codeResult);
};
window.downloadFile = function(filename) {
const fileInfo = fileStorage[filename];
if (!fileInfo) return;
const blob = new Blob([fileInfo.content], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
URL.revokeObjectURL(url);
addAILine(`文件 ${filename} 下载完成`, false);
};
window.deleteFile = function(filename) {
if (confirm(`确定要删除文件 ${filename} 吗?`)) {
delete fileStorage[filename];
localStorage.setItem('fileStorage', JSON.stringify(fileStorage));
refreshFileList();
addAILine(`文件 ${filename} 删除成功`, false);
}
};
refreshFileList();
editorContent.appendChild(container);
editorContent.scrollTop = editorContent.scrollHeight;
}
// 编码/解码功能
function encodeText(type, text) {
try {
if (!encodingTools[type]) {
return `不支持的编码类型: ${type}`;
}
return encodingTools[type].encode(text);
} catch (e) {
return `编码错误: ${e.message}`;
}
}
function decodeText(type, text) {
try {
if (!encodingTools[type]) {
return `不支持的解码类型: ${type}`;
}
return encodingTools[type].decode(text);
} catch (e) {
return `解码错误: ${e.message}`;
}
}
// 显示系统统计
function showStats() {
const stats = {
totalParseCount,
successParseCount,
successRate: totalParseCount > 0 ? Math.round((successParseCount / totalParseCount) * 100) : 0,
commandHistory: commandHistoryArray.length,
currentTime: new Date().toLocaleString(),
browser: navigator.userAgent.split(' ')[0],
screenResolution: `${screen.width}x${screen.height}`,
availableMemory: navigator.deviceMemory ? navigator.deviceMemory + 'GB' : '未知',
language: navigator.language,
platform: navigator.platform,
filesStored: Object.keys(fileStorage).length,
storageUsed: JSON.stringify(fileStorage).length
};
addAILine('📊 系统统计信息:', false);
addAILine(`🎯 总解析次数: ${stats.totalParseCount}`, false);
addAILine(`✅ 成功解析次数: ${stats.successParseCount}`, false);
addAILine(`📈 成功率: ${stats.successRate}%`, false);
addAILine(`📝 命令历史记录: ${stats.commandHistory} 条`, false);
addAILine(`📁 存储文件数: ${stats.filesStored} 个`, false);
addAILine(`💾 存储空间使用: ${(stats.storageUsed / 1024).toFixed(2)} KB`, false);
addAILine(`🕒 当前时间: ${stats.currentTime}`, false);
addAILine(`🌐 浏览器: ${stats.browser}`, false);
addAILine(`📱 平台: ${stats.platform}`, false);
addAILine(`🖥️ 屏幕分辨率: ${stats.screenResolution}`, false);
addAILine(`🧠 可用内存: ${stats.availableMemory}`, false);
addAILine(`🌍 语言: ${stats.language}`, false);
}
// 显示关于信息
function showAbout() {
addAILine('🚀 关于藤原的数字终端', false);
addAILine('', false);
addAILine('👨💻 开发者: 藤原', false);
addAILine('📧 邮箱: 2083737075@qq.com', false);
addAILine('🌐 网站: http://tengyuan.icu', false);
addAILine('📝 博客: http://blog.tengyuan.icu', false);
addAILine('📦 文件盒子: http://wp.tengyuan.icu', false);
addAILine('', false);
addAILine('✨ 功能特色:', false);
addAILine('• 🎬 影视解析 - 支持多平台视频解析', false);
addAILine('• 🤖 AI对话 - 智能助手交互', false);
addAILine('• 🔧 代码工具 - 格式化、压缩、检测', false);
addAILine('• 🖼️ 图片转换 - 多格式图片转换', false);
addAILine('• 📁 文件管理 - 本地文件存储管理', false);
addAILine('• 🌐 网络工具 - Ping测试、搜索功能', false);
addAILine('• 🔐 编码工具 - Base64、URL、HTML编解码', false);
addAILine('', false);
addAILine('💡 座右铭: "以清简代码,筑玖维数字宇宙。"', false);
addAILine(`© 2017-${new Date().getFullYear()} 藤原 版权所有`, false);
}
// 显示当前时间
function showTime() {
const now = new Date();
const timeString = now.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
weekday: 'long'
});
addAILine(`🕒 当前时间: ${timeString}`, false);
addAILine(`🌍 时区: ${Intl.DateTimeFormat().resolvedOptions().timeZone}`, false);
addAILine(`📅 Unix时间戳: ${Math.floor(now.getTime() / 1000)}`, false);
}
// 文件操作函数
function saveFile(filename, content) {
if (!filename) {
addAILine('请提供文件名', false);
return;
}
fileStorage[filename] = {
content: content || '',
created: fileStorage[filename] ? fileStorage[filename].created : new Date().toISOString(),
modified: new Date().toISOString()
};
localStorage.setItem('fileStorage', JSON.stringify(fileStorage));
addAILine(`文件 ${filename} 保存成功`, false);
}
function loadFile(filename) {
if (!filename) {
addAILine('请提供文件名', false);
return;
}
const fileInfo = fileStorage[filename];
if (!fileInfo) {
addAILine(`文件 ${filename} 不存在`, false);
return;
}
addAILine(`文件 ${filename} 内容:`, false);
const codeResult = document.createElement('div');
codeResult.className = 'code-result';
codeResult.textContent = fileInfo.content || '(空文件)';
editorContent.appendChild(codeResult);
addAILine(`文件大小: ${(new Blob([fileInfo.content]).size / 1024).toFixed(2)} KB`, false);
addAILine(`创建时间: ${new Date(fileInfo.created).toLocaleString()}`, false);
addAILine(`修改时间: ${new Date(fileInfo.modified).toLocaleString()}`, false);
}
function deleteFileByName(filename) {
if (!filename) {
addAILine('请提供文件名', false);
return;
}
if (!fileStorage[filename]) {
addAILine(`文件 ${filename} 不存在`, false);
return;
}
delete fileStorage[filename];
localStorage.setItem('fileStorage', JSON.stringify(fileStorage));
addAILine(`文件 ${filename} 删除成功`, false);
}
// 主命令处理函数
async function processCommand(input) {
const command = input.trim().toLowerCase();
const parts = input.trim().split(' ');
const cmd = parts[0].toLowerCase();
const args = parts.slice(1).join(' ');
// 保存到历史记录
saveToHistory(input.trim());
// 添加用户输入行
addUserLine(input);
// 处理不同命令
switch (cmd) {
case 'help':
addAILine(helpText, false);
break;
case 'clear':
clearTerminal();
addAILine('终端已清空', false);
break;
case 'history':
showCommandHistory();
break;
case 'about':
showAbout();
break;
case 'time':
showTime();
break;
case 'format':
if (args) {
const code = args;
const type = detectCodeType(code);
const formatted = formatCode(code, type);
addAILine(`格式化结果 (${type}):`, false);
const codeResult = document.createElement('div');
codeResult.className = 'code-result';
codeResult.textContent = formatted;
editorContent.appendChild(codeResult);
} else {
addAILine('请提供要格式化的代码,例如: format {"name":"John"}', false);
}
break;
case 'minify':
if (args) {
const code = args;
const type = detectCodeType(code);
const minified = minifyCode(code, type);
addAILine(`压缩结果 (${type}):`, false);
const codeResult = document.createElement('div');
codeResult.className = 'code-result';
codeResult.textContent = minified;
editorContent.appendChild(codeResult);
} else {
addAILine('请提供要压缩的代码,例如: minify <div><p>Hello</p></div>', false);
}
break;
case 'detect':
if (args) {
const code = args;
const type = detectCodeType(code);
addAILine(`检测到的代码类型: ${type}`, false);
} else {
addAILine('请提供要检测的代码,例如: detect SELECT * FROM users', false);
}
break;
case 'set':
if (parts[1] === 'indent' && parts[2]) {
const size = parseInt(parts[2]);
if (size >= 1 && size <= 8) {
indentSize = size;
addAILine(`缩进大小已设置为 ${size} 个空格`, false);
} else {
addAILine('缩进大小必须在1-8之间', false);
}
} else {
addAILine('无效的设置命令,使用: set indent [1-8]', false);
}
break;
case 'theme':
if (parts[1]) {
const theme = parts[1].toLowerCase();
if (['default', 'dark', 'blue'].includes(theme)) {
currentTheme = theme;
localStorage.setItem('terminalTheme', theme);
addAILine(`主题已切换为: ${theme}`, false);
// 这里可以添加主题切换逻辑
} else {
addAILine('支持的主题: default, dark, blue', false);
}
} else {
addAILine(`当前主题: ${currentTheme}`, false);
}
break;
case 'video':
if (args) {
const url = extractURL(args) || args;
await parseVideo(url);
} else {
addAILine('请提供视频URL,例如: video https://v.qq.com/x/cover/xxx.html', false);
}
break;
case 'shortvideo':
if (args) {
const url = extractURL(args) || args;
await parseShortVideo(url);
} else {
addAILine('请提供短视频URL,例如: shortvideo https://v.douyin.com/xxxxxx', false);
}
break;
case 'ping':
if (args) {
await pingTest(args);
} else {
addAILine('请提供要测试的网站或IP,例如: ping www.example.com', false);
}
break;
case 'search':
if (args) {
await searchWeb(args);
} else {
addAILine('请提供搜索关键词,例如: search JavaScript教程', false);
}
break;
case 'ai':
if (args) {
await sendMessage(args);
} else {
addAILine('请输入要对话的内容,例如: ai 你好', false);
}
break;
case 'image':
createImageConverter();
addAILine('图片格式转换器已打开,请选择图片文件', false);
break;
case 'files':
createFileManager();
addAILine('文件管理器已打开', false);
break;
case 'save':
if (parts.length >= 3) {
const filename = parts[1];
const content = parts.slice(2).join(' ');
saveFile(filename, content);
} else {
addAILine('用法: save [文件名] [内容]', false);
}
break;
case 'load':
if (parts[1]) {
loadFile(parts[1]);
} else {
addAILine('用法: load [文件名]', false);
}
break;
case 'delete':
if (parts[1]) {
deleteFileByName(parts[1]);
} else {
addAILine('用法: delete [文件名]', false);
}
break;
case 'encode':
if (parts.length >= 3) {
const type = parts[1];
const text = parts.slice(2).join(' ');
const result = encodeText(type, text);
addAILine(`编码结果 (${type}):`, false);
const codeResult = document.createElement('div');
codeResult.className = 'code-result';
codeResult.textContent = result;
editorContent.appendChild(codeResult);
} else {
addAILine('用法: encode [类型] [文本] (支持: base64, url, html)', false);
}
break;
case 'decode':
if (parts.length >= 3) {
const type = parts[1];
const text = parts.slice(2).join(' ');
const result = decodeText(type, text);
addAILine(`解码结果 (${type}):`, false);
const codeResult = document.createElement('div');
codeResult.className = 'code-result';
codeResult.textContent = result;
editorContent.appendChild(codeResult);
} else {
addAILine('用法: decode [类型] [文本] (支持: base64, url, html)', false);
}
break;
case 'stats':
showStats();
break;
default:
addAILine(`未知命令: ${cmd}`, false);
addAILine('输入 "help" 查看可用命令', false);
break;
}
}
// 输入框事件处理
userInput.addEventListener('keydown', async (e) => {
if (e.key === 'Enter') {
e.preventDefault();
const input = userInput.value.trim();
if (input) {
userInput.value = '';
await processCommand(input);
}
} else if (e.key === 'ArrowUp') {
e.preventDefault();
if (historyIndex < commandHistoryArray.length - 1) {
historyIndex++;
userInput.value = commandHistoryArray[commandHistoryArray.length - 1 - historyIndex];
}
} else if (e.key === 'ArrowDown') {
e.preventDefault();
if (historyIndex > 0) {
historyIndex--;
userInput.value = commandHistoryArray[commandHistoryArray.length - 1 - historyIndex];
} else if (historyIndex === 0) {
historyIndex = -1;
userInput.value = '';
}
} else if (e.key === 'Tab') {
e.preventDefault();
// 简单的命令自动补全
const input = userInput.value.toLowerCase();
const commands = ['help', 'clear', 'history', 'about', 'time', 'format', 'minify', 'detect', 'video', 'shortvideo', 'ping', 'search', 'ai', 'image', 'files', 'save', 'load', 'delete', 'encode', 'decode', 'stats', 'set', 'theme'];
const matches = commands.filter(cmd => cmd.startsWith(input));
if (matches.length === 1) {
userInput.value = matches[0] + ' ';
} else if (matches.length > 1) {
addAILine(`可能的命令: ${matches.join(', ')}`, false);
}
}
});
// 初始化
document.addEventListener('DOMContentLoaded', async function() {
// 初始化统计
updateParseStats();
// 点击终端区域时聚焦输入框
editorContent.addEventListener('click', () => {
if (terminalContainer.classList.contains('show')) {
userInput.focus();
}
});
// 键盘快捷键
document.addEventListener('keydown', (e) => {
// ESC 键关闭终端
if (e.key === 'Escape' && terminalContainer.classList.contains('show')) {
toggleTerminal();
}
// Ctrl/Cmd + K 清空终端
if ((e.ctrlKey || e.metaKey) && e.key === 'k' && terminalContainer.classList.contains('show')) {
e.preventDefault();
clearTerminal();
addAILine('终端已清空 (快捷键: Ctrl/Cmd+K)', false);
}
// Ctrl/Cmd + L 聚焦输入框
if ((e.ctrlKey || e.metaKey) && e.key === 'l' && terminalContainer.classList.contains('show')) {
e.preventDefault();
userInput.focus();
}
});
// 显示欢迎信息
setTimeout(() => {
if (!localStorage.getItem('terminalWelcomeShown')) {
addAILine('🎉 欢迎使用藤原的数字终端!', false);
addAILine('💡 输入 "help" 查看所有可用命令', false);
addAILine('🚀 输入 "about" 了解更多信息', false);
localStorage.setItem('terminalWelcomeShown', 'true');
}
}, 1000);
});
// 确保函数在全局作用域中可用
window.toggleTerminal = toggleTerminal;
</script>
</body>
</html>
index.html