81 lines
2.8 KiB
JavaScript
81 lines
2.8 KiB
JavaScript
// Helper utilities and algorithms
|
|
|
|
/**
|
|
* Format timestamps (supports Unix epoch seconds/ms, strings and ISO dates)
|
|
* @param {string|number|Date} dateVal
|
|
* @returns {string} Formatted HH:MM AM/PM string
|
|
*/
|
|
export function formatTime(dateVal) {
|
|
if (!dateVal) return '';
|
|
let date;
|
|
if (typeof dateVal === 'number') {
|
|
date = new Date(dateVal < 10000000000 ? dateVal * 1000 : dateVal);
|
|
} else if (typeof dateVal === 'string' && /^\d+$/.test(dateVal)) {
|
|
const num = parseInt(dateVal, 10);
|
|
date = new Date(num < 10000000000 ? num * 1000 : num);
|
|
} else {
|
|
date = new Date(dateVal);
|
|
}
|
|
|
|
let hours = date.getHours();
|
|
let minutes = date.getMinutes();
|
|
const ampm = hours >= 12 ? 'PM' : 'AM';
|
|
hours = hours % 12;
|
|
hours = hours ? hours : 12;
|
|
minutes = minutes < 10 ? '0' + minutes : minutes;
|
|
return `${hours}:${minutes} ${ampm}`;
|
|
}
|
|
|
|
/**
|
|
* Adjust outgoing messages backdated behind incoming messages due to clock drift.
|
|
* Uses a 30-second sliding bubble-sort window.
|
|
* @param {Array} messages List of raw messages from WAHA
|
|
* @returns {Array} Compensated chronological message array
|
|
*/
|
|
export function compensateMessageOrdering(messages) {
|
|
if (!Array.isArray(messages)) return [];
|
|
|
|
// Convert timestamps to numeric milliseconds for stable comparison
|
|
const msgs = messages.map(m => {
|
|
let t = m.timestamp;
|
|
if (typeof t === 'number') {
|
|
if (t < 10000000000) t = t * 1000;
|
|
} else {
|
|
t = new Date(t).getTime();
|
|
}
|
|
return { ...m, _time: t };
|
|
});
|
|
|
|
// Initial chronological sort
|
|
msgs.sort((a, b) => a._time - b._time);
|
|
|
|
// Apply drift bubble adjustments
|
|
let changed = true;
|
|
while (changed) {
|
|
changed = false;
|
|
for (let i = 0; i < msgs.length - 1; i++) {
|
|
const current = msgs[i];
|
|
const next = msgs[i + 1];
|
|
const timeDiff = next._time - current._time;
|
|
|
|
// Swap if an outgoing message is sorted before an incoming message within a 30-sec window
|
|
if (current.fromMe && !next.fromMe && timeDiff >= 0 && timeDiff <= 30000) {
|
|
msgs[i] = next;
|
|
msgs[i + 1] = current;
|
|
|
|
// Advance the outgoing message's timestamp to be exactly 1 second after the incoming one
|
|
current._time = next._time + 1000;
|
|
if (typeof current.timestamp === 'number') {
|
|
current.timestamp = Math.floor(current._time / 1000);
|
|
} else {
|
|
current.timestamp = new Date(current._time).toISOString();
|
|
}
|
|
|
|
changed = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Clean up temporary property
|
|
return msgs.map(({ _time, ...m }) => m);
|
|
}
|