|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+// 为雅思卡片(UserID=2, MiaoguoCardID>=1671933)的 ContentType=2 补充例句
|
|
|
2
|
+// 例句来源: kylx365_db.Words.ExampleSentence (BookID 212-217, 每词5句)
|
|
|
3
|
+// 渲染格式参照"其余单词"卡片: 例句:\n[读]英文句[/读]\n中文翻译
|
|
|
4
|
+import { query } from '../../../src/util/db.js';
|
|
|
5
|
+import { stringUtils } from '../../../src/util/stringClass.js';
|
|
|
6
|
+
|
|
|
7
|
+function extractWord(content) {
|
|
|
8
|
+ // 优先从音频URL提取: gettts?...&text=regent&...
|
|
|
9
|
+ let m = content.match(/text=([^&]+)/);
|
|
|
10
|
+ if (m && m[1]) return decodeURIComponent(m[1]).trim();
|
|
|
11
|
+ // 兜底: "regent 的基本中文释义"
|
|
|
12
|
+ m = content.match(/^(.*?)\s*的基本中文释义/);
|
|
|
13
|
+ if (m && m[1]) return m[1].trim();
|
|
|
14
|
+ return null;
|
|
|
15
|
+}
|
|
|
16
|
+
|
|
|
17
|
+// 高亮单词(参照 build.test31.js / 已有雅思卡片格式: [线]word[/线])
|
|
|
18
|
+function highlightWord(sentence, word) {
|
|
|
19
|
+ const forms = stringUtils.getWordAllForms(word);
|
|
|
20
|
+ let sent = sentence;
|
|
|
21
|
+ for (const form of forms) {
|
|
|
22
|
+ if (sent.indexOf(form) >= 0) {
|
|
|
23
|
+ sent = sent.replace(form, '[线]' + form + '[/线]');
|
|
|
24
|
+ break;
|
|
|
25
|
+ }
|
|
|
26
|
+ }
|
|
|
27
|
+ return sent;
|
|
|
28
|
+}
|
|
|
29
|
+
|
|
|
30
|
+// 渲染格式与"其余单词"雅思卡片一致: 例句:\n英文(高亮单词)\n中文\n\n...
|
|
|
31
|
+function buildExampleBlock(sentences, word) {
|
|
|
32
|
+ const lines = sentences.map(s => highlightWord(s.Sentence, word) + '\n' + s.Translate);
|
|
|
33
|
+ return '\n例句:\n' + lines.join('\n\n') + '\n\n';
|
|
|
34
|
+}
|
|
|
35
|
+
|
|
|
36
|
+async function run({ dryRun = false } = {}) {
|
|
|
37
|
+ // 1) 取目标卡片
|
|
|
38
|
+ const cards = await query(
|
|
|
39
|
+ 'SELECT MiaoguoCardID FROM kylx365_db.MiaoguoCard where UserID=2 and MiaoguoCardID>=1671933 order by MiaoguoCardID'
|
|
|
40
|
+ );
|
|
|
41
|
+ const ids = cards.map(r => r.MiaoguoCardID);
|
|
|
42
|
+ console.log('目标卡片数:', ids.length);
|
|
|
43
|
+
|
|
|
44
|
+ let updated = 0, skipped = 0, noWord = 0, noSrc = 0;
|
|
|
45
|
+ for (const cid of ids) {
|
|
|
46
|
+ const rows = await query(
|
|
|
47
|
+ 'select Content from kylx365_db.MiaoguoContent where MiaoguoCardID=? and ContentType=2',
|
|
|
48
|
+ [cid]
|
|
|
49
|
+ );
|
|
|
50
|
+ if (!rows.length) { noWord++; console.log(' 跳过(无ContentType=2):', cid); continue; }
|
|
|
51
|
+ let content = rows[0].Content;
|
|
|
52
|
+ if (content.includes('例句:')) { skipped++; continue; }
|
|
|
53
|
+
|
|
|
54
|
+ const word = extractWord(content);
|
|
|
55
|
+ if (!word) { noWord++; console.log(' 跳过(无法提取单词):', cid); continue; }
|
|
|
56
|
+
|
|
|
57
|
+ // 2) 查 Words.ExampleSentence
|
|
|
58
|
+ const ws = await query(
|
|
|
59
|
+ 'select ExampleSentence from kylx365_db.Words where BookID in (212,213,214,215,216,217) and Word=? limit 1',
|
|
|
60
|
+ [word]
|
|
|
61
|
+ );
|
|
|
62
|
+ if (!ws.length || !ws[0].ExampleSentence) { noSrc++; console.log(' 跳过(无例句源):', cid, word); continue; }
|
|
|
63
|
+
|
|
|
64
|
+ let parsed;
|
|
|
65
|
+ try { parsed = JSON.parse(ws[0].ExampleSentence); }
|
|
|
66
|
+ catch (e) { noSrc++; console.log(' 跳过(JSON解析失败):', cid, word); continue; }
|
|
|
67
|
+
|
|
|
68
|
+ const sentences = (parsed.Sentences || []).filter(s => s.Sentence && s.Translate);
|
|
|
69
|
+ if (!sentences.length) { noSrc++; console.log(' 跳过(例句为空):', cid, word); continue; }
|
|
|
70
|
+
|
|
|
71
|
+ const block = buildExampleBlock(sentences, word);
|
|
|
72
|
+ const newContent = content.replace(/\s*$/, '') + block;
|
|
|
73
|
+
|
|
|
74
|
+ if (dryRun) {
|
|
|
75
|
+ console.log(`\n=== [预览] Card ${cid} word=${word} 例句数=${sentences.length} ===`);
|
|
|
76
|
+ console.log(newContent.slice(0, 700));
|
|
|
77
|
+ } else {
|
|
|
78
|
+ await query(
|
|
|
79
|
+ 'update kylx365_db.MiaoguoContent set Content=? where MiaoguoCardID=? and ContentType=2',
|
|
|
80
|
+ [newContent, cid]
|
|
|
81
|
+ );
|
|
|
82
|
+ updated++;
|
|
|
83
|
+ if (updated <= 2) {
|
|
|
84
|
+ console.log(`\n=== [已写] Card ${cid} word=${word} 例句数=${sentences.length} ===`);
|
|
|
85
|
+ console.log(newContent.slice(0, 700));
|
|
|
86
|
+ }
|
|
|
87
|
+ }
|
|
|
88
|
+ }
|
|
|
89
|
+ console.log(`\n完成. updated=${updated} skipped(已有例句)=${skipped} noWord=${noWord} noSrc=${noSrc}`);
|
|
|
90
|
+ process.exit(0);
|
|
|
91
|
+}
|
|
|
92
|
+
|
|
|
93
|
+const dryRun = process.argv.includes('--dry');
|
|
|
94
|
+run({ dryRun }).catch(e => { console.error(e); process.exit(1); });
|