Files
JieXi/templates/api_docs.html
2025-11-30 19:49:25 +08:00

558 lines
17 KiB
HTML
Raw 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.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>API 文档 - 短视频解析平台</title>
<link rel="stylesheet" href="/static/css/ui-components.css?v=3">
<style>
body {
background: linear-gradient(135deg, #f0f9ff 0%, #e0e7ff 100%);
min-height: 100vh;
padding: 2rem 1rem;
}
.container {
max-width: 900px;
margin: 0 auto;
}
.page-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2rem;
}
.page-title {
font-size: 1.75rem;
font-weight: 700;
color: var(--secondary-900);
}
.header-actions {
display: flex;
gap: 0.75rem;
}
.doc-card {
background: white;
border-radius: var(--radius-lg);
padding: 1.5rem;
box-shadow: var(--shadow-md);
margin-bottom: 1.5rem;
}
.doc-card h2 {
font-size: 1.25rem;
font-weight: 600;
color: var(--secondary-900);
margin-bottom: 1rem;
padding-bottom: 0.75rem;
border-bottom: 1px solid var(--border-color);
}
.doc-card h3 {
font-size: 1rem;
font-weight: 600;
color: var(--secondary-800);
margin: 1.25rem 0 0.75rem;
}
.doc-card p {
color: var(--secondary-600);
line-height: 1.7;
margin-bottom: 1rem;
}
.endpoint {
display: flex;
align-items: center;
gap: 0.75rem;
margin-bottom: 1rem;
}
.method {
display: inline-block;
padding: 0.25rem 0.75rem;
border-radius: var(--radius-sm);
font-size: 0.75rem;
font-weight: 700;
text-transform: uppercase;
}
.method.post {
background: #dbeafe;
color: #1d4ed8;
}
.method.get {
background: #dcfce7;
color: #166534;
}
.url {
font-family: monospace;
font-size: 0.95rem;
color: var(--secondary-800);
background: var(--secondary-50);
padding: 0.5rem 0.75rem;
border-radius: var(--radius-sm);
flex: 1;
}
.code-block {
background: #1e293b;
color: #e2e8f0;
border-radius: var(--radius-md);
padding: 1rem 1.25rem;
font-family: 'Monaco', 'Menlo', monospace;
font-size: 0.85rem;
line-height: 1.6;
overflow-x: auto;
margin: 1rem 0;
position: relative;
}
.code-block .copy-btn {
position: absolute;
top: 0.5rem;
right: 0.5rem;
background: rgba(255,255,255,0.1);
border: none;
color: #94a3b8;
padding: 0.25rem 0.5rem;
border-radius: var(--radius-sm);
cursor: pointer;
font-size: 0.75rem;
}
.code-block .copy-btn:hover {
background: rgba(255,255,255,0.2);
color: white;
}
.code-block .comment {
color: #64748b;
}
.code-block .string {
color: #a5d6ff;
}
.code-block .key {
color: #7dd3fc;
}
.code-block .value {
color: #86efac;
}
.param-table {
width: 100%;
border-collapse: collapse;
margin: 1rem 0;
}
.param-table th,
.param-table td {
padding: 0.75rem;
text-align: left;
border-bottom: 1px solid var(--border-color);
font-size: 0.875rem;
}
.param-table th {
background: var(--secondary-50);
font-weight: 600;
color: var(--secondary-700);
}
.param-table code {
background: var(--secondary-100);
padding: 0.125rem 0.375rem;
border-radius: var(--radius-sm);
font-size: 0.8rem;
}
.required {
color: #dc2626;
font-size: 0.75rem;
}
.platform-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
margin: 1rem 0;
}
.platform-item {
background: var(--secondary-50);
padding: 1rem;
border-radius: var(--radius-md);
border: 1px solid var(--border-color);
}
.platform-name {
font-weight: 600;
color: var(--secondary-900);
margin-bottom: 0.5rem;
}
.platform-patterns {
font-size: 0.8rem;
color: var(--text-muted);
font-family: monospace;
}
.tip-box {
background: #eff6ff;
border: 1px solid #bfdbfe;
border-radius: var(--radius-md);
padding: 1rem;
font-size: 0.875rem;
color: #1e40af;
margin: 1rem 0;
}
.warning-box {
background: #fef3c7;
border: 1px solid #fcd34d;
border-radius: var(--radius-md);
padding: 1rem;
font-size: 0.875rem;
color: #92400e;
margin: 1rem 0;
}
.error-codes {
margin: 1rem 0;
}
.error-code {
display: flex;
gap: 1rem;
padding: 0.5rem 0;
border-bottom: 1px solid var(--secondary-100);
}
.error-code:last-child {
border-bottom: none;
}
.error-code code {
background: #fee2e2;
color: #991b1b;
padding: 0.125rem 0.5rem;
border-radius: var(--radius-sm);
font-size: 0.8rem;
white-space: nowrap;
}
@media (max-width: 640px) {
.page-header {
flex-direction: column;
align-items: flex-start;
gap: 1rem;
}
.endpoint {
flex-direction: column;
align-items: flex-start;
}
.url {
width: 100%;
}
}
</style>
</head>
<body>
<div class="container">
<div class="page-header">
<h1 class="page-title">API 文档</h1>
<div class="header-actions">
<a href="/user/apikey" class="ui-btn ui-btn-primary">管理 API Key</a>
<a href="/" class="ui-btn ui-btn-secondary">返回首页</a>
</div>
</div>
<!-- 快速开始 -->
<div class="doc-card">
<h2>快速开始</h2>
<p>短视频解析 API 支持抖音、TikTok、哔哩哔哩等平台的视频解析返回无水印视频链接、封面、标题、作者等信息。</p>
<h3>1. 获取 API Key</h3>
<p>登录后访问 <a href="/user/apikey">API Key 管理</a> 页面创建您的 API Key。</p>
<h3>2. 发起请求</h3>
<div class="code-block">
<button class="copy-btn" onclick="copyCode(this)">复制</button>
<pre>https://your-domain.com/api/v1/parse?key=sk_xxx&url=视频链接</pre>
</div>
<h3>3. 获取结果</h3>
<div class="code-block">
<button class="copy-btn" onclick="copyCode(this)">复制</button>
<pre>{
<span class="key">"code"</span>: <span class="value">200</span>,
<span class="key">"msg"</span>: <span class="string">"解析成功"</span>,
<span class="key">"data"</span>: {
<span class="key">"cover"</span>: <span class="string">"封面URL"</span>,
<span class="key">"title"</span>: <span class="string">"视频标题"</span>,
<span class="key">"description"</span>: <span class="string">"视频简介"</span>,
<span class="key">"author"</span>: <span class="string">"作者名"</span>,
<span class="key">"video_url"</span>: <span class="string">"无水印视频链接"</span>
}
}</pre>
</div>
</div>
<!-- 认证方式 -->
<div class="doc-card">
<h2>认证方式</h2>
<p>通过 URL 参数 <code>key</code> 传递 API Key</p>
<div class="code-block">
<button class="copy-btn" onclick="copyCode(this)">复制</button>
<pre>/api/v1/parse?key=您的API_Key&url=视频链接</pre>
</div>
<div class="warning-box">
请妥善保管您的 API Key不要在客户端代码中暴露。建议通过后端服务调用 API。
</div>
</div>
<!-- 解析接口 -->
<div class="doc-card">
<h2>解析接口</h2>
<div class="endpoint">
<span class="method get">GET</span>
<span class="url">/api/v1/parse</span>
</div>
<h3>请求参数</h3>
<table class="param-table">
<thead>
<tr>
<th>参数</th>
<th>类型</th>
<th>必填</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>key</code></td>
<td>string</td>
<td><span class="required"></span></td>
<td>您的 API Key</td>
</tr>
<tr>
<td><code>url</code></td>
<td>string</td>
<td><span class="required"></span></td>
<td>视频链接(支持短链接和完整链接)</td>
</tr>
</tbody>
</table>
<h3>成功响应</h3>
<div class="code-block">
<button class="copy-btn" onclick="copyCode(this)">复制</button>
<pre>{
<span class="key">"code"</span>: <span class="value">200</span>,
<span class="key">"msg"</span>: <span class="string">"解析成功"</span>,
<span class="key">"data"</span>: {
<span class="key">"cover"</span>: <span class="string">"封面图片URL"</span>,
<span class="key">"title"</span>: <span class="string">"视频标题"</span>,
<span class="key">"description"</span>: <span class="string">"视频简介"</span>,
<span class="key">"author"</span>: <span class="string">"作者名称"</span>,
<span class="key">"video_url"</span>: <span class="string">"无水印视频URL"</span>
}
}</pre>
</div>
<h3>错误响应</h3>
<div class="code-block">
<button class="copy-btn" onclick="copyCode(this)">复制</button>
<pre>{
<span class="key">"code"</span>: <span class="value">401</span>,
<span class="key">"msg"</span>: <span class="string">"错误描述"</span>
}</pre>
</div>
</div>
<!-- 支持平台 -->
<div class="doc-card">
<h2>支持平台</h2>
<div class="endpoint">
<span class="method get">GET</span>
<span class="url">/api/v1/platforms</span>
</div>
<p>此接口无需认证,可获取当前支持的平台列表。</p>
<div class="platform-list">
<div class="platform-item">
<div class="platform-name">抖音</div>
<div class="platform-patterns">douyin.com, v.douyin.com</div>
</div>
<div class="platform-item">
<div class="platform-name">TikTok</div>
<div class="platform-patterns">tiktok.com</div>
</div>
<div class="platform-item">
<div class="platform-name">哔哩哔哩</div>
<div class="platform-patterns">bilibili.com, b23.tv</div>
</div>
<div class="platform-item">
<div class="platform-name">快手</div>
<div class="platform-patterns">kuaishou.com</div>
</div>
<div class="platform-item">
<div class="platform-name">皮皮虾</div>
<div class="platform-patterns">pipix.com, h5.pipix.com</div>
</div>
<div class="platform-item">
<div class="platform-name">微博</div>
<div class="platform-patterns">weibo.com, weibo.cn</div>
</div>
</div>
</div>
<!-- 错误码 -->
<div class="doc-card">
<h2>错误码说明</h2>
<div class="error-codes">
<div class="error-code">
<code>UNAUTHORIZED</code>
<span>API Key 无效、已禁用或超出限额</span>
</div>
<div class="error-code">
<code>INVALID_REQUEST</code>
<span>请求格式错误,需要 JSON 格式</span>
</div>
<div class="error-code">
<code>MISSING_URL</code>
<span>缺少 url 参数</span>
</div>
<div class="error-code">
<code>UNSUPPORTED_PLATFORM</code>
<span>不支持的视频平台</span>
</div>
<div class="error-code">
<code>NO_AVAILABLE_API</code>
<span>该平台暂无可用解析接口</span>
</div>
<div class="error-code">
<code>PARSE_FAILED</code>
<span>解析失败,请检查链接或稍后重试</span>
</div>
</div>
</div>
<!-- 代码示例 -->
<div class="doc-card">
<h2>代码示例</h2>
<h3>Python</h3>
<div class="code-block">
<button class="copy-btn" onclick="copyCode(this)">复制</button>
<pre>import requests
api_key = "sk_your_api_key_here"
video_url = "https://v.douyin.com/xxxxx"
response = requests.get(
"https://your-domain.com/api/v1/parse",
params={"key": api_key, "url": video_url}
)
result = response.json()
if result["code"] == 200:
print("视频标题:", result["data"]["title"])
print("作者:", result["data"]["author"])
print("视频链接:", result["data"]["video_url"])
else:
print("错误:", result["msg"])</pre>
</div>
<h3>JavaScript</h3>
<div class="code-block">
<button class="copy-btn" onclick="copyCode(this)">复制</button>
<pre>const apiKey = 'sk_your_api_key_here';
const videoUrl = 'https://v.douyin.com/xxxxx';
fetch(`https://your-domain.com/api/v1/parse?key=${apiKey}&url=${encodeURIComponent(videoUrl)}`)
.then(res => res.json())
.then(result => {
if (result.code === 200) {
console.log('视频标题:', result.data.title);
console.log('作者:', result.data.author);
console.log('视频链接:', result.data.video_url);
} else {
console.error('错误:', result.msg);
}
});</pre>
</div>
<h3>cURL</h3>
<div class="code-block">
<button class="copy-btn" onclick="copyCode(this)">复制</button>
<pre>curl "https://your-domain.com/api/v1/parse?key=sk_xxx&url=https://v.douyin.com/xxxxx"</pre>
</div>
</div>
<!-- 限制说明 -->
<div class="doc-card">
<h2>使用限制</h2>
<table class="param-table">
<thead>
<tr>
<th>用户等级</th>
<th>每日限额</th>
</tr>
</thead>
<tbody>
<tr>
<td>普通用户</td>
<td>100 次/天/Key</td>
</tr>
<tr>
<td>VIP 用户</td>
<td>500 次/天/Key</td>
</tr>
<tr>
<td>SVIP 用户</td>
<td>2000 次/天/Key</td>
</tr>
</tbody>
</table>
<div class="tip-box">
每个用户最多可创建 5 个 API Key每日限额按单个 Key 计算。
</div>
</div>
</div>
<script src="/static/js/ui-components.js"></script>
<script>
function copyCode(btn) {
const codeBlock = btn.parentElement;
const code = codeBlock.querySelector('pre').textContent;
navigator.clipboard.writeText(code).then(() => {
const originalText = btn.textContent;
btn.textContent = '已复制';
setTimeout(() => {
btn.textContent = originalText;
}, 2000);
}).catch(() => {
UI.notify('复制失败', 'error');
});
}
</script>
</body>
</html>