From 318d188495ded02bbc0661bc261d536cfa82fa1b Mon Sep 17 00:00:00 2001 From: Martin Berka Date: Wed, 3 Jun 2026 10:04:36 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20oprava=20pro=20aktu=C3=A1ln=C3=AD=20podo?= =?UTF-8?q?bu=20TechTower?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/restaurants.ts | 139 ++++++++++++++++------- server/src/tests/fixtures/techtower.html | 30 ++--- 2 files changed, 105 insertions(+), 64 deletions(-) diff --git a/server/src/restaurants.ts b/server/src/restaurants.ts index 2eb0d1e..fabbe6b 100644 --- a/server/src/restaurants.ts +++ b/server/src/restaurants.ts @@ -314,53 +314,108 @@ export const getMenuTechTower = async (firstDayOfWeek: Date, mock: boolean = fal } const result: Food[][] = []; - const siblings = thirdTry + + // Čtvrtý pokus (detekce): thirdTry našel , ale nový formát má každý den v jednom

+ // s položkami oddělenými
místo separátních

pro každou položku + const fourthTry = thirdTry && $(font).parent().siblings('p').toArray().some(el => { + const firstChild = $(el).contents().first(); + return firstChild.is('strong') && DAYS_IN_WEEK.includes(firstChild.text().trim().toLocaleLowerCase()); + }); + + const siblings = (fourthTry || thirdTry) ? $(font).parent().siblings('p') : secondTry ? $(font).parent().parent().parent().siblings('p') : $(font).parent().parent().siblings(); - let parsing = false; - let currentDayIndex = 0; - for (let i = 0; i < siblings.length; i++) { - const text = $(siblings.get(i)).text().trim().replace('\t', '').replace('\n', ' '); - if (DAYS_IN_WEEK.includes(text.toLocaleLowerCase())) { - // Zjistíme aktuální index - currentDayIndex = DAYS_IN_WEEK.indexOf(text.toLocaleLowerCase()); - if (!parsing) { - // Našli jsme libovolný den v týdnu a ještě neparsujeme, tak začneme - parsing = true; - } - } else if (parsing) { - if (text.length == 0) { - // Prázdná řádka - bývá na zcela náhodných místech ¯\_(ツ)_/¯ - continue; - } - let price = 'na\xA0váhu'; - let nameRaw = text.replace('•', ''); - if (text.toLowerCase().endsWith('kč')) { - const tmp = text.replace('\xA0', ' ').split(' '); - const split = [tmp.slice(0, -2).join(' ')].concat(tmp.slice(-2)); - price = `${split.slice(1)[0]}\xA0Kč` - nameRaw = split[0].replace('•', ''); - } else if (text.toLowerCase().endsWith(',-')) { - const tmp = text.replace('\xA0', ' ').split(' '); - const split = [tmp.slice(0, -1).join(' ')].concat(tmp.slice(-1)); - price = `${split.slice(1)[0].replace(',-', '')}\xA0Kč` - nameRaw = split[0].replace('•', ''); - } - if (nameRaw.endsWith('–')|| nameRaw.endsWith('—')) { - nameRaw = nameRaw.slice(0, -1).trim(); - } - const parsed = parseAllergens(nameRaw); - result[currentDayIndex] ??= []; - result[currentDayIndex].push({ - amount: '-', - name: parsed.cleanName, - price, - isSoup: isTextSoupName(parsed.cleanName), - allergens: parsed.allergens.length > 0 ? parsed.allergens : undefined, - }) + if (fourthTry) { + siblings.each((_, el) => { + const $el = $(el); + const firstChild = $el.contents().first(); + if (!firstChild.is('strong')) return; + const dayName = firstChild.text().trim().toLocaleLowerCase(); + if (!DAYS_IN_WEEK.includes(dayName)) return; + + const dayIndex = DAYS_IN_WEEK.indexOf(dayName); + result[dayIndex] ??= []; + + const elHtml = $el.html() ?? ''; + const itemLines = elHtml.split(//i).slice(1) + .map(part => $(`${part}`).text().trim()) + .filter(line => line.length > 0); + + for (const text of itemLines) { + let price = 'na\xA0váhu'; + let nameRaw = text.replace('•', ''); + if (text.toLowerCase().endsWith('kč')) { + const tmp = text.replace('\xA0', ' ').split(' '); + const split = [tmp.slice(0, -2).join(' ')].concat(tmp.slice(-2)); + price = `${split.slice(1)[0]}\xA0Kč`; + nameRaw = split[0].replace('•', ''); + } else if (text.toLowerCase().endsWith(',-')) { + const tmp = text.replace('\xA0', ' ').split(' '); + const split = [tmp.slice(0, -1).join(' ')].concat(tmp.slice(-1)); + price = `${split.slice(1)[0].replace(',-', '')}\xA0Kč`; + nameRaw = split[0].replace('•', ''); + } + if (nameRaw.endsWith('–') || nameRaw.endsWith('—')) { + nameRaw = nameRaw.slice(0, -1).trim(); + } + + const parsed = parseAllergens(nameRaw); + result[dayIndex].push({ + amount: '-', + name: parsed.cleanName, + price, + isSoup: isTextSoupName(parsed.cleanName), + allergens: parsed.allergens.length > 0 ? parsed.allergens : undefined, + }); + } + }); + } else { + let parsing = false; + let currentDayIndex = 0; + for (let i = 0; i < siblings.length; i++) { + const text = $(siblings.get(i)).text().trim().replace('\t', '').replace('\n', ' '); + if (DAYS_IN_WEEK.includes(text.toLocaleLowerCase())) { + // Zjistíme aktuální index + currentDayIndex = DAYS_IN_WEEK.indexOf(text.toLocaleLowerCase()); + if (!parsing) { + // Našli jsme libovolný den v týdnu a ještě neparsujeme, tak začneme + parsing = true; + } + } else if (parsing) { + if (text.length == 0) { + // Prázdná řádka - bývá na zcela náhodných místech ¯\_(ツ)_/¯ + continue; + } + let price = 'na\xA0váhu'; + let nameRaw = text.replace('•', ''); + if (text.toLowerCase().endsWith('kč')) { + const tmp = text.replace('\xA0', ' ').split(' '); + const split = [tmp.slice(0, -2).join(' ')].concat(tmp.slice(-2)); + price = `${split.slice(1)[0]}\xA0Kč` + nameRaw = split[0].replace('•', ''); + } else if (text.toLowerCase().endsWith(',-')) { + const tmp = text.replace('\xA0', ' ').split(' '); + const split = [tmp.slice(0, -1).join(' ')].concat(tmp.slice(-1)); + price = `${split.slice(1)[0].replace(',-', '')}\xA0Kč` + nameRaw = split[0].replace('•', ''); + } + if (nameRaw.endsWith('–')|| nameRaw.endsWith('—')) { + nameRaw = nameRaw.slice(0, -1).trim(); + } + + const parsed = parseAllergens(nameRaw); + result[currentDayIndex] ??= []; + result[currentDayIndex].push({ + amount: '-', + name: parsed.cleanName, + price, + isSoup: isTextSoupName(parsed.cleanName), + allergens: parsed.allergens.length > 0 ? parsed.allergens : undefined, + }) + } } } diff --git a/server/src/tests/fixtures/techtower.html b/server/src/tests/fixtures/techtower.html index 74bf729..aa497a4 100644 --- a/server/src/tests/fixtures/techtower.html +++ b/server/src/tests/fixtures/techtower.html @@ -1,29 +1,15 @@ -

-
-

- Obědy 12.5.-16.5.2025 -

+
+
+

Jídelní lístek 12.5.-16.5.2025

+

Pondělí
Polévka dne 1
Svíčková na smetaně s knedlíkem 1,3,7 — 149 Kč
Smažený sýr s bramborami 1,3 — 139 Kč

+

Úterý
Česnečka 1
Vepřový guláš s houskovým knedlíkem 1,3 — 145 Kč

+

Středa
Hovězí vývar s nudlemi 1
Kuřecí řízek s bramborami 1 — 139 Kč

+

Čtvrtek
Dršťková polévka 1
Segedínský guláš s knedlíkem 1,3 — 145 Kč

+

Pátek
Rajská polévka s rýží 1
Rizoto s kuřecím masem a zeleninou 1 — 139 Kč

- -

Pondělí

-

• Polévka dne 1

-

• Svíčková na smetaně s knedlíkem 1, 3, 7 149 Kč

-

• Smažený sýr s bramborami 1, 3 139 Kč

-

Úterý

-

• Česnečka 1

-

• Vepřový guláš s houskovým knedlíkem 1, 3 145 Kč

-

Středa

-

• Hovězí vývar s nudlemi 1

-

• Kuřecí řízek s bramborami 1 139 Kč

-

Čtvrtek

-

• Dršťková polévka 1

-

• Segedínský guláš s knedlíkem 1, 3 145 Kč

-

Pátek

-

• Rajská polévka s rýží 1

-

• Rizoto s kuřecím masem a zeleninou 1 139 Kč