From f6fee70cd0af080d4ab9ff2616f79fd11c96c864 Mon Sep 17 00:00:00 2001 From: MDeeApp <6595194+MDeeApp@users.noreply.github.com> Date: Mon, 20 Oct 2025 15:44:46 +0200 Subject: [PATCH] enhanced deadline parsing --- extension/content.js | 63 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/extension/content.js b/extension/content.js index f47fa97..620ee5d 100644 --- a/extension/content.js +++ b/extension/content.js @@ -1678,25 +1678,49 @@ function extractDeadlineFromPostText(postElement) { // German date patterns const patterns = [ - // DD.MM.YYYY or DD.MM.YY - /\b(\d{1,2})\.(\d{1,2})\.(\d{2,4})\b/g, - // DD.MM (without year) - /\b(\d{1,2})\.(\d{1,2})\.\s*(?!\d)/g + // DD.MM.YYYY or DD.MM.YY (with optional time like ", 23:59Uhr") + /\b(\d{1,2})\.(\d{1,2})\.(\d{2,4})(?!\d)/g, + // DD.MM (without year, optional trailing time) + /\b(\d{1,2})\.(\d{1,2})\.(?!\d)/g ]; + const extractTimeAfterIndex = (text, index) => { + const tail = text.slice(index, index + 40); + const timeMatch = /^\s*(?:[,;:-]|\b)?\s*(?:um|ab|bis)?\s*(?:ca\.?)?\s*(\d{1,2})[:.](\d{2})\s*(?:uhr|h)?/i.exec(tail); + if (!timeMatch) { + return null; + } + const hour = parseInt(timeMatch[1], 10); + const minute = parseInt(timeMatch[2], 10); + if (Number.isNaN(hour) || Number.isNaN(minute)) { + return null; + } + if (hour < 0 || hour > 23 || minute < 0 || minute > 59) { + return null; + } + return { hour, minute }; + }; + + const hasInclusiveKeywordNear = (text, index) => { + const windowStart = Math.max(0, index - 40); + const windowText = text.slice(windowStart, index).toLowerCase(); + return /\b(einschlie(?:ß|ss)lich|inklusive|inkl\.)\b/.test(windowText); + }; + const foundDates = []; for (const pattern of patterns) { let match; - while ((match = pattern.exec(fullText)) !== null) { - const day = parseInt(match[1], 10); - const month = parseInt(match[2], 10); - let year = match[3] ? parseInt(match[3], 10) : today.getFullYear(); + while ((match = pattern.exec(fullText)) !== null) { + const day = parseInt(match[1], 10); + const month = parseInt(match[2], 10); + let year = match[3] ? parseInt(match[3], 10) : today.getFullYear(); + const matchIndex = match.index; - // Handle 2-digit years - if (year < 100) { - year += 2000; - } + // Handle 2-digit years + if (year < 100) { + year += 2000; + } // Validate date if (month >= 1 && month <= 12 && day >= 1 && day <= 31) { @@ -1704,6 +1728,13 @@ function extractDeadlineFromPostText(postElement) { // Check if date is valid (e.g., not 31.02.) if (date.getMonth() === month - 1 && date.getDate() === day) { + const timeInfo = extractTimeAfterIndex(fullText, pattern.lastIndex); + if (timeInfo) { + date.setHours(timeInfo.hour, timeInfo.minute, 0, 0); + } else if (hasInclusiveKeywordNear(fullText, matchIndex)) { + date.setHours(23, 59, 0, 0); + } + // Only add if date is in the future if (date > today) { foundDates.push(date); @@ -1721,12 +1752,20 @@ function extractDeadlineFromPostText(postElement) { const monthStr = monthMatch[2].toLowerCase(); const month = monthNames[monthStr]; const year = today.getFullYear(); + const matchIndex = monthMatch.index; if (month && day >= 1 && day <= 31) { const date = new Date(year, month - 1, day, 0, 0, 0, 0); // Check if date is valid if (date.getMonth() === month - 1 && date.getDate() === day) { + const timeInfo = extractTimeAfterIndex(fullText, monthPattern.lastIndex); + if (timeInfo) { + date.setHours(timeInfo.hour, timeInfo.minute, 0, 0); + } else if (hasInclusiveKeywordNear(fullText, matchIndex)) { + date.setHours(23, 59, 0, 0); + } + // If date has passed this year, assume next year if (date <= today) { date.setFullYear(year + 1);