Files
shumengya f45a0068a2 chore: 完善开源项目文档与结构,移除敏感原始图片
- 重写 README.md,添加在线体验、API 文档、部署指南、技术栈等
- 添加 MIT LICENSE
- 添加 CONTRIBUTING.md 贡献指南
- 添加 GitHub Issue/PR 模板
- 完善 .gitignore,防止原始图片和敏感文件误提交
- 从 git 中移除 25 个原始图片文件(.png/.jpg/非序号 webp)
- 项目结构迁移:functions/ -> src/,根目录静态文件 -> public/
- 添加 wrangler.toml 与 package.json 配置
2026-06-06 20:52:59 +08:00

259 lines
8.6 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.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>随机背景API</title>
<meta name="description" content="Cloudflare Workers随机背景 API 说明与预览。">
<style>
:root {
--text: #1a1a1a;
--muted: #666;
--border: #ddd;
--code-bg: #f5f5f5;
--accent: #06c;
}
*, *::before, *::after { box-sizing: border-box; }
body {
margin: 0;
padding: 1.5rem 1.25rem 3rem;
color: var(--text);
font: 16px/1.6 ui-sans-serif, system-ui, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
background: #fff;
}
a { color: var(--accent); }
code {
font: 0.92em ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
background: var(--code-bg);
padding: 0.15em 0.35em;
}
pre, .pre-like {
margin: 0.5rem 0 1rem;
padding: 0.65rem 0.85rem;
background: var(--code-bg);
font: 13px/1.45 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
overflow-x: auto;
border: 1px solid var(--border);
white-space: pre-wrap;
word-break: break-all;
}
.doc {
max-width: 40rem;
margin: 0 auto;
}
h1 {
font-size: 1.5rem;
font-weight: 600;
margin: 0 0 0.5rem;
line-height: 1.25;
}
h2 {
font-size: 1.05rem;
font-weight: 600;
margin: 2rem 0 0.65rem;
padding-bottom: 0.25rem;
border-bottom: 1px solid var(--border);
}
p { margin: 0 0 0.85rem; }
.muted { color: var(--muted); font-size: 0.95rem; }
ul {
margin: 0 0 1rem;
padding-left: 1.2rem;
}
li { margin: 0.2rem 0; }
.api-item { margin-bottom: 1.1rem; }
.api-item p { margin: 0.25rem 0 0.35rem; }
.controls {
display: flex;
flex-wrap: wrap;
gap: 0.75rem 1rem;
align-items: flex-end;
margin: 0.75rem 0 1rem;
}
.field label {
display: block;
font-size: 0.75rem;
color: var(--muted);
margin-bottom: 0.2rem;
}
select {
font: inherit;
padding: 0.35rem 0.45rem;
border: 1px solid var(--border);
background: #fff;
color: inherit;
min-width: 6.5rem;
}
button {
font: inherit;
padding: 0.38rem 0.85rem;
border: 1px solid var(--border);
background: var(--accent);
color: #fff;
cursor: pointer;
}
button:hover { filter: brightness(1.05); }
#apiUrl {
width: 100%;
box-sizing: border-box;
font: 13px ui-monospace, Menlo, Consolas, monospace;
padding: 0.45rem 0.5rem;
border: 1px solid var(--border);
background: #fafafa;
}
#previewImg {
display: block;
width: 100%;
max-height: 14rem;
object-fit: cover;
margin-top: 0.5rem;
border: 1px solid var(--border);
background: var(--code-bg);
}
footer {
margin-top: 2.5rem;
font-size: 0.875rem;
color: var(--muted);
border-top: 1px solid var(--border);
padding-top: 1rem;
}
@media (max-width: 480px) {
.controls { flex-direction: column; align-items: stretch; }
button { width: 100%; }
}
</style>
</head>
<body>
<main class="doc">
<h1>随机背景 API</h1>
<p>Cloudflare Workers 接口。先用 <code>build.py</code><code>public/</code> 下生成序号 <code>.webp</code><code>manifest.json</code>,再通过 <code>/api/random</code><code>/api/list</code> 调用。</p>
<p class="muted">约定:<code>mobile-image</code> 竖屏,<code>desketop-image</code> 横屏。默认响应为 302<code>format=json</code> 时返回 JSON。</p>
<h2 id="links">快捷链接</h2>
<ul>
<li><a href="/api/list" target="_blank" rel="noreferrer"><code>/api/list</code></a></li>
<li><a href="/manifest.json" target="_blank" rel="noreferrer"><code>/manifest.json</code></a></li>
<li><a href="/mobile-image/1.webp" target="_blank" rel="noreferrer"><code>/mobile-image/1.webp</code></a>(示例)</li>
</ul>
<h2 id="api">接口说明</h2>
<div class="api-item">
<p><strong><code>GET /api/random</code></strong></p>
<p class="muted">按设备方向选一个文件名302 跳到对应图片。</p>
<pre>GET /api/random</pre>
</div>
<div class="api-item">
<p><strong><code>GET /api/random?format=json</code></strong></p>
<p class="muted">返回包含 <code>url</code> 等字段的 JSON。</p>
<pre>GET /api/random?format=json</pre>
</div>
<div class="api-item">
<p><strong><code>GET /api/random?mode=mobile</code></strong> / <strong><code>?mode=desktop</code></strong></p>
<p class="muted">强制使用竖屏或横屏素材目录。</p>
<pre>GET /api/random?mode=mobile
GET /api/random?mode=desktop</pre>
</div>
<p class="muted">查询参数:<code>mode=auto|mobile|desktop</code><code>orientation=portrait|landscape</code><code>device=mobile|desktop</code><code>format=redirect|json</code></p>
<h2 id="preview">在线预览</h2>
<div class="controls">
<div class="field">
<label for="modeSelect">mode</label>
<select id="modeSelect">
<option value="auto">auto</option>
<option value="mobile">mobile</option>
<option value="desktop">desktop</option>
</select>
</div>
<div class="field">
<label for="orientationSelect">orientation</label>
<select id="orientationSelect">
<option value="">auto</option>
<option value="portrait">portrait</option>
<option value="landscape">landscape</option>
</select>
</div>
<div class="field">
<label for="formatSelect">format</label>
<select id="formatSelect">
<option value="json">json</option>
<option value="redirect">redirect</option>
</select>
</div>
<button id="refreshBtn" type="button">刷新</button>
</div>
<p><label for="apiUrl" class="muted" style="font-size: 0.75rem;">当前请求</label></p>
<input id="apiUrl" readonly value="" autocomplete="off" spellcheck="false">
<img id="previewImg" alt="随机背景预览" src="">
<p><span class="muted" style="font-size: 0.75rem;">响应体</span></p>
<pre class="pre-like" id="jsonOutput">{}</pre>
<footer>
构建:<code>python3 build.py</code>。部署:<code>npm run deploy</code><code>wrangler deploy</code>。Worker 仅含 API静态页与图片来自 Assets。
</footer>
</main>
<script>
const modeSelect = document.getElementById('modeSelect');
const orientationSelect = document.getElementById('orientationSelect');
const formatSelect = document.getElementById('formatSelect');
const refreshBtn = document.getElementById('refreshBtn');
const apiUrl = document.getElementById('apiUrl');
const previewImg = document.getElementById('previewImg');
const jsonOutput = document.getElementById('jsonOutput');
function detectOrientation() {
return window.matchMedia('(orientation: portrait)').matches ? 'portrait' : 'landscape';
}
function detectDevice() {
if (navigator.userAgentData && typeof navigator.userAgentData.mobile === 'boolean') {
return navigator.userAgentData.mobile ? 'mobile' : 'desktop';
}
return /Mobi|Android|iPhone|iPad|iPod/i.test(navigator.userAgent) ? 'mobile' : 'desktop';
}
function buildApiPath() {
const params = new URLSearchParams();
params.set('mode', modeSelect.value);
params.set('device', detectDevice());
params.set('format', formatSelect.value);
const orientation = orientationSelect.value || detectOrientation();
params.set('orientation', orientation);
return `/api/random?${params.toString()}`;
}
async function refresh() {
const url = buildApiPath();
apiUrl.value = url;
previewImg.style.opacity = '0.72';
if (formatSelect.value === 'json') {
const response = await fetch(url);
const data = await response.json();
jsonOutput.textContent = JSON.stringify(data, null, 2);
previewImg.src = data.url || '';
} else {
jsonOutput.textContent = '{ "format": "redirect" }';
previewImg.src = url;
}
}
previewImg.addEventListener('load', () => {
previewImg.style.opacity = '1';
});
refreshBtn.addEventListener('click', refresh);
modeSelect.addEventListener('change', refresh);
orientationSelect.addEventListener('change', refresh);
formatSelect.addEventListener('change', refresh);
refresh();
</script>
</body>
</html>