diff --git a/content.js b/content.js index b890b9c..72f375a 100644 --- a/content.js +++ b/content.js @@ -195,13 +195,22 @@ data.weeklyResetText = resetText; // Parsear "Se restablece vie, 4:59" para obtener día y hora - const resetMatch = resetText.match(/Se restablece\s+(\w+),?\s*([\d:]+)/i); + const resetMatch = resetText.match(/Se restablece\s+([a-záéíóúñü]+),?\s*([\d:]+)/i); if (resetMatch) { const dayAbbr = resetMatch[1].toLowerCase(); data.resetHour = resetMatch[2]; - // Encontrar el índice del día - data.resetDayIndex = DAYS_ES.findIndex(d => d === dayAbbr || d.startsWith(dayAbbr.substring(0, 3))); + // Encontrar el índice del día (comparar primeras 3 letras sin acentos) + const normalize = s => s.normalize('NFD').replace(/[\u0300-\u036f]/g, ''); + const dayAbbrNorm = normalize(dayAbbr); + data.resetDayIndex = DAYS_ES.findIndex(d => { + const dNorm = normalize(d); + return dNorm === dayAbbrNorm || dNorm.startsWith(dayAbbrNorm.substring(0, 3)) || dayAbbrNorm.startsWith(dNorm.substring(0, 3)); + }); + + console.log('[Claude Usage Tracker] Reset parsed:', dayAbbr, '->', data.resetDayIndex, 'hour:', data.resetHour); + } else { + console.log('[Claude Usage Tracker] Reset text no match:', resetText); } } } @@ -236,6 +245,7 @@ /** * Calcula el desglose diario basado en los datos reales * Usa HORAS transcurridas para mayor precisión + * Divide el día de reinicio en dos partes: inicio (después del reinicio) y fin (antes del reinicio) */ function calculateDailyUsage(pageData) { const { weeklyUsage, resetDayIndex, resetHour } = pageData; @@ -246,14 +256,16 @@ // Calcular el momento exacto del último reinicio const [resetH, resetM] = (resetHour || '5:00').split(':').map(Number); + const resetHourDecimal = resetH + (resetM || 0) / 60; - // Encontrar la fecha del último reinicio + // Encontrar la fecha del último reinicio (usar effectiveResetDayIndex más abajo) + const effectiveResetIdx = resetDayIndex >= 0 ? resetDayIndex : 5; let lastResetDate = new Date(now); - let daysSinceReset = todayIndex - resetDayIndex; + let daysSinceReset = todayIndex - effectiveResetIdx; if (daysSinceReset < 0) daysSinceReset += 7; if (daysSinceReset === 0) { // Es el día de reinicio, ¿ya pasó la hora? - if (now.getHours() < resetH || (now.getHours() === resetH && now.getMinutes() < resetM)) { + if (currentHour < resetHourDecimal) { daysSinceReset = 7; // Aún no ha reiniciado, usar el de la semana pasada } } @@ -279,88 +291,126 @@ const avgUsagePerHour = hoursElapsed > 0 ? weeklyUsage / hoursElapsed : 0; const idealUsagePerHour = 100 / totalWeekHours; - // La semana empieza el mismo día del reinicio (ej: viernes) - // El primer día es el día del reinicio, desde la hora de reinicio - const startDayIndex = resetDayIndex; - - // Calcular la posición del día actual dentro de la semana de facturación - // Posición 0 = día del reinicio, posición 1 = día siguiente, etc. - let todayPositionInWeek = todayIndex - resetDayIndex; - if (todayPositionInWeek < 0) todayPositionInWeek += 7; + // Nombre del día de reinicio (con fallback, reutilizar effectiveResetIdx) + const effectiveResetDayIndex = effectiveResetIdx; + const resetDayName = DAYS_ES_DISPLAY[effectiveResetDayIndex] || 'Vie'; + const resetDayFullName = DAYS_FULL_ES[effectiveResetDayIndex] || 'Viernes'; const dailyBreakdown = []; - for (let i = 0; i < 7; i++) { - const dayIndex = (startDayIndex + i) % 7; - const isToday = (i === todayPositionInWeek); - const isPast = (i < todayPositionInWeek); - const isFuture = (i > todayPositionInWeek); + // Estructura: 8 segmentos + // 0: Día reinicio (inicio) - desde resetHour hasta 24:00 + // 1-6: Días completos (sáb, dom, lun, mar, mié, jue si reinicio es viernes) + // 7: Día reinicio (fin) - desde 00:00 hasta resetHour + + for (let i = 0; i < 8; i++) { + let dayIndex, dayName, dayFullName, dayTotalHours, isResetDayStart, isResetDayEnd; - // Calcular cuántas horas de este día han transcurrido + if (i === 0) { + // Primer segmento: día de reinicio (parte después del reinicio) + dayIndex = effectiveResetDayIndex; + dayName = resetDayName; + dayFullName = resetDayFullName + ' (inicio)'; + dayTotalHours = 24 - resetHourDecimal; + isResetDayStart = true; + isResetDayEnd = false; + } else if (i === 7) { + // Último segmento: día de reinicio (parte antes del reinicio) + dayIndex = effectiveResetDayIndex; + dayName = resetDayName; + dayFullName = resetDayFullName + ' (fin)'; + dayTotalHours = resetHourDecimal; + isResetDayStart = false; + isResetDayEnd = true; + } else { + // Días intermedios (completos) + dayIndex = (effectiveResetDayIndex + i) % 7; + dayName = DAYS_ES_DISPLAY[dayIndex]; + dayFullName = DAYS_FULL_ES[dayIndex]; + dayTotalHours = 24; + isResetDayStart = false; + isResetDayEnd = false; + } + + // Calcular posición del día actual + let segmentPosition; + if (todayIndex === effectiveResetDayIndex) { + // Hoy es el día de reinicio + if (currentHour >= resetHourDecimal) { + segmentPosition = 0; // Estamos en la parte de inicio + } else { + segmentPosition = 7; // Estamos en la parte de fin (antes del reinicio) + } + } else { + // Día normal + let pos = todayIndex - effectiveResetDayIndex; + if (pos <= 0) pos += 7; + segmentPosition = pos; + } + + const isToday = (i === segmentPosition); + const isPast = (i < segmentPosition); + const isFuture = (i > segmentPosition); + + // Calcular horas transcurridas en este segmento let dayHoursElapsed = 0; if (isPast) { - // Día completo ya pasado - if (i === 0) { - // Primer día (día del reinicio): desde hora de reinicio hasta medianoche - dayHoursElapsed = 24 - (resetH + (resetM || 0) / 60); - } else { - dayHoursElapsed = 24; - } + dayHoursElapsed = dayTotalHours; } else if (isToday) { if (i === 0) { - // Hoy es el día del reinicio: desde hora de reinicio hasta ahora - dayHoursElapsed = currentHour - (resetH + (resetM || 0) / 60); + // Hoy es el día de reinicio, parte inicio + dayHoursElapsed = currentHour - resetHourDecimal; if (dayHoursElapsed < 0) dayHoursElapsed = 0; + } else if (i === 7) { + // Hoy es el día de reinicio, parte fin + dayHoursElapsed = currentHour; } else { - // Día actual normal: desde medianoche hasta ahora + // Día normal dayHoursElapsed = currentHour; } } // Días futuros: dayHoursElapsed = 0 - // Calcular horas totales del día (para el porcentaje de llenado) - let dayTotalHours = 24; - if (i === 0) { - // Primer día: solo cuenta desde la hora de reinicio - dayTotalHours = 24 - (resetH + (resetM || 0) / 60); - } - - // Porcentaje de llenado del día (0-100%) + // Porcentaje de llenado del segmento (0-100%) const dayFillPercent = dayTotalHours > 0 ? (dayHoursElapsed / dayTotalHours) * 100 : 0; - // Uso asignado a este día (promedio distribuido) + // Uso asignado a este segmento (promedio distribuido) let usage = 0; if (dayHoursElapsed > 0 && hoursElapsed > 0) { - // Distribuir el uso total proporcionalmente a las horas transcurridas usage = (dayHoursElapsed / hoursElapsed) * weeklyUsage; } - // Estado basado en si el uso del día está dentro del ideal + // Estado basado en si el uso está dentro del ideal let status = 'pending'; if (dayHoursElapsed > 0) { - const idealForThisDay = (dayHoursElapsed / 24) * idealDailyPercent; - status = usage <= idealForThisDay * 1.1 ? 'good' : - usage <= idealForThisDay * 1.5 ? 'warning' : 'danger'; + const idealForThisSegment = (dayHoursElapsed / totalWeekHours) * 100; + const actualForThisSegment = usage; + status = actualForThisSegment <= idealForThisSegment * 1.1 ? 'good' : + actualForThisSegment <= idealForThisSegment * 1.5 ? 'warning' : 'danger'; } - // Offset para el primer día (horas antes del reinicio que no cuentan) - const dayStartOffsetPercent = (i === 0) ? ((resetH + (resetM || 0) / 60) / 24) * 100 : 0; + // Offset visual (solo para el segmento de inicio del día de reinicio) + const dayStartOffsetPercent = isResetDayStart ? (resetHourDecimal / 24) * 100 : 0; + // Offset final (solo para el segmento de fin del día de reinicio) + const dayEndOffsetPercent = isResetDayEnd ? ((24 - resetHourDecimal) / 24) * 100 : 0; dailyBreakdown.push({ dayIndex, - dayName: DAYS_ES_DISPLAY[dayIndex], - dayFullName: DAYS_FULL_ES[dayIndex], + dayName, + dayFullName, isPast, isToday, isFuture, - isResetDay: i === 0, + isResetDayStart, + isResetDayEnd, usage, - idealUsage: idealDailyPercent, - dayFillPercent, // % del día transcurrido (para llenar la barra) + idealUsage: (dayTotalHours / totalWeekHours) * 100, + dayFillPercent, dayHoursElapsed, dayTotalHours, - dayStartOffsetPercent, // % del día antes del reinicio (hueco a la izquierda) + dayStartOffsetPercent, + dayEndOffsetPercent, status }); } @@ -410,7 +460,7 @@ container.id = 'claude-usage-tracker'; const usagePercent = pageData.weeklyUsage; - const resetDayName = DAYS_FULL_ES[pageData.resetDayIndex] || 'próximo reinicio'; + const resetDayName = DAYS_FULL_ES[pageData.resetDayIndex >= 0 ? pageData.resetDayIndex : 5] || 'próximo reinicio'; const boostStatus = getBoostStatus(); container.innerHTML = ` @@ -434,21 +484,22 @@