Fix lap limits and five-minute stint statistics
This commit is contained in:
@@ -51,6 +51,9 @@ function buildPublicTrainingProfile(state, shareToken, updatedAt, sinceTimestamp
|
||||
timestamp: Math.max(0, Number(entry.timestamp || 0) || 0),
|
||||
lapMs: Math.max(0, Math.round(Number(entry.lapMs || 0) || 0)),
|
||||
sessionId: String(entry.sessionId || ""),
|
||||
sourceId: String(entry.sourceId || entry.driverId || ""),
|
||||
excludedFromPace: Boolean(entry.excludedFromPace),
|
||||
stintBoundary: Boolean(entry.stintBoundary),
|
||||
}))
|
||||
.sort((left, right) => left.timestamp - right.timestamp);
|
||||
const stats = buildPublicTrainingStats(classLaps);
|
||||
@@ -148,9 +151,9 @@ function normalizePublicTrainingWindow(value) {
|
||||
}
|
||||
|
||||
function buildPublicTrainingWindowStats(laps) {
|
||||
const lapTimes = laps.map((lap) => Number(lap.lapMs || 0)).filter((lapMs) => lapMs > 500);
|
||||
const lapTimes = laps.filter((lap) => !lap.excludedFromPace).map((lap) => Number(lap.lapMs || 0)).filter((lapMs) => lapMs > 500);
|
||||
return {
|
||||
laps: lapTimes.length,
|
||||
laps: laps.length,
|
||||
bestLapMs: lapTimes.length ? Math.min(...lapTimes) : 0,
|
||||
averageLapMs: lapTimes.length ? Math.round(lapTimes.reduce((sum, lapMs) => sum + lapMs, 0) / lapTimes.length) : 0,
|
||||
};
|
||||
@@ -171,7 +174,8 @@ function buildPublicTrainingGoal(goal, currentLaps) {
|
||||
}
|
||||
|
||||
function buildPublicTrainingStats(laps) {
|
||||
const lapTimes = laps.map((lap) => lap.lapMs);
|
||||
const paceLaps = laps.filter((lap) => !lap.excludedFromPace);
|
||||
const lapTimes = paceLaps.map((lap) => lap.lapMs);
|
||||
const recent = lapTimes.slice(-30);
|
||||
const previous = lapTimes.slice(Math.max(0, lapTimes.length - 60), Math.max(0, lapTimes.length - 30));
|
||||
const average = (values) => values.length ? Math.round(values.reduce((sum, value) => sum + value, 0) / values.length) : 0;
|
||||
@@ -191,7 +195,7 @@ function buildPublicTrainingStats(laps) {
|
||||
const previousConsistencySpreadPct = spread(previous);
|
||||
const trendSampleReady = recent.length >= 10 && previous.length >= 10;
|
||||
const daily = new Map();
|
||||
laps.forEach((lap) => {
|
||||
paceLaps.forEach((lap) => {
|
||||
const date = new Date(lap.timestamp);
|
||||
const dateKey = Number.isNaN(date.getTime()) ? "unknown" : `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
|
||||
const day = daily.get(dateKey) || { dateKey, laps: 0, totalMs: 0, bestLapMs: 0, latestTimestamp: 0 };
|
||||
@@ -265,24 +269,40 @@ function buildPublicTrainingAchievements(stats) {
|
||||
}
|
||||
|
||||
function splitPublicTrainingStints(laps, breakThresholdMs = 2 * 60 * 1000) {
|
||||
const stints = [];
|
||||
const streams = new Map();
|
||||
(Array.isArray(laps) ? laps : []).forEach((lap) => {
|
||||
const previousStint = stints.at(-1);
|
||||
const previousLap = previousStint?.laps.at(-1);
|
||||
const lapStartedAt = Math.max(0, Number(lap.timestamp || 0) - Number(lap.lapMs || 0));
|
||||
const breakMs = previousLap ? Math.max(0, Number(lap.timestamp || 0) - Number(previousLap.timestamp || 0)) : 0;
|
||||
const startsNewStint = !previousStint
|
||||
|| String(previousLap.sessionId || "") !== String(lap.sessionId || "")
|
||||
|| breakMs > breakThresholdMs;
|
||||
const normalizedLap = {
|
||||
...lap,
|
||||
excludedFromPace: Boolean(previousLap && breakMs > breakThresholdMs && Number(lap.lapMs || 0) > breakThresholdMs),
|
||||
sessionId: String(lap.sessionId || ""),
|
||||
sourceId: String(lap.sourceId || lap.driverId || "default"),
|
||||
timestamp: Number(lap.timestamp || 0),
|
||||
lapMs: Number(lap.lapMs || 0),
|
||||
};
|
||||
if (startsNewStint) {
|
||||
stints.push({ sessionId: String(lap.sessionId || ""), laps: [normalizedLap] });
|
||||
} else {
|
||||
previousStint.laps.push(normalizedLap);
|
||||
}
|
||||
const key = `${normalizedLap.sessionId}:${normalizedLap.sourceId}`;
|
||||
if (!streams.has(key)) streams.set(key, []);
|
||||
streams.get(key).push(normalizedLap);
|
||||
});
|
||||
|
||||
const stints = [];
|
||||
streams.forEach((stream) => {
|
||||
let current = null;
|
||||
stream.sort((left, right) => left.timestamp - right.timestamp).forEach((lap) => {
|
||||
const previousLap = current?.laps.at(-1);
|
||||
const breakMs = previousLap ? Math.max(0, lap.timestamp - previousLap.timestamp) : 0;
|
||||
const detectedBreak = Boolean(previousLap && breakMs > breakThresholdMs);
|
||||
const explicitBoundary = Boolean(lap.stintBoundary);
|
||||
const normalizedLap = {
|
||||
...lap,
|
||||
excludedFromPace: Boolean(lap.excludedFromPace || explicitBoundary || (detectedBreak && lap.lapMs > breakThresholdMs)),
|
||||
stintBoundary: Boolean(explicitBoundary || detectedBreak),
|
||||
};
|
||||
if (!current || detectedBreak || explicitBoundary) {
|
||||
current = { sessionId: lap.sessionId, sourceId: lap.sourceId, laps: [normalizedLap] };
|
||||
stints.push(current);
|
||||
} else {
|
||||
current.laps.push(normalizedLap);
|
||||
}
|
||||
});
|
||||
});
|
||||
return stints;
|
||||
}
|
||||
@@ -319,6 +339,7 @@ function getPublicBestDurationResult(stints, targetMs) {
|
||||
const lastLap = counted.at(-1);
|
||||
if (!lastLap || Number(lastLap.timestamp || 0) < cutoffAt) continue;
|
||||
const totalMs = Number(lastLap.timestamp || 0) - startedAt;
|
||||
if (totalMs > targetMs + Number(lastLap.lapMs || 0)) continue;
|
||||
const lapCount = counted.length;
|
||||
const candidate = {
|
||||
targetMs,
|
||||
|
||||
Reference in New Issue
Block a user