aboutsummaryrefslogtreecommitdiffstats
path: root/src/format/text.js
blob: 4cd1ab1e38f4c15adeb96740b457a7897210dc01 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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');
}