381 lines
16 KiB
HTML
381 lines
16 KiB
HTML
|
||
|
||
<!-- 英文 SEO 标签 -->
|
||
<meta name="description" content="ap_ds official code repository. Browse branches (APDSLTS001), tags (v3.0.0), view README/setup.py with syntax highlighting, search files, and download ZIP/TAR.GZ/WHL. Self-hosted, never offline.">
|
||
<meta name="keywords" content="ap_ds source code, Python audio library code, browse repository, download WHL, self-hosted git, APDSLTS001, v3.0.0 source">
|
||
<meta property="og:title" content="ap_ds Code Repository – Browse & Download Source">
|
||
<meta property="og:description" content="Official self-hosted Git-style code browser for ap_ds. Syntax-highlighted Python files, Markdown rendering, multi-format downloads.">
|
||
<meta property="og:type" content="software">
|
||
<meta name="twitter:card" content="summary">
|
||
<meta name="twitter:title" content="ap_ds Code Repository">
|
||
|
||
<!-- 中文 SEO 标签 -->
|
||
<meta name="description" lang="zh-CN" content="ap_ds 官方代码仓库。浏览分支(APDSLTS001)和版本(v3.0.0)下的所有源文件,语法高亮预览 README/setup.py,文件搜索,一键下载 ZIP/TAR.GZ/WHL。自主托管,永不掉线。">
|
||
<meta name="keywords" lang="zh-CN" content="ap_ds 源代码, Python音频库代码, 浏览仓库, 下载WHL, 自建Git仓库, APDSLTS001, v3.0.0源码">
|
||
<meta property="og:title" lang="zh-CN" content="ap_ds 代码仓库 – 浏览与下载源码">
|
||
<meta property="og:description" lang="zh-CN" content="ap_ds 官方自建代码仓库。支持语法高亮的 Python 文件预览、Markdown 渲染、多格式源码下载。">{% extends "base.html" %}
|
||
{% block content %}
|
||
|
||
{% block title %}ap_ds Code Repository – Official Self-Hosted Git Source Code & Downloads{% endblock %}<!-- 仓库头部 -->
|
||
<div class="repo-header">
|
||
<div class="repo-path">
|
||
<a href="/code">ap_ds</a>
|
||
<span class="separator">/</span>
|
||
<span>{{ current_branch if current_branch else '选择分支' }}</span>
|
||
{% if current_version %}
|
||
<span class="separator">/</span>
|
||
<span>{{ current_version }}</span>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 搜索栏 -->
|
||
<div class="search-box">
|
||
<form action="{{ url_for('search') }}" method="get" style="display: flex; gap: 8px; width: 100%;">
|
||
<input type="hidden" name="branch" value="{{ current_branch }}">
|
||
<input type="hidden" name="version" value="{{ current_version }}">
|
||
<input type="text" name="q" class="search-input" placeholder="查找文件..." value="{{ search_query or '' }}">
|
||
<button type="submit" class="btn btn-primary">搜索</button>
|
||
</form>
|
||
</div>
|
||
|
||
<div class="two-column">
|
||
<!-- 左侧边栏 -->
|
||
<div class="sidebar">
|
||
<div class="sidebar-section">
|
||
<div class="sidebar-title">📌 分支</div>
|
||
<div class="branch-selector" id="branch-selector">
|
||
<span>{{ current_branch if current_branch else '选择分支' }}</span>
|
||
<span>▼</span>
|
||
</div>
|
||
<div id="branch-menu" class="branch-menu-dropdown" style="display: none;">
|
||
{% for branch_name in branches.keys() %}
|
||
<div class="branch-menu-item" data-branch="{{ branch_name }}">{{ branch_name }}</div>
|
||
{% endfor %}
|
||
</div>
|
||
</div>
|
||
|
||
<div class="sidebar-section">
|
||
<div class="sidebar-title">🏷️ 版本</div>
|
||
<div class="branch-selector" id="version-selector">
|
||
<span>{{ current_version if current_version else '选择版本' }}</span>
|
||
<span>▼</span>
|
||
</div>
|
||
<div id="version-menu" class="branch-menu-dropdown" style="display: none;">
|
||
{% if current_branch and branches[current_branch] %}
|
||
{% for version in branches[current_branch] %}
|
||
<div class="branch-menu-item" data-version="{{ version.name }}">{{ version.name }}</div>
|
||
{% endfor %}
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
|
||
<div class="sidebar-section">
|
||
<div class="sidebar-title">📦 下载</div>
|
||
<div style="display: flex; flex-direction: column; gap: 8px;">
|
||
<a href="{{ url_for('download_zip', branch=current_branch, version=current_version) if current_branch and current_version else '#' }}" class="btn btn-secondary {% if not current_branch or not current_version %}disabled{% endif %}" {% if not current_branch or not current_version %}style="opacity:0.5; pointer-events:none;"{% endif %}>
|
||
📥 下载 ZIP
|
||
</a>
|
||
<a href="{{ url_for('download_tar', branch=current_branch, version=current_version) if current_branch and current_version else '#' }}" class="btn btn-secondary {% if not current_branch or not current_version %}disabled{% endif %}" {% if not current_branch or not current_version %}style="opacity:0.5; pointer-events:none;"{% endif %}>
|
||
📥 下载 TAR.GZ
|
||
</a>
|
||
<a href="{{ url_for('download_whl', version=current_version) if current_version else '#' }}" class="btn btn-secondary {% if not current_version %}disabled{% endif %}" {% if not current_version %}style="opacity:0.5; pointer-events:none;"{% endif %}>
|
||
📥 下载 WHL
|
||
</a>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="sidebar-section">
|
||
<div class="sidebar-title">🔗 快速链接</div>
|
||
<div style="display: flex; flex-direction: column; gap: 6px;">
|
||
<a href="/releases" class="btn btn-secondary" style="text-align: center;">查看发行版</a>
|
||
<a href="/feedback" class="btn btn-secondary" style="text-align: center;">提交反馈</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 右侧内容 -->
|
||
<div class="main-content">
|
||
<!-- 搜索结果 -->
|
||
{% if search_results %}
|
||
<div class="file-list">
|
||
<div class="file-list-header">
|
||
<span>🔍 搜索结果 ({{ search_results|length }})</span>
|
||
<span></span>
|
||
</div>
|
||
{% for result in search_results %}
|
||
<div class="file-row">
|
||
<div class="file-name">
|
||
<span class="icon">📄</span>
|
||
{% set relative_path = result.path.replace(current_branch + '/' + current_version + '/', '') %}
|
||
<a href="{{ url_for('view_file', file_path=relative_path, branch=current_branch, version=current_version) }}">{{ result.name }}</a>
|
||
</div>
|
||
<div class="file-message">{{ result.path }}</div>
|
||
<div class="file-time">
|
||
{% if result.size < 1024 %}
|
||
{{ result.size }} B
|
||
{% elif result.size < 1024*1024 %}
|
||
{{ (result.size/1024)|round(1) }} KB
|
||
{% else %}
|
||
{{ (result.size/(1024*1024))|round(1) }} MB
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
{% endfor %}
|
||
</div>
|
||
{% endif %}
|
||
|
||
<!-- 文件列表 -->
|
||
{% if not search_results %}
|
||
<div class="file-list">
|
||
<div class="file-list-header">
|
||
<span>📁 文件列表</span>
|
||
<span></span>
|
||
<span>大小</span>
|
||
</div>
|
||
<!-- 文件列表中的链接改为使用完整路径 -->
|
||
{% for item in file_tree %}
|
||
<div class="file-row">
|
||
<div class="file-name">
|
||
<span class="icon">{% if item.type == 'dir' %}📁{% else %}📄{% endif %}</span>
|
||
{% if item.type == 'dir' %}
|
||
<a href="{{ url_for('browse_directory', dir_path=item.path, branch=current_branch, version=current_version) }}">{{ item.name }}</a>
|
||
{% else %}
|
||
<!-- 直接使用完整路径,不加替换 -->
|
||
<a href="{{ url_for('view_file', file_path=item.path, branch=current_branch, version=current_version) }}">{{ item.name }}</a>
|
||
{% endif %}
|
||
</div>
|
||
<div class="file-message">
|
||
{% if item.type == 'dir' %}目录{% else %}{{ item.name }}{% endif %}
|
||
</div>
|
||
<div class="file-time">
|
||
{% if item.type == 'file' %}
|
||
{% if item.size < 1024 %}
|
||
{{ item.size }} B
|
||
{% elif item.size < 1024*1024 %}
|
||
{{ (item.size/1024)|round(1) }} KB
|
||
{% else %}
|
||
{{ (item.size/(1024*1024))|round(1) }} MB
|
||
{% endif %}
|
||
{% else %}
|
||
-
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
|
||
{% else %}
|
||
<div class="file-row">
|
||
<div class="file-name" style="justify-content: center; color: var(--repo-color-text-tertiary);">
|
||
此目录为空
|
||
</div>
|
||
<div class="file-message"></div>
|
||
<div class="file-time"></div>
|
||
</div>
|
||
{% endfor %}
|
||
</div>
|
||
{% endif %}
|
||
|
||
<!-- README 区域 -->
|
||
<div class="readme-section">
|
||
<div class="readme-header">
|
||
📖 README.md
|
||
</div>
|
||
<div class="readme-content" id="readme-content">
|
||
<div class="loading">加载中...</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
// 获取当前 URL 基础路径
|
||
var currentUrl = "{{ url_for('code_browser') }}";
|
||
var currentBranch = "{{ current_branch }}";
|
||
var currentVersion = "{{ current_version }}";
|
||
|
||
// ========== 分支/版本选择器 ==========
|
||
var branchSelector = document.getElementById('branch-selector');
|
||
var branchMenu = document.getElementById('branch-menu');
|
||
var versionSelector = document.getElementById('version-selector');
|
||
var versionMenu = document.getElementById('version-menu');
|
||
|
||
if (branchSelector) {
|
||
branchSelector.onclick = function(e) {
|
||
e.stopPropagation();
|
||
branchMenu.style.display = branchMenu.style.display === 'none' ? 'block' : 'none';
|
||
if (versionMenu) versionMenu.style.display = 'none';
|
||
};
|
||
}
|
||
|
||
if (versionSelector) {
|
||
versionSelector.onclick = function(e) {
|
||
e.stopPropagation();
|
||
versionMenu.style.display = versionMenu.style.display === 'none' ? 'block' : 'none';
|
||
if (branchMenu) branchMenu.style.display = 'none';
|
||
};
|
||
}
|
||
|
||
document.onclick = function() {
|
||
if (branchMenu) branchMenu.style.display = 'none';
|
||
if (versionMenu) versionMenu.style.display = 'none';
|
||
};
|
||
|
||
var branchItems = document.querySelectorAll('#branch-menu .branch-menu-item');
|
||
branchItems.forEach(function(item) {
|
||
item.onclick = function(e) {
|
||
e.stopPropagation();
|
||
var branch = this.getAttribute('data-branch');
|
||
if (branch) {
|
||
window.location.href = currentUrl + '?branch=' + encodeURIComponent(branch);
|
||
}
|
||
};
|
||
});
|
||
|
||
var versionItems = document.querySelectorAll('#version-menu .branch-menu-item');
|
||
versionItems.forEach(function(item) {
|
||
item.onclick = function(e) {
|
||
e.stopPropagation();
|
||
var version = this.getAttribute('data-version');
|
||
if (version && currentBranch) {
|
||
window.location.href = currentUrl + '?branch=' + encodeURIComponent(currentBranch) + '&version=' + encodeURIComponent(version);
|
||
}
|
||
};
|
||
});
|
||
|
||
// ========== 加载 README ==========
|
||
function loadReadme() {
|
||
if (!currentBranch || !currentVersion) {
|
||
document.getElementById('readme-content').innerHTML = '<div class="info-message" style="text-align: center;">请选择分支和版本以查看 README</div>';
|
||
return;
|
||
}
|
||
|
||
var readmeUrl = '/view/' + currentBranch + '/' + currentVersion + '/README.md?branch=' + currentBranch + '&version=' + currentVersion;
|
||
|
||
fetch(readmeUrl)
|
||
.then(function(res) {
|
||
if (res.ok) {
|
||
return res.text();
|
||
}
|
||
throw new Error('README.md 不存在');
|
||
})
|
||
.then(function(html) {
|
||
var container = document.getElementById('readme-content');
|
||
|
||
if (html.indexOf('<div class="readme-content">') !== -1) {
|
||
var match = html.match(/<div class="readme-content">([\s\S]*?)<\/div>/);
|
||
if (match && match[1]) {
|
||
container.innerHTML = match[1];
|
||
} else {
|
||
container.innerHTML = html;
|
||
}
|
||
} else {
|
||
container.innerHTML = html;
|
||
}
|
||
|
||
var codeBlocks = container.querySelectorAll('pre code');
|
||
codeBlocks.forEach(function(block) {
|
||
if (typeof hljs !== 'undefined') {
|
||
hljs.highlightElement(block);
|
||
}
|
||
});
|
||
})
|
||
.catch(function(err) {
|
||
document.getElementById('readme-content').innerHTML = '<div class="info-message" style="text-align: center;">📄 暂无 README.md 文件</div>';
|
||
});
|
||
}
|
||
|
||
loadReadme();
|
||
</script>
|
||
|
||
<style>
|
||
.disabled {
|
||
opacity: 0.5;
|
||
pointer-events: none;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
.branch-menu-dropdown {
|
||
position: absolute;
|
||
background-color: var(--repo-color-bg);
|
||
border: 1px solid var(--repo-color-border);
|
||
border-radius: var(--repo-radius-md, 6px);
|
||
width: 200px;
|
||
z-index: var(--repo-z-dropdown, 100);
|
||
box-shadow: var(--repo-shadow-md);
|
||
max-height: 300px;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.branch-menu-item {
|
||
padding: var(--repo-spacing-2, 8px) var(--repo-spacing-3, 12px);
|
||
cursor: pointer;
|
||
transition: background 0.2s;
|
||
color: var(--repo-color-text);
|
||
}
|
||
|
||
.branch-menu-item:hover {
|
||
background-color: var(--repo-color-bg-hover);
|
||
}
|
||
|
||
.loading {
|
||
text-align: center;
|
||
padding: var(--repo-spacing-8, 32px);
|
||
color: var(--repo-color-text-tertiary);
|
||
}
|
||
|
||
.info-message {
|
||
text-align: center;
|
||
padding: var(--repo-spacing-8, 32px);
|
||
color: var(--repo-color-text-tertiary);
|
||
}
|
||
|
||
/* README 内容样式 */
|
||
#readme-content h1, #readme-content h2, #readme-content h3 {
|
||
margin-top: 24px;
|
||
margin-bottom: 16px;
|
||
font-weight: 600;
|
||
}
|
||
#readme-content h1 { font-size: 2em; border-bottom: 1px solid var(--repo-color-border); padding-bottom: 0.3em; }
|
||
#readme-content h2 { font-size: 1.5em; border-bottom: 1px solid var(--repo-color-border); padding-bottom: 0.3em; }
|
||
#readme-content p { margin-bottom: 16px; line-height: 1.6; }
|
||
#readme-content code {
|
||
background-color: var(--repo-color-bg-tertiary);
|
||
padding: 0.2em 0.4em;
|
||
border-radius: 4px;
|
||
font-family: monospace;
|
||
}
|
||
#readme-content pre {
|
||
background-color: var(--repo-color-bg-tertiary);
|
||
padding: 16px;
|
||
border-radius: 8px;
|
||
overflow-x: auto;
|
||
margin-bottom: 16px;
|
||
}
|
||
#readme-content pre code {
|
||
background: none;
|
||
padding: 0;
|
||
}
|
||
#readme-content ul, #readme-content ol {
|
||
padding-left: 2em;
|
||
margin-bottom: 16px;
|
||
}
|
||
#readme-content blockquote {
|
||
border-left: 4px solid var(--repo-color-border);
|
||
padding-left: 16px;
|
||
color: var(--repo-color-text-tertiary);
|
||
margin-bottom: 16px;
|
||
}
|
||
#readme-content table {
|
||
border-collapse: collapse;
|
||
margin-bottom: 16px;
|
||
width: 100%;
|
||
}
|
||
#readme-content th, #readme-content td {
|
||
border: 1px solid var(--repo-color-border);
|
||
padding: 8px 12px;
|
||
}
|
||
#readme-content th {
|
||
background-color: var(--repo-color-bg-secondary);
|
||
}
|
||
</style>
|
||
{% endblock %} |