数字我 Digital Me:全量入库(大文件走 Git LFS)
nginx serve /uploads direct (audio speed) / patch-nginx (push) Failing after 1m34s

This commit is contained in:
2026-10-10 16:24:43 +08:00
commit 0593ff7e62
1893 changed files with 361723 additions and 0 deletions
@@ -0,0 +1,80 @@
// 导出《天下·拾遗 诗词篇 全稿(审阅版)》——供老板离线通读审定。每首:原诗+作者其时+考证+魂句+化用曲词。
// 输出 Word 可直接打开的 .doc(HTML)到 Downloads。
import { readFileSync, writeFileSync } from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const REPO = path.resolve(__dirname, '../..');
const BACKEND = path.resolve(__dirname, '..');
const src = readFileSync(path.join(REPO, 'digital-me-web/src/data/shici.ts'), 'utf8');
const SHI = JSON.parse(src.match(/export const SHI: Shi\[\] = (\[[\s\S]*\]);/)[1]);
const ERAS = JSON.parse(src.match(/export const SHI_ERAS:[^=]*= (\[[\s\S]*?\]);/)[1]);
// Suno 风格指令在后端曲库(前端已剥配方)。审阅稿给老板自己看+喂Suno,带上。id: shici.ts 的 p.id ↔ music-library 的 shici:<id>
const LIB = JSON.parse(readFileSync(path.join(BACKEND, 'src/data/music-library.json'), 'utf8'));
const sunoMap = {}; const clipMap = {};
for (const s of LIB) if (String(s.id).startsWith('shici:')) { const k = s.id.slice('shici:'.length); sunoMap[k] = s.sunoStyle || ''; clipMap[k] = s.clip || ''; }
const esc = (s) => String(s == null ? '' : s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
const br = (s) => esc(s).replace(/\n/g, '<br/>');
const generatedAt = new Date().toISOString().slice(0, 10);
let body = '';
let n = 0;
for (const era of ERAS) {
const list = SHI.filter((p) => p.eraSlug === era.slug);
if (!list.length) continue;
body += `<h2 class="era">${esc(era.label)} <span class="cnt">${list.length} 首</span></h2>`;
for (const p of list) {
n++;
body += `<div class="poem">
<div class="ph"><span class="idx">${n}</span> <b class="tt">${esc(p.title)}</b> <span class="au">${esc(p.author)}</span> <span class="dy">${esc(p.dynasty)}</span> <span class="pid">[${esc(p.id)}]</span></div>
<div class="sec"><span class="lb">原诗</span><div class="text">${br(p.text)}</div></div>
${p.authorBrief ? `<div class="sec"><span class="lb">作者其时</span><div class="v">${br(p.authorBrief)}</div></div>` : ''}
${p.background ? `<div class="sec"><span class="lb">创作背景</span><div class="v">${br(p.background)}</div></div>` : ''}
${p.kao ? `<div class="sec"><span class="lb">考证</span><div class="v">${br(p.kao)}</div></div>` : ''}
${p.soulLine ? `<div class="sec"><span class="lb">魂句</span><div class="v soul">${br(p.soulLine)}</div></div>` : ''}
${p.song && p.song.lyrics ? `<div class="sec"><span class="lb">化用曲词</span><div class="lyr">${br(p.song.lyrics)}</div>${p.song.embedded ? `<div class="emb">嵌入原句:${br(p.song.embedded)}</div>` : ''}</div>` : '<div class="sec nolyr">(此首暂无化用曲词)</div>'}
${sunoMap[p.id] ? `<div class="sec"><span class="lb suno">Suno 风格指令</span><div class="suno">${br(sunoMap[p.id])}</div>${clipMap[p.id] ? `<div class="clip">1分钟截取:${br(clipMap[p.id])}</div>` : ''}</div>` : '<div class="sec nolyr">(此首暂无 Suno 风格指令)</div>'}
</div>`;
}
}
const html = `<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-html40"><head><meta charset="utf-8"/>
<title>天下·拾遗 诗词篇 全稿(审阅版)</title>
<style>
body{ font-family:"宋体","SimSun","Microsoft YaHei",serif; color:#1a1a1a; line-height:1.7; font-size:11pt; }
h1{ font-size:22pt; text-align:center; margin:0 0 4pt; }
.meta{ text-align:center; color:#666; font-size:9pt; margin-bottom:18pt; }
.legend{ text-align:center; color:#8a6d33; font-size:9pt; margin-bottom:20pt; }
h2.era{ font-size:15pt; color:#9e2b1e; border-bottom:2px solid #9e2b1e; padding-bottom:3pt; margin:22pt 0 10pt; }
.era .cnt{ font-size:9pt; color:#999; font-weight:normal; }
.poem{ border:1px solid #ddd; border-radius:4px; padding:10pt 12pt; margin:0 0 12pt; page-break-inside:avoid; }
.ph{ font-size:12pt; margin-bottom:6pt; border-bottom:1px dashed #ccc; padding-bottom:4pt; }
.idx{ color:#9e2b1e; font-weight:bold; }
.tt{ font-size:13pt; }
.au{ color:#8a6d33; margin-left:6pt; }
.dy{ color:#999; font-size:9pt; margin-left:6pt; }
.pid{ color:#bbb; font-size:8pt; font-family:Consolas,monospace; float:right; }
.sec{ margin:6pt 0; }
.lb{ display:inline-block; background:#f2ead8; color:#8a6d33; font-size:8.5pt; padding:1pt 6pt; border-radius:3px; margin-right:6pt; }
.text{ margin-top:4pt; padding-left:10pt; color:#333; }
.v{ display:inline; color:#444; font-size:10pt; }
.soul{ color:#9e2b1e; }
.lyr{ margin-top:4pt; padding:6pt 10pt; background:#faf7ef; border-left:3px solid #c8a25e; color:#2a2a2a; font-size:10.5pt; }
.emb{ color:#8a6d33; font-size:9pt; margin-top:3pt; }
.lb.suno{ background:#e7efe8; color:#2c6e49; }
.suno{ margin-top:4pt; padding:6pt 10pt; background:#f3f8f4; border-left:3px solid #2c6e49; color:#234; font-size:10pt; font-family:Consolas,"Courier New",monospace; }
.clip{ color:#2c6e49; font-size:9pt; margin-top:3pt; }
.nolyr{ color:#c0392b; font-size:9pt; }
</style></head><body>
<h1>天下 · 拾遗 · 诗词篇 全稿(审阅版)</h1>
<div class="meta">共 ${SHI.length} 首 · 先秦至明清 · 每首含【化用曲词 + Suno 风格指令】· 生成 ${generatedAt} · 供离线审定</div>
<div class="legend">审阅用法:要改的请记下左上角编号或 [id](如 [tang-012]),回头告诉我批量改;改定后再一起做确权。<br/>⚠ 本稿含 Suno 风格指令(=制作配方,仅你自己看/喂 Suno 用,前端已对用户隐藏,勿外传)。</div>
${body}
</body></html>`;
const OUT = 'C:/Users/solut/Downloads/天下诗词篇全稿-审阅版-含Suno风格.doc';
writeFileSync(OUT, '\uFEFF' + html, 'utf8');
console.log('已导出:', OUT);
console.log('共', SHI.length, '首;有化用曲词的', SHI.filter((p) => p.song && p.song.lyrics).length, '首');