61 lines
2.4 KiB
JavaScript
61 lines
2.4 KiB
JavaScript
|
|
import { mkdirSync } from 'node:fs';
|
|||
|
|
import { readFile, writeFile } from 'node:fs/promises';
|
|||
|
|
import { fileURLToPath } from 'node:url';
|
|||
|
|
|
|||
|
|
import { config, mediaPath } from '../config.js';
|
|||
|
|
import { encrypt } from './crypto.js';
|
|||
|
|
import { logger } from './logger.js';
|
|||
|
|
|
|||
|
|
/** Определяем тип медиа по объекту сообщения GramJS. */
|
|||
|
|
export function detectMedia(message) {
|
|||
|
|
if (!message?.media) return null;
|
|||
|
|
if (message.photo) return 'photo';
|
|||
|
|
if (message.video) return 'video';
|
|||
|
|
if (message.voice) return 'voice';
|
|||
|
|
if (message.videoNote) return 'video_note';
|
|||
|
|
if (message.gif) return 'gif';
|
|||
|
|
if (message.audio) return 'audio';
|
|||
|
|
if (message.sticker) return 'sticker';
|
|||
|
|
if (message.document) return 'document';
|
|||
|
|
return 'media';
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Одноразовые медиа помечены ttlSeconds на самом медиа. Такие файлы Telegram
|
|||
|
|
* стирает у клиента после просмотра — их важно скачать в момент прихода.
|
|||
|
|
*/
|
|||
|
|
export function isOneTime(message) {
|
|||
|
|
const media = message?.media;
|
|||
|
|
const ttl = media?.ttlSeconds ?? media?.photo?.ttlSeconds ?? media?.document?.ttlSeconds;
|
|||
|
|
return Boolean(ttl);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Скачивает медиа сообщения, шифрует и кладёт на диск. Возвращает
|
|||
|
|
* { kind, path } либо null. Имя файла не раскрывает содержимого.
|
|||
|
|
*/
|
|||
|
|
export async function downloadEncrypted(client, message, tag = 'm') {
|
|||
|
|
const kind = detectMedia(message);
|
|||
|
|
if (!kind) return null;
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
const buffer = await client.downloadMedia(message, {});
|
|||
|
|
if (!buffer || !buffer.length) return { kind, path: null };
|
|||
|
|
|
|||
|
|
mkdirSync(mediaPath(), { recursive: true });
|
|||
|
|
const name = `${tag}_${message.id ?? 'x'}_${buffer.length}.enc`;
|
|||
|
|
const full = fileURLToPath(new URL(name, config.mediaDir));
|
|||
|
|
await writeFile(full, encrypt(buffer));
|
|||
|
|
logger.debug(`media: сохранено ${kind} -> ${name} (${buffer.length} б)`);
|
|||
|
|
return { kind, path: name };
|
|||
|
|
} catch (err) {
|
|||
|
|
logger.warn(`media: не удалось скачать ${kind}:`, err.message);
|
|||
|
|
return { kind, path: null };
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/** Читает зашифрованный медиа-файл с диска по имени (как хранится в БД). */
|
|||
|
|
export function readMedia(name) {
|
|||
|
|
return readFile(fileURLToPath(new URL(name, config.mediaDir)));
|
|||
|
|
}
|