Files

679 lines
28 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- 英文 SEO 标签 -->
<meta name="description" content="ap_ds is an ultra-lightweight Python audio library (2.5MB) for high-quality playback & precise metadata parsing of MP3, FLAC, OGG, WAV. Zero external dependencies, non-blocking architecture. Created by Dvs (DvsXT), released 2026-03-01. A precise revolution in Python audio.">
<meta name="keywords" content="Python audio library, lightweight audio player, MP3, FLAC, OGG, WAV metadata, non-blocking playback, ap_ds, DvsXT, zero dependencies, 2026 Python ecosystem">
<meta property="og:title" content="ap_ds: Ultra-Lightweight Python Audio Library (2.5MB)">
<meta property="og:description" content="Zero external deps, non-blocking playback, precise metadata parsing for MP3/FLAC/OGG/WAV. Released 2026-03-01 by Dvs (DvsXT).">
<meta property="og:type" content="software">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="ap_ds - Python Audio Library, 2.5MB">
<meta name="twitter:description" content="Solve the lightweight vs completeness contradiction in Python audio. Non-blocking, zero deps, 4 major formats.">
<!-- 中文 SEO 标签 -->
<meta name="description" lang="zh-CN" content="ap_ds 是一个超轻量级 Python 音频库(仅 2.5MB),支持 MP3、FLAC、OGG、WAV 四种主流格式的高质量播放和精确元数据解析。零外部 Python 依赖,非阻塞播放架构让 GUI 应用流畅运行。由 Dvs (DvsXT) 创作,发布于 2026-03-01,是 Python 音频领域的精准革命。">
<meta name="keywords" lang="zh-CN" content="Python音频库, 轻量级音频播放, MP3, FLAC, OGG, WAV元数据解析, 非阻塞播放, ap_ds, DvsXT, 零依赖, 2026 Python生态">
<meta property="og:title" content="ap_ds:超轻量级 Python 音频库 (2.5MB)">
<meta property="og:description" lang="zh-CN" content="零外部依赖,非阻塞播放,精准解析 MP3/FLAC/OGG/WAV。2026-03-01 由 Dvs (DvsXT) 发布。终结 Python 音频库的「完整性与轻量化」矛盾。">
<!-- 新增:官方自建代码仓库说明 -->
<meta name="description" content="This domain is the official self-hosted code repository for ap_ds. Direct source, stable releases, and authoritative documentation.">
<meta name="description" lang="zh-CN" content="本域名是 ap_ds 官方自建代码仓库。提供直接源代码、稳定版本及权威文档。"> {% extends "base.html" %}
{% block title %}ap_ds · lightweight Python audio solution ap_ds · 轻量级Python音频库{% endblock %}
{% block extra_head %}
<link rel="canonical" href="https://apds.top" />
<link rel="me" href="https://gitee.com/dssxt/ap_ds" />
<link rel="me" href="https://gitcode.com/dvsxt/ap_ds" />
<link rel="nofollow" href="https://github.com/dvs-web/ap_ds" />
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism-tomorrow.min.css">
<script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/prism.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-python.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-bash.min.js"></script>
<style>
/* 首页自定义样式 - 基于 css.css 变量 */
.home-container {
max-width: 1280px;
margin: 0 auto;
padding: var(--repo-spacing-6) var(--repo-spacing-4);
}
/* Hero 区域 */
.hero-section {
text-align: center;
padding: var(--repo-spacing-10) 0 var(--repo-spacing-8);
background: linear-gradient(135deg, var(--repo-color-bg) 0%, var(--repo-color-bg-secondary) 100%);
border-radius: var(--repo-radius-xl);
margin-bottom: var(--repo-spacing-8);
}
.hero-title {
font-size: 3rem;
font-weight: 700;
margin-bottom: var(--repo-spacing-4);
background: linear-gradient(135deg, var(--repo-color-primary) 0%, #6366f1 100%);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.hero-subtitle {
font-size: var(--repo-font-size-xl);
color: var(--repo-color-text-secondary);
margin-bottom: var(--repo-spacing-6);
}
.version-badges {
display: flex;
justify-content: center;
gap: var(--repo-spacing-3);
flex-wrap: wrap;
margin-top: var(--repo-spacing-4);
}
/* 目录 */
.toc-section {
background: var(--repo-color-bg-secondary);
border-radius: var(--repo-radius-lg);
padding: var(--repo-spacing-6);
margin-bottom: var(--repo-spacing-8);
border-left: 4px solid var(--repo-color-primary);
}
.toc-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: var(--repo-spacing-2);
margin-top: var(--repo-spacing-4);
}
.toc-link {
color: var(--repo-color-text-secondary);
text-decoration: none;
font-size: var(--repo-font-size-sm);
padding: var(--repo-spacing-1) 0;
display: inline-block;
}
.toc-link:hover {
color: var(--repo-color-primary);
text-decoration: none;
}
/* 内容区块 */
.content-card {
background: var(--repo-color-bg);
border: 1px solid var(--repo-color-border);
border-radius: var(--repo-radius-lg);
padding: var(--repo-spacing-8);
margin-bottom: var(--repo-spacing-8);
box-shadow: var(--repo-shadow-sm);
}
.content-card h2 {
font-size: var(--repo-font-size-2xl);
font-weight: 600;
margin-bottom: var(--repo-spacing-6);
padding-bottom: var(--repo-spacing-3);
border-bottom: 2px solid var(--repo-color-border);
color: var(--repo-color-text);
}
.content-card h3 {
font-size: var(--repo-font-size-xl);
font-weight: 600;
margin-top: var(--repo-spacing-6);
margin-bottom: var(--repo-spacing-4);
color: var(--repo-color-text);
}
.content-card h4 {
font-size: var(--repo-font-size-lg);
font-weight: 600;
margin-top: var(--repo-spacing-4);
margin-bottom: var(--repo-spacing-3);
color: var(--repo-color-text);
}
/* 特性网格 */
.feature-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: var(--repo-spacing-5);
margin-bottom: var(--repo-spacing-8);
}
.feature-card {
background: var(--repo-color-bg-secondary);
border-radius: var(--repo-radius-lg);
padding: var(--repo-spacing-5);
border: 1px solid var(--repo-color-border);
transition: all 0.2s ease;
}
.feature-card:hover {
transform: translateY(-2px);
box-shadow: var(--repo-shadow-md);
border-color: var(--repo-color-primary);
}
.feature-icon {
font-size: 2rem;
margin-bottom: var(--repo-spacing-3);
}
.feature-title {
font-weight: 600;
font-size: var(--repo-font-size-lg);
margin-bottom: var(--repo-spacing-2);
color: var(--repo-color-text);
}
.feature-desc {
color: var(--repo-color-text-secondary);
font-size: var(--repo-font-size-sm);
}
/* 对比表格 */
.comparison-table {
width: 100%;
border-collapse: collapse;
margin: var(--repo-spacing-4) 0;
}
.comparison-table th,
.comparison-table td {
border: 1px solid var(--repo-color-border);
padding: var(--repo-spacing-3) var(--repo-spacing-4);
text-align: left;
}
.comparison-table th {
background: var(--repo-color-bg-secondary);
font-weight: 600;
}
/* 提示框 */
.note-box {
background: #eef2ff;
border-left: 4px solid var(--repo-color-primary);
border-radius: var(--repo-radius-md);
padding: var(--repo-spacing-4) var(--repo-spacing-6);
margin: var(--repo-spacing-4) 0;
color: #1e40af;
}
.warning-box {
background: #fffbeb;
border-left: 4px solid #f59e0b;
border-radius: var(--repo-radius-md);
padding: var(--repo-spacing-4) var(--repo-spacing-6);
margin: var(--repo-spacing-4) 0;
color: #92400e;
}
.success-box {
background: #ecfdf5;
border-left: 4px solid #10b981;
border-radius: var(--repo-radius-md);
padding: var(--repo-spacing-4) var(--repo-spacing-6);
margin: var(--repo-spacing-4) 0;
color: #065f46;
}
/* 代码块 */
.code-block {
position: relative;
background: #0f172a;
border-radius: var(--repo-radius-lg);
margin: var(--repo-spacing-4) 0;
overflow: hidden;
}
.code-block pre {
margin: 0;
padding: var(--repo-spacing-5);
overflow-x: auto;
background: transparent !important;
}
.code-block code {
font-family: var(--repo-font-family-mono);
font-size: var(--repo-font-size-sm);
color: #f8fafc;
}
.copy-btn {
position: absolute;
top: 12px;
right: 16px;
background: #334155;
color: #f1f5f9;
border: none;
border-radius: var(--repo-radius-full);
padding: 4px 14px;
font-size: var(--repo-font-size-xs);
cursor: pointer;
transition: 0.2s;
opacity: 0.7;
}
.copy-btn:hover {
opacity: 1;
background: #475569;
}
.copy-btn.copied {
background: #059669;
}
/* 许可证区域 */
.license-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: var(--repo-spacing-4);
margin-top: var(--repo-spacing-6);
}
.license-card {
background: var(--repo-color-bg-secondary);
border-radius: var(--repo-radius-lg);
padding: var(--repo-spacing-5);
border: 1px solid var(--repo-color-border);
}
.license-card h4 {
margin-top: 0;
margin-bottom: var(--repo-spacing-3);
}
/* 公告区域 */
.announcement-content {
line-height: 1.7;
}
.announcement-content h1,
.announcement-content h2,
.announcement-content h3 {
margin-top: var(--repo-spacing-5);
margin-bottom: var(--repo-spacing-3);
}
.announcement-content h1 { font-size: var(--repo-font-size-xl); border-bottom: 1px solid var(--repo-color-border); padding-bottom: var(--repo-spacing-2); }
.announcement-content h2 { font-size: var(--repo-font-size-lg); border-bottom: 1px solid var(--repo-color-border); padding-bottom: var(--repo-spacing-2); }
.announcement-content h3 { font-size: var(--repo-font-size-base); }
.announcement-content p { margin-bottom: var(--repo-spacing-4); }
.announcement-content ul, .announcement-content ol { padding-left: var(--repo-spacing-6); margin-bottom: var(--repo-spacing-4); }
.announcement-content code {
background: var(--repo-color-bg-tertiary);
padding: 0.2em 0.4em;
border-radius: var(--repo-radius-sm);
font-size: 0.9em;
}
.announcement-content pre {
background: #0f172a;
padding: var(--repo-spacing-4);
border-radius: var(--repo-radius-md);
overflow-x: auto;
margin: var(--repo-spacing-4) 0;
}
.announcement-content pre code {
background: none;
padding: 0;
color: #f8fafc;
}
.announcement-content blockquote {
border-left: 4px solid var(--repo-color-border);
padding-left: var(--repo-spacing-4);
margin: var(--repo-spacing-4) 0;
color: var(--repo-color-text-secondary);
}
/* 响应式 */
@media (max-width: 768px) {
.hero-title {
font-size: 2rem;
}
.content-card {
padding: var(--repo-spacing-5);
}
.feature-grid {
grid-template-columns: 1fr;
}
}
</style>
{% endblock %}
{% block content %}
<div class="home-container">
<!-- Hero 区域 -->
<div class="hero-section">
<h1 class="hero-title" id="hero-title">ap_ds: 轻量级 Python 音频革命</h1>
<p class="hero-subtitle" id="hero-subtitle">2.5MB 终结 160MB 臃肿时代</p>
<div class="version-badges" id="version-badges">
<span class="repo-tag repo-tag--primary">v3.0.0 LTS</span>
<span class="repo-tag repo-tag--success">仅 2.5MB</span>
<span class="repo-tag repo-tag--warning">跨平台 W/M/L</span>
</div>
</div>
<!-- 目录 -->
<div class="toc-section">
<h3 class="repo-text-lg repo-font-semibold repo-mb-4"><i class="fa fa-list-ul" style="margin-right: 8px; color: var(--repo-color-primary);"></i>目录</h3>
<div class="toc-grid">
<a href="#introduction" class="toc-link">1. 项目介绍</a>
<a href="#features" class="toc-link">2. 核心特性</a>
<a href="#comparison" class="toc-link">3. 技术对比</a>
<a href="#installation" class="toc-link">4. 安装与使用</a>
<a href="#license" class="toc-link">5. 开源许可证</a>
<a href="#faq" class="toc-link">6. 常见问题</a>
<a href="#contact" class="toc-link">7. 联系与支持</a>
<a href="#announcement" class="toc-link">8. 最新公告</a>
</div>
</div>
<!-- 1. 项目介绍 -->
<div class="content-card" id="introduction">
<h2>1. 项目介绍</h2>
<div class="note-box">
<p><strong>📋 官方信息</strong></p>
<p>项目名称:ap_ds</p>
<p>官方网站:<a href="https://apds.top" style="color: var(--repo-color-primary);">https://apds.top</a></p>
<p>PyPI:<a href="https://pypi.org/project/ap_ds/" style="color: var(--repo-color-primary);">https://pypi.org/project/ap_ds/</a></p>
<p>开发者:Dvs (DvsXT)</p>
</div>
<p>ap_ds 是一个极轻量级(2.5MB)的 Python 音频库,用于播放和精确解析 MP3、FLAC、OGG 和 WAV 文件。它没有外部 Python 依赖,仅使用 Python 标准库,为非阻塞播放提供平滑的 GUI 应用程序体验。</p>
<div class="success-box">
<p><strong>🎉 v3.0.0 LTS 长期支持版本</strong></p>
<p>首个长期支持版本,提供 <strong>永久免费技术支持</strong>,哈希验证下载,确定性资源清理。</p>
</div>
</div>
<!-- 2. 核心特性 -->
<div class="content-card" id="features">
<h2>2. 核心特性</h2>
<div class="feature-grid">
<div class="feature-card">
<div class="feature-icon">⚡</div>
<div class="feature-title">极致轻量</div>
<div class="feature-desc">Windows 2.5MB · macOS 3.36MB · Linux 就绪</div>
</div>
<div class="feature-card">
<div class="feature-icon">🎵</div>
<div class="feature-title">四种格式</div>
<div class="feature-desc">MP3 / FLAC / OGG / WAV</div>
</div>
<div class="feature-card">
<div class="feature-icon">📊</div>
<div class="feature-title">精确元数据</div>
<div class="feature-desc">WAV/FLAC 100% 准确</div>
</div>
<div class="feature-card">
<div class="feature-icon">▶️</div>
<div class="feature-title">非阻塞播放</div>
<div class="feature-desc">完美适配 GUI 应用</div>
</div>
</div>
<div class="grid" style="display: grid; grid-template-columns: 1fr 1fr; gap: var(--repo-spacing-8);">
<div>
<h3>📦 体积对比</h3>
<ul style="list-style: none; padding-left: 0;">
<li style="margin-bottom: var(--repo-spacing-2);">🟢 <strong>ap_ds</strong> Windows: 2.5MB</li>
<li style="margin-bottom: var(--repo-spacing-2);">🍎 macOS: 3.36MB</li>
<li style="margin-bottom: var(--repo-spacing-2);">🐧 Linux: 动态链接 ~50KB</li>
<li style="margin-bottom: var(--repo-spacing-2);">🔴 FFmpeg: ≥160MB</li>
<li>🟡 Pygame + 解析库: 臃肿且功能不全</li>
</ul>
</div>
<div>
<h3>⚙️ 为什么这么小?</h3>
<ul>
<li>专注:仅播放和解析,无编辑/转码</li>
<li>基于工业级 SDL2</li>
<li>逐字节优化</li>
<li>跨平台 W/M/L</li>
</ul>
</div>
</div>
</div>
<!-- 3. 技术对比 -->
<div class="content-card" id="comparison">
<h2>3. 技术对比</h2>
<h3>第一章:Pygame —— 游戏引擎的"音频残疾"</h3>
<div class="code-block">
<pre class="language-python"><code># Pygame 不可靠的音频时长
my_sound = pygame.mixer.Sound('my_song.mp3')
total_length = my_sound.get_length() # 仅对 WAV 可靠!</code></pre>
<button class="copy-btn" onclick="copyCode(this)"><i class="fa fa-clipboard"></i> 复制</button>
</div>
<div class="warning-box">
⚠️ Pygame 的 <code>Sound.get_length()</code> 仅对 WAV 格式正确,MP3/OGG/FLAC 返回无效值。
</div>
<h3>第二章:FFmpeg 套件 —— 160MB 的"至少"之痛</h3>
<table class="comparison-table">
<thead><tr><th>组件</th><th>功能</th><th>大小</th></tr></thead>
<tbody>
<tr><td>ffplay.exe</td><td>播放核心</td><td>≈80MB</td></tr>
<tr><td>ffprobe.exe</td><td>元数据探测</td><td>≈80MB</td></tr>
<tr><td>ffmpeg.exe</td><td>转换器</td><td>≈80MB</td></tr>
</tbody>
</table>
<div class="note-box">🔍 三个独立可执行文件,无 Python 封装,总计 ≥160MB。</div>
<h3>第三章:ap_ds 革命</h3>
<div class="success-box">
<p><strong>七大技术突破</strong></p>
<ul>
<li>✓ 2.5MB 解决 160MB 问题</li>
<li>✓ 非阻塞消除 GUI 卡顿</li>
<li>✓ 精确进度查询</li>
<li>✓ 零依赖部署</li>
<li>✓ AID 多音频管理</li>
<li>✓ SDL2 性能</li>
<li>✓ 智能 C 依赖跨平台</li>
</ul>
</div>
</div>
<!-- 4. 安装与使用 -->
<div class="content-card" id="installation">
<h2>4. 安装与使用</h2>
<div class="code-block">
<pre class="language-bash"><code>pip install ap_ds</code></pre>
<button class="copy-btn" onclick="copyCode(this)"><i class="fa fa-clipboard"></i> 复制</button>
</div>
<h3>基础示例</h3>
<div class="code-block">
<pre class="language-python"><code>from ap_ds import AudioLibrary
lib = AudioLibrary()
aid = lib.play_from_file("music.mp3")
lib.pause_audio(aid)
lib.seek_audio(aid, 30.5)
duration = lib.stop_audio(aid)</code></pre>
<button class="copy-btn" onclick="copyCode(this)"><i class="fa fa-clipboard"></i> 复制</button>
</div>
<h3>DAP 播放列表 (v2.3.0+)</h3>
<div class="code-block">
<pre class="language-python"><code>aid1 = lib.play_from_file("song1.mp3")
recordings = lib.get_dap_recordings()
lib.save_dap_to_json("my_playlist.ap-ds-dap")</code></pre>
<button class="copy-btn" onclick="copyCode(this)"><i class="fa fa-clipboard"></i> 复制</button>
</div>
<h3>淡入淡出效果 (v2.4.0+)</h3>
<div class="code-block">
<pre class="language-python"><code># 2秒淡入
lib.fadein_music(aid, loops=-1, ms=2000)
# 3秒淡出
lib.fadeout_music(ms=3000)
# 检查播放状态
if lib.is_music_playing():
print("音乐播放中")</code></pre>
<button class="copy-btn" onclick="copyCode(this)"><i class="fa fa-clipboard"></i> 复制</button>
</div>
</div>
<!-- 5. 开源许可证 -->
<div class="content-card" id="license">
<h2>5. 开源许可证</h2>
<div class="license-grid">
<div class="license-card">
<h4>✅ 您可以</h4>
<ul>
<li>商业使用</li>
<li>修改代码</li>
<li>闭源集成</li>
<li>销售解决方案</li>
<li>云服务部署</li>
</ul>
</div>
<div class="license-card">
<h4>❌ 您不可以</h4>
<ul>
<li>使用原始品牌名称</li>
<li>删除版权声明</li>
<li>用于非法用途</li>
<li>专利侵权诉讼</li>
</ul>
</div>
<div class="license-card">
<h4>👍 您应该</h4>
<ul>
<li>保留版权声明</li>
<li>标注来源归属</li>
<li>报告安全问题</li>
<li>修改版本用独立品牌</li>
</ul>
</div>
</div>
<p class="repo-text-secondary repo-text-sm repo-mt-4">详细许可证请查看 <code>AP_DS_LICENSE.MD</code> 文件。</p>
</div>
<!-- 6. 常见问题 -->
<div class="content-card" id="faq">
<h2>6. 常见问题</h2>
<div><p class="repo-font-semibold">问:公司可以将其集成到商业产品中吗?</p><div class="success-box">✅ 完全可以,无需付费、无需通知、无需授权。</div></div>
<div><p class="repo-font-semibold repo-mt-4">问:我可以修改并重新分发吗?</p><div class="success-box">✅ 可以,但必须使用独立品牌、保留版权、标注来源、提供维护者声明。</div></div>
<div><p class="repo-font-semibold repo-mt-4">问:我必须开源我的修改吗?</p><div class="warning-box">❌ 不需要,您可以闭源分发。</div></div>
<div><p class="repo-font-semibold repo-mt-4">问:在云服务中使用需要付费吗?</p><div class="warning-box">❌ 不需要,但欢迎贡献代码。</div></div>
<div><p class="repo-font-semibold repo-mt-4">问:技术支持收费吗?</p><div class="success-box">✅ 永久免费技术支持,通过 GitCode Issues 或邮件联系。</div></div>
</div>
<!-- 7. 联系与支持 -->
<div class="content-card" id="contact">
<h2>7. 联系与支持</h2>
<div class="grid" style="display: grid; grid-template-columns: 1fr 1fr; gap: var(--repo-spacing-6);">
<div style="background: var(--repo-color-bg-secondary); padding: var(--repo-spacing-5); border-radius: var(--repo-radius-lg);">
<h4>📧 授权咨询</h4>
<p>me@dvsyun.top 或 dvs6666@163.com</p>
<p class="repo-text-sm repo-text-tertiary">7个工作日内回复</p>
</div>
<div style="background: var(--repo-color-bg-secondary); padding: var(--repo-spacing-5); border-radius: var(--repo-radius-lg);">
<h4>🛠️ 技术支持</h4>
<p>GitCode Issues · 官方文档 · 邮件支持</p>
<p class="repo-text-sm repo-text-success">✅ 永久免费</p>
</div>
</div>
<div class="repo-mt-6" style="background: var(--repo-color-bg-secondary); border-radius: var(--repo-radius-lg); padding: var(--repo-spacing-5);">
<h3>🔗 官方仓库</h3>
<div class="grid" style="display: grid; grid-template-columns: 1fr 1fr; gap: var(--repo-spacing-4); margin-top: var(--repo-spacing-3);">
<div>
<p>✅ <strong>主仓库:</strong><a href="https://gitcode.com/dvsxt/ap_ds" class="repo-text-link">GitCode</a></p>
<p>✅ <strong>国内镜像:</strong><a href="https://gitee.com/dssxt/ap_ds" class="repo-text-link">Gitee</a></p>
</div>
<div>
<p>❌ <strong>已废弃:</strong><a href="https://github.com/dvs-web/ap_ds" class="repo-text-danger">GitHub</a></p>
<p>🔗 <strong>项目主页:</strong><a href="https://apds.top" class="repo-text-link">apds.top</a></p>
</div>
</div>
</div>
</div>
<!-- 8. 最新公告 -->
<div class="content-card" id="announcement">
<h2>8. 最新公告</h2>
<div id="announcement-content" class="announcement-content">加载中...</div>
</div>
</div>
<script>
// 复制代码函数
window.copyCode = function(btn) {
const pre = btn.parentElement.querySelector('pre');
const code = pre.innerText;
navigator.clipboard.writeText(code).then(() => {
btn.classList.add('copied');
btn.innerHTML = '<i class="fa fa-check"></i> 已复制';
setTimeout(() => {
btn.classList.remove('copied');
btn.innerHTML = '<i class="fa fa-clipboard"></i> 复制';
}, 2000);
});
};
// 从后端获取版本信息
fetch('/api/version-info')
.then(res => res.json())
.then(data => {
if (data.title) document.getElementById('hero-title').innerHTML = data.title;
if (data.subtitle) document.getElementById('hero-subtitle').innerHTML = data.subtitle;
const badgesDiv = document.getElementById('version-badges');
if (data.version || data.size) {
badgesDiv.innerHTML = `
<span class="repo-tag repo-tag--primary">${data.version || 'v3.0.0 LTS'}</span>
<span class="repo-tag repo-tag--success">仅 ${data.size || '2.5MB'}</span>
<span class="repo-tag repo-tag--warning">跨平台 W/M/L</span>
`;
}
})
.catch(() => {});
// 加载最新公告
fetch('/api/latest-announcement')
.then(res => res.json())
.then(data => {
const container = document.getElementById('announcement-content');
if (data.html) {
container.innerHTML = data.html;
// 高亮代码块
if (typeof Prism !== 'undefined') {
Prism.highlightAllUnder(container);
}
// 为代码块添加复制按钮
container.querySelectorAll('pre').forEach(pre => {
if (!pre.parentElement.classList.contains('code-block')) {
const wrapper = document.createElement('div');
wrapper.className = 'code-block';
pre.parentNode.insertBefore(wrapper, pre);
wrapper.appendChild(pre);
const btn = document.createElement('button');
btn.className = 'copy-btn';
btn.innerHTML = '<i class="fa fa-clipboard"></i> 复制';
btn.onclick = function() { window.copyCode(btn); };
wrapper.appendChild(btn);
}
});
} else {
container.innerHTML = '<p class="repo-text-tertiary">暂无公告</p>';
}
})
.catch(() => {
document.getElementById('announcement-content').innerHTML = '<p class="repo-text-tertiary">无法加载公告</p>';
});
</script>
{% endblock %}