cortico-world-forward-reader 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +47 -28
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cortico-world-forward-reader",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "转发拆解 World:把 QQ 的「合并转发」一层层拆到底,嵌套在里面的转发也展开,输出带缩进的人话。只读,不发消息。",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
package/src/index.js CHANGED
@@ -40,13 +40,21 @@ function senderName(sender) {
40
40
  return sender.card || sender.nickname || (sender.user_id ? String(sender.user_id) : '?');
41
41
  }
42
42
 
43
+ /** 今天的时间只给 HH:MM;跨天的带上日期,免得整份记录分不清哪天。 */
43
44
  function clockOf(time) {
44
45
  if (!time) return '';
45
46
  const d = new Date(Number(time) * 1000);
46
47
  if (Number.isNaN(d.getTime())) return '';
47
48
  const hh = String(d.getHours()).padStart(2, '0');
48
49
  const mm = String(d.getMinutes()).padStart(2, '0');
49
- return `${hh}:${mm}`;
50
+ const now = new Date();
51
+ const sameDay =
52
+ d.getFullYear() === now.getFullYear() && d.getMonth() === now.getMonth() && d.getDate() === now.getDate();
53
+ if (sameDay) return `${hh}:${mm}`;
54
+ const mo = String(d.getMonth() + 1).padStart(2, '0');
55
+ const dd = String(d.getDate()).padStart(2, '0');
56
+ const year = d.getFullYear() === now.getFullYear() ? '' : `${d.getFullYear()}-`;
57
+ return `${year}${mo}-${dd} ${hh}:${mm}`;
50
58
  }
51
59
 
52
60
  /** 把一条消息的段合成一行,并挑出里面嵌套的转发段。 */
@@ -126,7 +134,8 @@ export class ForwardReaderWorld {
126
134
  const cfg = this.cfg;
127
135
  const rawRef = String(args.ref ?? '')
128
136
  .trim()
129
- .replace(/^#/, '');
137
+ .replace(/^#/, '')
138
+ .trim();
130
139
  if (!rawRef) return fail('要给消息编号(QQ 消息行首的 #后面那串数字)。');
131
140
  // QQ 的 message_id 有负数的(合并转发卡片就常见):负号是 id 的一部分,不能丢。
132
141
  if (!/^-?\d+$/.test(rawRef)) return fail(`"${rawRef}" 不像消息编号,应该是数字(前面可能带一个负号),比如 265277450 或 -1175570559。`);
@@ -134,39 +143,49 @@ export class ForwardReaderWorld {
134
143
  const maxDepth = clampInt(args.depth ?? cfg.maxDepth, 8, 1, 20);
135
144
  const limit = clampInt(args.maxChars ?? cfg.maxChars, MAX_OUTPUT_CHARS, 1000, 60000);
136
145
 
146
+ let data;
147
+ try {
148
+ data = await callOneBot(cfg, 'get_msg', { message_id: rawRef });
149
+ } catch (err) {
150
+ const why = String(err?.message || err);
151
+ const hint = /not found|不存在|找不到/i.test(why)
152
+ ? '取不到这条,常见原因:消息太老、SnowLuma 那边没缓存了;或者编号抄错——负号是编号的一部分,除了行首的「#」别的字符一个都不能少。'
153
+ : '';
154
+ return fail(`取消息 ${rawRef} 失败:${why}${hint ? '\n' + hint : ''}\n可以先跑 qq_forward_status 看看接口和 token 怎么样。`);
155
+ }
156
+
137
157
  const out = [];
138
158
  const state = { items: 0, levels: 0, truncated: false };
159
+ const segments = data?.message || [];
160
+ const whole = foldMessage(segments);
161
+ const who = senderName(data?.sender);
162
+ const when = clockOf(data?.time);
163
+
164
+ if (!whole.nested.length) {
165
+ // 不是合并转发:直接把这条消息本身给人看。
166
+ out.push(`# 消息 ${rawRef}${who !== '?' ? ` · ${who}` : ''}${when ? ` · ${when}` : ''}`);
167
+ out.push('');
168
+ out.push(whole.text || '(没有文字内容)');
169
+ out.push('');
170
+ out.push('这条不是合并转发卡片,所以没有可拆的层。');
171
+ return cap(out.join('\n'), limit);
172
+ }
139
173
 
140
- try {
141
- const data = await callOneBot(cfg, 'get_msg', { message_id: rawRef });
142
- const segments = data?.message || [];
143
- const whole = foldMessage(segments);
144
-
145
- if (!whole.nested.length) {
146
- // 不是合并转发:直接把这条消息本身给人看。
147
- const who = senderName(data?.sender);
148
- const when = clockOf(data?.time);
149
- out.push(`# 消息 ${rawRef}${who !== '?' ? ` · ${who}` : ''}${when ? ` · ${when}` : ''}`);
150
- out.push('');
151
- out.push(whole.text || '(没有文字内容)');
152
- out.push('');
153
- out.push('这条不是合并转发卡片,所以没有可拆的层。');
154
- return cap(out.join('\n'), limit);
155
- }
174
+ out.push(`# 转发拆解 · 消息 ${rawRef}${who !== '?' ? ` · ${who}` : ''}${when ? ` · ${when}` : ''}`);
175
+ out.push('');
156
176
 
157
- const time = clockOf(data?.time);
158
- out.push(`# 转发拆解 · 消息 ${rawRef}${time ? ` · ${time}` : ''}`);
177
+ // 卡片本身带的文字也要留下,不然只列转发内容就把原话吞掉了。
178
+ if (whole.text) {
179
+ out.push(`(这张卡片上还写着)${whole.text}`);
159
180
  out.push('');
181
+ }
160
182
 
161
- for (const seg of whole.nested) {
162
- await this.walk(seg.data?.id, 0, out, state, maxDepth);
163
- }
164
-
165
- out.unshift(`共 ${state.levels} 层 / ${state.items} 条${state.truncated ? '(已达条数上限,后面没再往下翻)' : ''}`);
166
- return cap(out.join('\n'), limit);
167
- } catch (err) {
168
- return fail(`拆不开:${err.message}\n可以先跑 qq_forward_status 看看接口和 token 怎么样。`);
183
+ for (const seg of whole.nested) {
184
+ await this.walk(seg.data?.id, 0, out, state, maxDepth);
169
185
  }
186
+
187
+ out.unshift(`共 ${state.levels} 层 / ${state.items} 条${state.truncated ? '(已达条数上限,后面没再往下翻)' : ''}`);
188
+ return cap(out.join('\n'), limit);
170
189
  }
171
190
 
172
191
  async walk(forwardId, depth, out, state, maxDepth) {