diff options
Diffstat (limited to 'src/format/text.js')
| -rw-r--r-- | src/format/text.js | 51 |
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'); +} |