@will-17173/telegram-cli 0.5.0 → 0.6.0

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.
@@ -0,0 +1,321 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { mkdir, open, rename, rm } from 'node:fs/promises';
3
+ import { dirname, extname, join, parse } from 'node:path';
4
+ import { randomUUID } from 'node:crypto';
5
+ import { sanitizeAttachmentFileName } from './attachment-download.js';
6
+ const MAX_FLOOD_RETRIES = 5;
7
+ export class DownloadService {
8
+ source;
9
+ sleep;
10
+ exists;
11
+ uuid;
12
+ constructor(source, dependencies = {}) {
13
+ this.source = source;
14
+ this.sleep = dependencies.sleep ?? ((milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)));
15
+ this.exists = dependencies.exists ?? existsSync;
16
+ this.uuid = dependencies.uuid ?? randomUUID;
17
+ }
18
+ async download(input) {
19
+ const invalid = validateDownloadInput(input);
20
+ if (invalid != null)
21
+ return invalid;
22
+ if (input.groupedId != null && input.groupedMessages == null) {
23
+ return {
24
+ ok: false,
25
+ error: {
26
+ code: 'download_grouped_id_not_resolved',
27
+ message: `Grouped album ${input.groupedId} was not resolved from the local message cache.`,
28
+ },
29
+ };
30
+ }
31
+ const targets = await this.collectTargets(input);
32
+ if ((input.messageId != null || input.groupedId != null) && input.attachment != null && targets.length === 0) {
33
+ return {
34
+ ok: false,
35
+ error: {
36
+ code: 'download_attachment_not_found',
37
+ message: `${input.groupedId == null ? `Message ${input.messageId}` : `Grouped album ${input.groupedId}`} does not have attachment ${input.attachment}.`,
38
+ },
39
+ };
40
+ }
41
+ const result = {
42
+ chat: input.chat,
43
+ output: input.output,
44
+ requested: targets.length,
45
+ downloaded: 0,
46
+ skipped: this.lastSkipped,
47
+ failed: 0,
48
+ flood_waits: 0,
49
+ files: [],
50
+ failures: [],
51
+ };
52
+ await mkdir(input.output, { recursive: true });
53
+ await this.runDownloads(targets, Math.max(1, Math.floor(input.concurrency ?? 3)), result);
54
+ result.files.sort((left, right) => right.msg_id - left.msg_id || left.attachment - right.attachment);
55
+ const output = { ...result, human: downloadSummary(result) };
56
+ if (result.failed > 0) {
57
+ return {
58
+ ok: false,
59
+ error: {
60
+ code: 'download_partial_failure',
61
+ message: 'Download completed with one or more attachment failures.',
62
+ details: output,
63
+ },
64
+ };
65
+ }
66
+ return { ok: true, data: result, human: output.human };
67
+ }
68
+ lastSkipped = 0;
69
+ async collectTargets(input) {
70
+ this.lastSkipped = 0;
71
+ if (input.groupedMessages != null)
72
+ return this.targetsFromGroupedMessages(input.groupedMessages, input);
73
+ const targets = [];
74
+ const reserved = new Set();
75
+ const lower = lowerMessageId(input);
76
+ const upper = upperMessageId(input);
77
+ const minId = lower == null ? undefined : lower - 1;
78
+ for await (const page of this.source.iterHistoryPages({
79
+ chat: input.chat,
80
+ ...(input.since == null ? {} : { since: input.since }),
81
+ ...(input.until == null ? {} : { until: input.until }),
82
+ ...(minId == null ? {} : { minId }),
83
+ })) {
84
+ for (const message of page) {
85
+ if (lower != null && message.msg_id < lower)
86
+ continue;
87
+ if (upper != null && message.msg_id > upper)
88
+ continue;
89
+ if (!matchesDateRange(message, input))
90
+ continue;
91
+ if (message.attachment?.downloadable !== true) {
92
+ if (message.attachment != null)
93
+ this.lastSkipped += 1;
94
+ continue;
95
+ }
96
+ const attachmentNumber = 1;
97
+ if (input.attachment != null && input.attachment !== attachmentNumber)
98
+ continue;
99
+ const destination = uniqueDestination(input.output, fileNameForMessage(message), this.exists, reserved);
100
+ reserved.add(destination);
101
+ targets.push({ chat: input.chat, message, attachment: attachmentNumber, destination });
102
+ }
103
+ }
104
+ return targets;
105
+ }
106
+ targetsFromGroupedMessages(messages, input) {
107
+ const reserved = new Set();
108
+ const ordered = [...messages].sort((left, right) => left.msg_id - right.msg_id);
109
+ const targets = [];
110
+ ordered.forEach((message, index) => {
111
+ const attachmentNumber = index + 1;
112
+ if (input.attachment != null && input.attachment !== attachmentNumber)
113
+ return;
114
+ if (message.attachment?.downloadable !== true) {
115
+ if (message.attachment != null)
116
+ this.lastSkipped += 1;
117
+ return;
118
+ }
119
+ const destination = uniqueDestination(input.output, fileNameForMessage(message), this.exists, reserved);
120
+ reserved.add(destination);
121
+ targets.push({ chat: input.chat, message, attachment: attachmentNumber, destination });
122
+ });
123
+ return targets;
124
+ }
125
+ async runDownloads(targets, concurrency, result) {
126
+ let index = 0;
127
+ const worker = async () => {
128
+ while (index < targets.length) {
129
+ const target = targets[index];
130
+ index += 1;
131
+ await this.downloadOne(target, result);
132
+ }
133
+ };
134
+ await Promise.all(Array.from({ length: Math.min(concurrency, targets.length) }, worker));
135
+ }
136
+ async downloadOne(target, result) {
137
+ await mkdir(dirname(target.destination), { recursive: true });
138
+ const temporary = join(dirname(target.destination), `.telegram-cli-download-${this.uuid()}.part`);
139
+ const handle = await open(temporary, 'wx');
140
+ await handle.close();
141
+ try {
142
+ let floodRetries = 0;
143
+ while (true) {
144
+ try {
145
+ await this.source.downloadMedia({
146
+ chat: target.chat,
147
+ messageId: target.message.msg_id,
148
+ destination: temporary,
149
+ });
150
+ break;
151
+ }
152
+ catch (error) {
153
+ const seconds = floodWaitSeconds(error);
154
+ if (!Number.isFinite(seconds) || floodRetries >= MAX_FLOOD_RETRIES)
155
+ throw error;
156
+ floodRetries += 1;
157
+ result.flood_waits += 1;
158
+ await this.sleep((seconds + 1) * 1000);
159
+ }
160
+ }
161
+ await rename(temporary, target.destination);
162
+ result.downloaded += 1;
163
+ result.files.push({
164
+ chat_id: target.message.chat_id,
165
+ msg_id: target.message.msg_id,
166
+ attachment: target.attachment,
167
+ path: target.destination,
168
+ });
169
+ }
170
+ catch (error) {
171
+ result.failed += 1;
172
+ result.failures.push({
173
+ msg_id: target.message.msg_id,
174
+ attachment: target.attachment,
175
+ error: errorMessage(error),
176
+ });
177
+ }
178
+ finally {
179
+ await rm(temporary, { force: true }).catch(() => undefined);
180
+ }
181
+ }
182
+ }
183
+ function validateDownloadInput(input) {
184
+ if (String(input.chat).trim() === '')
185
+ return invalidOption('chat must be a non-empty string.');
186
+ if (!input.output.trim())
187
+ return invalidOption('output must be a non-empty path.');
188
+ if (input.messageId != null && !isPositiveInteger(input.messageId))
189
+ return invalidOption('message id must be a positive integer.');
190
+ if (input.attachment != null && !isPositiveInteger(input.attachment))
191
+ return invalidOption('attachment must be a positive integer.');
192
+ if (input.fromId != null && !isPositiveInteger(input.fromId))
193
+ return invalidOption('from id must be a positive integer.');
194
+ if (input.toId != null && !isPositiveInteger(input.toId))
195
+ return invalidOption('to id must be a positive integer.');
196
+ if (input.concurrency != null && !isPositiveInteger(input.concurrency))
197
+ return invalidOption('concurrency must be a positive integer.');
198
+ if (input.since != null && input.until != null && input.since.getTime() >= input.until.getTime()) {
199
+ return invalidOption('since must be earlier than until.');
200
+ }
201
+ const scopes = [
202
+ input.messageId != null,
203
+ input.groupedId != null,
204
+ input.fromId != null || input.toId != null,
205
+ input.since != null || input.until != null,
206
+ input.all === true,
207
+ ].filter(Boolean).length;
208
+ if (scopes !== 1) {
209
+ return invalidOption('Select exactly one download scope: message id, --grouped-id, --from/--to, --date/--since/--until, or --all.');
210
+ }
211
+ if (input.groupedId != null && input.groupedId.trim() === '')
212
+ return invalidOption('grouped id must be a non-empty string.');
213
+ if (input.attachment != null && input.messageId == null && input.groupedId == null) {
214
+ return invalidOption('--attachment can only be used with a single message id or --grouped-id.');
215
+ }
216
+ return null;
217
+ }
218
+ function invalidOption(message) {
219
+ return { ok: false, error: { code: 'invalid_option', message } };
220
+ }
221
+ function isPositiveInteger(value) {
222
+ return Number.isInteger(value) && value > 0;
223
+ }
224
+ function lowerMessageId(input) {
225
+ if (input.messageId != null)
226
+ return input.messageId;
227
+ if (input.fromId != null && input.toId != null)
228
+ return Math.min(input.fromId, input.toId);
229
+ return input.fromId ?? input.toId;
230
+ }
231
+ function upperMessageId(input) {
232
+ if (input.messageId != null)
233
+ return input.messageId;
234
+ if (input.fromId != null && input.toId != null)
235
+ return Math.max(input.fromId, input.toId);
236
+ return input.fromId ?? input.toId;
237
+ }
238
+ function matchesDateRange(message, input) {
239
+ const timestamp = Date.parse(message.timestamp);
240
+ if (!Number.isFinite(timestamp))
241
+ return false;
242
+ if (input.since != null && timestamp < input.since.getTime())
243
+ return false;
244
+ if (input.until != null && timestamp >= input.until.getTime())
245
+ return false;
246
+ return true;
247
+ }
248
+ function fileNameForMessage(message) {
249
+ const raw = message.attachment?.file_name?.trim();
250
+ if (raw)
251
+ return raw;
252
+ const extension = extensionForAttachment(message.attachment?.type);
253
+ return `${message.chat_id}-${message.msg_id}.${extension}`;
254
+ }
255
+ function extensionForAttachment(type) {
256
+ switch (type?.toLowerCase()) {
257
+ case 'photo':
258
+ return 'jpg';
259
+ case 'video':
260
+ return 'mp4';
261
+ case 'audio':
262
+ return 'mp3';
263
+ case 'voice':
264
+ return 'ogg';
265
+ case 'sticker':
266
+ return 'webp';
267
+ case 'animation':
268
+ return 'mp4';
269
+ default:
270
+ return 'bin';
271
+ }
272
+ }
273
+ function uniqueDestination(directory, fileName, exists, reserved) {
274
+ const safeName = sanitizeAttachmentFileName(fileName);
275
+ let destination = join(directory, safeName);
276
+ if (!exists(destination) && !reserved.has(destination))
277
+ return destination;
278
+ const extension = extname(safeName);
279
+ const baseName = parse(safeName).name;
280
+ let index = 2;
281
+ do {
282
+ destination = join(directory, `${baseName} (${index})${extension}`);
283
+ index += 1;
284
+ } while (exists(destination) || reserved.has(destination));
285
+ return destination;
286
+ }
287
+ function floodWaitSeconds(error) {
288
+ if (error != null && typeof error === 'object') {
289
+ const maybe = error;
290
+ if (typeof maybe.seconds === 'number' && Number.isFinite(maybe.seconds))
291
+ return maybe.seconds;
292
+ const text = typeof maybe.text === 'string' ? maybe.text : typeof maybe.message === 'string' ? maybe.message : '';
293
+ const match = /FLOOD_WAIT_(\d+)/.exec(text);
294
+ if (match != null)
295
+ return Number(match[1]);
296
+ }
297
+ return Number.NaN;
298
+ }
299
+ function errorMessage(error) {
300
+ return error instanceof Error ? error.message : String(error);
301
+ }
302
+ function downloadSummary(result) {
303
+ return {
304
+ kind: 'summary',
305
+ title: 'Download',
306
+ fields: [
307
+ { label: 'Requested', value: String(result.requested) },
308
+ { label: 'Downloaded', value: String(result.downloaded), tone: result.failed === 0 ? 'success' : 'warning' },
309
+ { label: 'Skipped', value: String(result.skipped) },
310
+ { label: 'Failed', value: String(result.failed), tone: result.failed === 0 ? 'default' : 'danger' },
311
+ { label: 'Flood Waits', value: String(result.flood_waits), tone: result.flood_waits === 0 ? 'default' : 'warning' },
312
+ { label: 'Output', value: result.output },
313
+ ],
314
+ table: {
315
+ columns: ['MESSAGE', 'ATTACHMENT', 'PATH'],
316
+ rows: result.files.map((file) => [String(file.msg_id), String(file.attachment), file.path]),
317
+ emptyText: 'No media downloaded.',
318
+ },
319
+ };
320
+ }
321
+ //# sourceMappingURL=download-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download-service.js","sourceRoot":"","sources":["../../src/services/download-service.ts"],"names":[],"mappings":"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"}
@@ -13,10 +13,13 @@ export class SyncService {
13
13
  const invalid = validateHistoryOptions(options);
14
14
  if (invalid)
15
15
  return invalid;
16
+ const chatId = this.db.resolveChatId(options.chat);
17
+ const offset = chatId == null ? null : this.db.getFirstMsgOffset(chatId);
16
18
  try {
17
19
  const messages = await this.tg.fetchHistory({
18
20
  chat: parseChat(options.chat),
19
21
  limit: options.limit,
22
+ ...(offset == null ? {} : { offset }),
20
23
  pageDelay: options.pageDelay,
21
24
  onProgress: options.onProgress,
22
25
  });
@@ -86,18 +89,26 @@ export class SyncService {
86
89
  const results = {};
87
90
  const failures = {};
88
91
  for (let index = 0; index < selected.length; index += 1) {
92
+ if (options.stopSignal?.aborted)
93
+ break;
89
94
  const dialog = selected[index];
90
95
  const lastId = this.db.getLastMsgId(dialog.id) ?? 0;
91
96
  const limit = lastId === 0 && options.limit > FIRST_SYNC_LIMIT ? FIRST_SYNC_LIMIT : options.limit;
97
+ const onProgress = options.onProgress == null
98
+ ? undefined
99
+ : (count) => options.onProgress?.(dialog.name, count);
100
+ options.onChatStart?.(dialog.name);
92
101
  try {
93
- const messages = await this.tg.fetchHistory({ chat: dialog.id, limit, minId: lastId, pageDelay: 1 });
102
+ const messages = await this.tg.fetchHistory({ chat: dialog.id, limit, minId: lastId, pageDelay: 1, onProgress });
94
103
  results[dialog.name] = this.db.insertBatch(messages);
104
+ options.onChatComplete?.(dialog.name, results[dialog.name]);
95
105
  }
96
106
  catch (error) {
97
107
  results[dialog.name] = 0;
98
108
  failures[dialog.name] = errorMessage(error);
109
+ options.onChatComplete?.(dialog.name, 0, failures[dialog.name]);
99
110
  }
100
- if (options.delay > 0 && index < selected.length - 1) {
111
+ if (!options.stopSignal?.aborted && options.delay > 0 && index < selected.length - 1) {
101
112
  const jitter = options.delay * (Math.random() * 0.4 - 0.2);
102
113
  await delayMs((options.delay + jitter) * 1000);
103
114
  }
@@ -108,7 +119,7 @@ export class SyncService {
108
119
  .map(([name]) => name);
109
120
  const data = {
110
121
  new_messages: Object.values(results).reduce((sum, count) => sum + count, 0),
111
- chats: selected.length,
122
+ chats: Object.keys(results).length,
112
123
  updated_chats,
113
124
  results,
114
125
  failures,
@@ -1 +1 @@
1
- {"version":3,"file":"sync-service.js","sourceRoot":"","sources":["../../src/services/sync-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sync-service.js","sourceRoot":"","sources":["../../src/services/sync-service.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,7 @@ import { tmpdir } from 'node:os';
5
5
  import { dirname, join } from 'node:path';
6
6
  import { getDbPath } from '../config/env.js';
7
7
  import { canonicalChatId } from './chat-resolver.js';
8
+ import { extractGroupedId } from '../telegram/raw-message.js';
8
9
  let snapshotCopyHook;
9
10
  export function __setMessageDbSnapshotCopyHookForTests(hook) {
10
11
  const previous = snapshotCopyHook;
@@ -64,6 +65,7 @@ export class MessageDB {
64
65
  content TEXT,
65
66
  timestamp TEXT NOT NULL,
66
67
  raw_json TEXT,
68
+ preview_jpeg_base64 TEXT,
67
69
  UNIQUE(platform, chat_id, msg_id)
68
70
  );
69
71
  CREATE INDEX IF NOT EXISTS idx_messages_chat_ts ON messages(chat_id, timestamp);
@@ -72,6 +74,7 @@ export class MessageDB {
72
74
  CREATE INDEX IF NOT EXISTS idx_messages_content ON messages(content);
73
75
  CREATE INDEX IF NOT EXISTS idx_messages_sender ON messages(sender_name);
74
76
  `);
77
+ this.ensurePreviewColumn();
75
78
  }
76
79
  static async openReadonly(path) {
77
80
  const { snapshotDir, snapshotPath } = await createConsistentSnapshotAsync(path);
@@ -88,8 +91,8 @@ export class MessageDB {
88
91
  return 0;
89
92
  const stmt = this.db.prepare(`
90
93
  INSERT OR IGNORE INTO messages
91
- (platform, chat_id, chat_name, msg_id, sender_id, sender_name, content, timestamp, raw_json)
92
- VALUES (@platform, @chat_id, @chat_name, @msg_id, @sender_id, @sender_name, @content, @timestamp, @raw_json)
94
+ (platform, chat_id, chat_name, msg_id, sender_id, sender_name, content, timestamp, raw_json, preview_jpeg_base64)
95
+ VALUES (@platform, @chat_id, @chat_name, @msg_id, @sender_id, @sender_name, @content, @timestamp, @raw_json, @preview_jpeg_base64)
93
96
  `);
94
97
  let inserted = 0;
95
98
  const tx = this.db.transaction((rows) => {
@@ -103,8 +106,8 @@ export class MessageDB {
103
106
  insertMessage(message) {
104
107
  const stmt = this.db.prepare(`
105
108
  INSERT OR IGNORE INTO messages
106
- (platform, chat_id, chat_name, msg_id, sender_id, sender_name, content, timestamp, raw_json)
107
- VALUES (@platform, @chat_id, @chat_name, @msg_id, @sender_id, @sender_name, @content, @timestamp, @raw_json)
109
+ (platform, chat_id, chat_name, msg_id, sender_id, sender_name, content, timestamp, raw_json, preview_jpeg_base64)
110
+ VALUES (@platform, @chat_id, @chat_name, @msg_id, @sender_id, @sender_name, @content, @timestamp, @raw_json, @preview_jpeg_base64)
108
111
  `);
109
112
  return this.insertPrepared(stmt, message) === 1;
110
113
  }
@@ -156,10 +159,24 @@ export class MessageDB {
156
159
  getMessagesPage(options) {
157
160
  const params = [canonicalChatId(options.chatId)];
158
161
  const conditions = ['chat_id = ?'];
159
- const filter = options.q?.trim();
160
- if (filter) {
162
+ const q = options.q?.trim();
163
+ if (q) {
164
+ conditions.push('(content LIKE ? OR sender_name LIKE ? OR CAST(sender_id AS TEXT) LIKE ?)');
165
+ params.push(`%${q}%`, `%${q}%`, `%${q}%`);
166
+ }
167
+ if (options.senderId != null) {
168
+ conditions.push('sender_id = ?');
169
+ params.push(options.senderId);
170
+ }
171
+ const senderName = options.senderName?.trim();
172
+ if (senderName) {
173
+ conditions.push('sender_name LIKE ?');
174
+ params.push(`%${senderName}%`);
175
+ }
176
+ const text = options.text?.trim();
177
+ if (text) {
161
178
  conditions.push('content LIKE ?');
162
- params.push(`%${filter}%`);
179
+ params.push(`%${text}%`);
163
180
  }
164
181
  if (options.since) {
165
182
  conditions.push('timestamp >= ?');
@@ -174,18 +191,24 @@ export class MessageDB {
174
191
  conditions.push('(timestamp, id) < (?, ?)');
175
192
  params.push(cursor.timestamp, cursor.id);
176
193
  }
194
+ const total = this.db.prepare(`
195
+ SELECT COUNT(*) AS count FROM messages INDEXED BY idx_messages_chat_recent
196
+ WHERE ${conditions.join(' AND ')}
197
+ `).get(...params).count;
177
198
  const limit = clampInteger(options.limit, 50, 1, 100);
199
+ const offset = Math.max(0, Math.trunc(options.offset ?? 0));
178
200
  const rows = this.db.prepare(`
179
201
  SELECT * FROM messages INDEXED BY idx_messages_chat_recent
180
202
  WHERE ${conditions.join(' AND ')}
181
203
  ORDER BY timestamp DESC, id DESC
182
204
  LIMIT ?
183
- `).all(...params, limit + 1);
205
+ OFFSET ?
206
+ `).all(...params, limit + 1, offset);
184
207
  const items = rows.slice(0, limit);
185
208
  const next_cursor = rows.length > limit && items.length > 0
186
209
  ? encodeMessageCursor(items[items.length - 1])
187
210
  : null;
188
- return { items, next_cursor };
211
+ return { items, total, next_cursor };
189
212
  }
190
213
  getMessagesByKeys(keys) {
191
214
  if (keys.length === 0)
@@ -202,6 +225,14 @@ export class MessageDB {
202
225
  });
203
226
  return read(keys);
204
227
  }
228
+ findMessagesByGroupedId(chatId, groupedId) {
229
+ const rows = this.db.prepare(`
230
+ SELECT * FROM messages
231
+ WHERE platform = 'telegram' AND chat_id = ? AND raw_json IS NOT NULL
232
+ ORDER BY msg_id ASC
233
+ `).all(canonicalChatId(chatId));
234
+ return rows.filter((row) => extractGroupedId(row.raw_json) === groupedId);
235
+ }
205
236
  getToday(options = {}) {
206
237
  const [start, nextStart] = this.todayRange(options.tzOffsetHours);
207
238
  const params = [start, nextStart];
@@ -395,14 +426,19 @@ export class MessageDB {
395
426
  return { sql: `SELECT * FROM messages WHERE ${conditions.join(' AND ')}`, params };
396
427
  }
397
428
  insertPrepared(stmt, row) {
398
- const { preview_jpeg_base64, ...persisted } = row;
399
- void preview_jpeg_base64;
400
429
  return stmt.run({
401
- ...persisted,
430
+ ...row,
402
431
  chat_id: canonicalChatId(row.chat_id),
403
432
  raw_json: row.raw_json == null ? null : JSON.stringify(row.raw_json),
433
+ preview_jpeg_base64: row.preview_jpeg_base64 ?? null,
404
434
  }).changes;
405
435
  }
436
+ ensurePreviewColumn() {
437
+ const columns = this.db.prepare('PRAGMA table_info(messages)').all();
438
+ if (columns.some((column) => column.name === 'preview_jpeg_base64'))
439
+ return;
440
+ this.db.exec('ALTER TABLE messages ADD COLUMN preview_jpeg_base64 TEXT');
441
+ }
406
442
  addFilters(conditions, params, options, tableAlias) {
407
443
  const prefix = tableAlias ? `${tableAlias}.` : '';
408
444
  if (options.chatId != null) {