85 lines
2.0 KiB
TypeScript
85 lines
2.0 KiB
TypeScript
export type MomentAsset = {
|
|
id: string;
|
|
capture_ts_utc: string;
|
|
};
|
|
|
|
export type MomentCluster = {
|
|
day: string;
|
|
start: string;
|
|
end: string;
|
|
count: number;
|
|
assets: MomentAsset[];
|
|
};
|
|
|
|
const MOMENT_WINDOW_MINUTES = 30;
|
|
const MOMENT_WINDOW_MS = MOMENT_WINDOW_MINUTES * 60 * 1000;
|
|
|
|
function dayKeyFromIso(iso: string) {
|
|
const d = new Date(iso);
|
|
const yyyy = d.getUTCFullYear();
|
|
const mm = String(d.getUTCMonth() + 1).padStart(2, "0");
|
|
const dd = String(d.getUTCDate()).padStart(2, "0");
|
|
return `${yyyy}-${mm}-${dd}`;
|
|
}
|
|
|
|
export function clusterMoments(input: MomentAsset[]): MomentCluster[] {
|
|
const byDay = new Map<string, MomentAsset[]>();
|
|
|
|
for (const asset of input) {
|
|
if (!asset.capture_ts_utc) continue;
|
|
const key = dayKeyFromIso(asset.capture_ts_utc);
|
|
const list = byDay.get(key);
|
|
if (list) list.push(asset);
|
|
else byDay.set(key, [asset]);
|
|
}
|
|
|
|
const clusters: MomentCluster[] = [];
|
|
|
|
for (const [day, assets] of byDay) {
|
|
const sorted = [...assets].sort((a, b) =>
|
|
a.capture_ts_utc.localeCompare(b.capture_ts_utc),
|
|
);
|
|
|
|
let current: MomentAsset[] = [];
|
|
let lastTs: number | null = null;
|
|
|
|
for (const asset of sorted) {
|
|
const ts = new Date(asset.capture_ts_utc).getTime();
|
|
if (!Number.isFinite(ts)) continue;
|
|
|
|
if (lastTs === null || ts - lastTs <= MOMENT_WINDOW_MS) {
|
|
current.push(asset);
|
|
} else {
|
|
const start = current[0]?.capture_ts_utc;
|
|
const end = current[current.length - 1]?.capture_ts_utc;
|
|
if (start && end) {
|
|
clusters.push({
|
|
day,
|
|
start,
|
|
end,
|
|
count: current.length,
|
|
assets: current,
|
|
});
|
|
}
|
|
current = [asset];
|
|
}
|
|
|
|
lastTs = ts;
|
|
}
|
|
|
|
if (current.length) {
|
|
const start = current[0].capture_ts_utc;
|
|
const end = current[current.length - 1].capture_ts_utc;
|
|
clusters.push({
|
|
day,
|
|
start,
|
|
end,
|
|
count: current.length,
|
|
assets: current,
|
|
});
|
|
}
|
|
}
|
|
|
|
return clusters;
|
|
}
|