diff --git a/client/src/App.tsx b/client/src/App.tsx
index 829ed7b..1eed593 100644
--- a/client/src/App.tsx
+++ b/client/src/App.tsx
@@ -415,6 +415,7 @@ function App() {
Poslední změny:
- Podpora ručního refresh týdne
+ - Úprava pro přepracovanou podobu stránek Sladovnická
{dayIndex != null &&
diff --git a/server/src/restaurants.ts b/server/src/restaurants.ts
index efb39d4..9d6f681 100644
--- a/server/src/restaurants.ts
+++ b/server/src/restaurants.ts
@@ -23,7 +23,7 @@ const SOUP_NAMES = [
const DAYS_IN_WEEK = ['pondělí', 'úterý', 'středa', 'čtvrtek', 'pátek', 'sobota', 'neděle'];
// URL na týdenní menu jednotlivých restaurací
-const SLADOVNICKA_URL = 'https://sladovnicka.unasplzenchutna.cz/cz/denni-nabidka';
+const SLADOVNICKA_URL = 'https://sladovnicka.unasplzenchutna.cz/cz/#denni-nabidka';
const U_MOTLIKU_URL = 'https://www.umotliku.cz/menu';
const TECHTOWER_URL = 'https://www.equifarm.cz/restaurace-techtower';
const ZASTAVKAUMICHALA_URL = 'https://www.zastavkaumichala.cz';
@@ -78,81 +78,65 @@ export const getMenuSladovnicka = async (firstDayOfWeek: Date, mock: boolean = f
const html = await getHtml(SLADOVNICKA_URL);
const $ = load(html);
- const list = $('ul.tab-links').children();
+ const menuContentElements = $('#daily-menu-content-list').children('[id^="daily-menu-content-"]');
+ // Prozatím předpokládáme, že budou mít vždy elementy pro všech 5 dní v týdnu, i pokud bude zavřeno
+ if (menuContentElements.length < 5) {
+ throw Error("Neočekávaný počet dní v menu Sladovnické: " + menuContentElements.length + ", očekáváno 5 (možná je některý den zavřeno?)");
+ }
+
const result: Food[][] = [];
for (let dayIndex = 0; dayIndex < 5; dayIndex++) {
- const currentDate = new Date(firstDayOfWeek);
- currentDate.setDate(firstDayOfWeek.getDate() + dayIndex);
- const searchedDayText = `${currentDate.getDate()}.${currentDate.getMonth() + 1}.${capitalize(DAYS_IN_WEEK[dayIndex])}`;
- // Najdeme index pro vstupní datum (např. při svátcích bude posunutý)
- // TODO validovat, že vstupní datum je v aktuálním týdnu
- // TODO tenhle způsob je zbytečně komplikovaný - stačilo by hledat rovnou v div.tab-content, protože každý den tam má datum taky (akorát je print-only)
- let index = undefined;
- list.each((i, dayRow) => {
- const rowText = $(dayRow).first().text().trim();
- if (rowText === searchedDayText) {
- index = i;
- }
- })
- if (index === undefined) {
- // Pravděpodobně svátek, nebo je zavřeno
- result[dayIndex] = [{
- amount: undefined,
- name: "Pro daný den nebyla nalezena denní nabídka",
- price: "",
- isSoup: false,
- }];
- continue;
+ const dayChildren = $(menuContentElements[dayIndex]).children();
+ // Prozatím předpokládáme, že budou mít vždy polévku a hlavní jídla
+ if (dayChildren.length < 2) {
+ throw Error("Neočekávaný počet children v menu Sladovnické pro den " + dayIndex + ": " + dayChildren.length + ", očekávány alespoň 2 (polévka a hlavní jídlo)");
}
- // Dle dohledaného indexu najdeme správný tabpanel
- const rows = $('div.tab-content').children();
- if (index >= rows.length) {
- throw Error("V HTML nebyl nalezen řádek menu pro index " + index);
- }
- const tabPanel = $(rows.get(index));
-
- // Opětovná validace, že daný tabpanel je pro vstupní datum
- const headers = tabPanel.find('h2');
- if (headers.length !== 3) {
- throw Error("Neočekávaný počet elementů h2 v menu pro datum " + searchedDayText + ", očekávány 3, ale nalezeno bylo " + headers.length);
- }
- const dayText = $(headers.get(0)).text().trim();
- if (dayText !== searchedDayText) {
- throw Error("Neočekávaný datum na řádce nalezeného dne: '" + dayText + "', ale očekáváno bylo '" + searchedDayText + "'");
- }
-
- // V tabpanelu očekáváme dvě tabulky - pro polévku a pro hlavní jídlo
- const tables = tabPanel.find('table');
- if (tables.length !== 2) {
- throw Error("Neočekávaný počet tabulek na řádce nalezeného dne: " + tables.length + ", ale očekávány byly 2");
- }
- const currentDayFood: Food[] = [];
- // Polévka - div -> table -> tbody -> tr -> 3x td
- const soupCells = $(tables.get(0)).children().first().children().first().children();
+ // Parsování polévky
+ const soupElement = dayChildren.get(0);
+ const soupTable = $(soupElement).find('table tbody tr');
+ const soupCells = soupTable.children('td');
if (soupCells.length !== 3) {
throw Error("Neočekávaný počet buněk v tabulce polévky: " + soupCells.length + ", ale očekávány byly 3");
}
+
+ const soupAmount = sanitizeText($(soupCells.get(0)).text());
+ const soupName = sanitizeText($(soupCells.get(1)).text());
+ const soupPrice = sanitizeText($(soupCells.get(2)).text().replace(' ', '\xA0'));
+
+ // Parsování hlavních jídel
+ const mainCourseElement = dayChildren.get(1);
+ const mainCourseTable = $(mainCourseElement).find('table tbody');
+ const mainCourseRows = mainCourseTable.children('tr');
+
+ const currentDayFood: Food[] = [];
+
+ // Přidáme polévku do seznamu jídel
currentDayFood.push({
- amount: sanitizeText($(soupCells.get(0)).text()),
- name: sanitizeText($(soupCells.get(1)).text()),
- price: sanitizeText($(soupCells.get(2)).text().replace(' ', '\xA0')),
+ amount: soupAmount,
+ name: soupName,
+ price: soupPrice,
isSoup: true,
});
- // Hlavní jídla - div -> table -> tbody -> 3x tr
- const mainCourseRows = $(tables.get(1)).children().first().children();
- mainCourseRows.each((i, foodRow) => {
- const foodCells = $(foodRow).children();
- if (foodCells.length !== 3) {
- throw Error("Neočekávaný počet buněk v řádku jídla: " + foodCells.length + ", ale očekávány byly 3");
+
+ // Projdeme všechny řádky hlavních jídel
+ mainCourseRows.each((i, row) => {
+ const cells = $(row).children('td');
+ const amount = sanitizeText($(cells.get(0)).text());
+ const name = sanitizeText($(cells.get(1)).text());
+ const price = sanitizeText($(cells.get(2)).text().replace(' ', '\xA0'));
+
+ // Přeskočíme prázdné řádky (první řádek může být prázdný)
+ if (name.trim().length > 0) {
+ currentDayFood.push({
+ amount,
+ name,
+ price,
+ isSoup: false,
+ });
}
- currentDayFood.push({
- amount: sanitizeText($(foodCells.get(0)).text()),
- name: sanitizeText($(foodCells.get(1)).text()),
- price: sanitizeText($(foodCells.get(2)).text().replace(' ', '\xA0')),
- isSoup: false,
- });
- })
+ });
+
result[dayIndex] = currentDayFood;
}
return result;