aboutsummaryrefslogtreecommitdiffstats
path: root/src/format/text.js
diff options
context:
space:
mode:
authorElvis Claros Castro <elvis@claros.ar>2026-09-26 19:26:33 -0300
committerElvis Claros Castro <elvis@claros.ar>2026-09-26 19:26:33 -0300
commitd80640d01eeb84907e36ff4af33add9081eda17c (patch)
tree27698b34e06e28d111c2196700015d9c82f78274 /src/format/text.js
downloadwa-cli-d80640d01eeb84907e36ff4af33add9081eda17c.tar.gz
wa-cli-d80640d01eeb84907e36ff4af33add9081eda17c.zip
wa-cli: WhatsApp from the terminal, with a neomutt Maildir bridgeHEADmain
Diffstat (limited to 'src/format/text.js')
-rw-r--r--src/format/text.js51
1 files changed, 51 insertions, 0 deletions
diff --git a/src/format/text.js b/src/format/text.js
new file mode 100644
index 0000000..4cd1ab1
--- /dev/null
+++ b/src/format/text.js
@@ -0,0 +1,51 @@
+// "text" format: a human-readable conversation. Returns null if the data is not messages
+// (and the caller falls back to table).
+
+const isMessage = (m) => m && typeof m === 'object' && 'stanzaId' in m && 'chatId' in m;
+
+function when(ts) {
+ const d = new Date(ts * 1000);
+ const p = (n) => String(n).padStart(2, '0');
+ return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`;
+}
+
+export function describeContent(m) {
+ const parts = [];
+ if (m.hasMedia) {
+ const name = m.media?.filename ? ` ${m.media.filename}` : '';
+ parts.push(`[${m.type}${name}]`);
+ } else if (m.type === 'location' && m.location) {
+ parts.push(`[location ${m.location.latitude},${m.location.longitude}${m.location.name ? ` ${m.location.name}` : ''}]`);
+ } else if (m.type === 'vcard' || m.type === 'multi_vcard') {
+ parts.push('[contact]');
+ } else if (m.type === 'revoked') {
+ parts.push('[deleted message]');
+ } else if (m.poll) {
+ parts.push(`[poll] ${m.poll.name}: ${m.poll.options.join(' / ')}`);
+ return parts.join(' ');
+ } else if (!['chat', 'text'].includes(m.type) && !m.body) {
+ parts.push(`[${m.type}]`);
+ }
+ if (m.body) parts.push(m.body);
+ return parts.join(' ');
+}
+
+export function messageLine(m, { chatName } = {}) {
+ const who = m.fromMe ? 'me' : (m.senderName || m.sender);
+ const chat = chatName ? `${chatName} | ` : '';
+ const flags = `${m.isForwarded ? '↪ ' : ''}${m.hasQuotedMsg ? '↩ ' : ''}`;
+ const body = describeContent(m).replace(/\n/g, '\n ');
+ return `[${when(m.timestamp)}] ${chat}${who}: ${flags}${body}`;
+}
+
+export function toText(data, opts = {}) {
+ // +watch event: {event, data}
+ if (data && data.event && data.data !== undefined) {
+ const inner = data.data.message ?? data.data;
+ if (isMessage(inner)) return messageLine(inner, { chatName: inner.chatId });
+ return null;
+ }
+ const list = Array.isArray(data) ? data : [data];
+ if (!list.length || !list.every(isMessage)) return null;
+ return list.map((m) => messageLine(m, opts)).join('\n');
+}