koishi-plugin-bns-blacklist 1.0.7 → 1.0.9

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/lib/index.js +72 -9
  2. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -38,6 +38,7 @@ exports.apply = apply;
38
38
  const koishi_1 = require("koishi");
39
39
  const fs = __importStar(require("fs"));
40
40
  const path = __importStar(require("path"));
41
+ const zlib = __importStar(require("zlib"));
41
42
  exports.name = 'bns-blacklist';
42
43
  exports.inject = ['puppeteer'];
43
44
  exports.Config = koishi_1.Schema.object({
@@ -227,23 +228,43 @@ async function scrapeSheet(page, url, logger) {
227
228
  const text = item.text || item.body;
228
229
  if (logger)
229
230
  logger.info(` ${item.endpoint} -> status=${item.status}, len=${text?.length}`);
231
+ if (!text || text.length < 10)
232
+ continue;
233
+ // Try to parse Tencent Docs custom key-value format
234
+ const kvData = parseTencentKvFormat(text, logger);
235
+ if (kvData) {
236
+ // Look for chunk data (compressed cell data)
237
+ const chunkKey = Object.keys(kvData).find(k => k.startsWith('chunk_'));
238
+ if (chunkKey) {
239
+ try {
240
+ const compressed = Buffer.from(kvData[chunkKey], 'base64');
241
+ const decompressed = zlib.inflateSync(compressed).toString('utf-8');
242
+ if (logger)
243
+ logger.info(` Chunk decompressed: ${decompressed.length} bytes, sample: ${decompressed.substring(0, 300)}`);
244
+ const rows = parseTencentChunk(decompressed);
245
+ if (rows.length > 0) {
246
+ if (logger)
247
+ logger.info(`Found ${rows.length} rows from chunk`);
248
+ return parseSheetData(rows);
249
+ }
250
+ }
251
+ catch (e) {
252
+ if (logger)
253
+ logger.info(` Chunk decompress failed: ${e.message}`);
254
+ }
255
+ }
256
+ }
257
+ // Try JSON parse as fallback
230
258
  try {
231
259
  const json = JSON.parse(text);
232
- // Log sample of JSON structure for debugging
233
- if (logger && text.length > 100) {
234
- const keys = Object.keys(json);
235
- logger.info(` JSON keys: [${keys.join(', ')}]`);
236
- // Log first 500 chars
237
- logger.info(` JSON sample: ${text.substring(0, 500)}`);
238
- }
239
260
  const rows = extractRowsFromJson(json);
240
261
  if (rows.length > 0) {
241
262
  if (logger)
242
- logger.info(`Found data: ${rows.length} rows`);
263
+ logger.info(`Found data: ${rows.length} rows via JSON`);
243
264
  return parseSheetData(rows);
244
265
  }
245
266
  }
246
- catch (_) { /* try next */ }
267
+ catch (_) { /* not JSON */ }
247
268
  }
248
269
  // Strategy 2: Dump page text and try to parse
249
270
  const pageText = await page.evaluate(() => document.body.innerText);
@@ -267,6 +288,48 @@ async function scrapeSheet(page, url, logger) {
267
288
  }
268
289
  return [];
269
290
  }
291
+ // Parse Tencent Docs custom KV text format:
292
+ // key \n type \n len \n value (each on separate lines)
293
+ function parseTencentKvFormat(text, logger) {
294
+ const parts = text.split('\n').map(s => s.trim()).filter(s => s.length > 0);
295
+ const result = {};
296
+ let i = 0;
297
+ while (i < parts.length - 2) {
298
+ const key = parts[i];
299
+ const type = parts[i + 1];
300
+ // type is usually "text", value length is next, then value
301
+ if (type === 'text' && /^\d+$/.test(parts[i + 2])) {
302
+ const len = parseInt(parts[i + 2]);
303
+ const value = parts[i + 3] || '';
304
+ result[key] = value;
305
+ i += 4;
306
+ }
307
+ else {
308
+ i += 1;
309
+ }
310
+ }
311
+ return Object.keys(result).length > 2 ? result : null;
312
+ }
313
+ // Parse the decompressed chunk data into rows
314
+ // The chunk format is likely tab-separated or similar
315
+ function parseTencentChunk(data) {
316
+ const rows = [];
317
+ const lines = data.split('\n').filter(l => l.trim());
318
+ for (const line of lines) {
319
+ // Try tab-separated
320
+ const cells = line.split('\t');
321
+ if (cells.length >= 3) {
322
+ rows.push(cells.map(c => c.trim()));
323
+ continue;
324
+ }
325
+ // Try comma-separated
326
+ const csvCells = line.split(',');
327
+ if (csvCells.length >= 5) {
328
+ rows.push(csvCells.map(c => c.trim().replace(/^"|"$/g, '')));
329
+ }
330
+ }
331
+ return rows;
332
+ }
270
333
  // Recursively search JSON for array-of-arrays that looks like sheet data
271
334
  function extractRowsFromJson(obj, depth = 0) {
272
335
  if (depth > 8)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koishi-plugin-bns-blacklist",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "剑灵怀旧服副本黑名单查询 - 从腾讯文档实时拉取数据,输入角色名即可生成黑名单截图",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",