#!/usr/bin/env -S npx nodejsscript /* jshint esversion: 11,-W097, -W040, module: true, node: true, expr: true, undef: true *//* global echo, $, pipe, s, fetch, cyclicLoop */ const { version, description }= s.cat("package.json").xargs(JSON.parse); const today= [ 6, 0, 1, 2, 3, 4, 5 ][new Date().getDay()]; $.api() .version(version) .describe(description) .command("pull", "Update article list") .option("--git", "Update git repository") .option("--dry-run", "Dry run") .action(async function pull({ git: is_git= false, ["dry-run"]: dryRun= false, ..._ }= {}){ if(dryRun) is_git= false; if(is_git) s.run`git pull --rebase`; const menicka= await Promise.allSettled([ menickoCukrovarka(), menickoGlobus(), menickoMamafoodbistro() ]) .then(results=> results.filter(p=> p.status!=="rejected" ? true : (echo(p), false)).map(p=> p.value)); const days= [ "pondělí", "úterý", "středa", "čtvrtek", "pátek", "sobota", "neděle" ]; const out_head= description+"\n\n" + days.map((v)=> `[${v}](#${v})`).join(" · "); // anchors for days let out= ""; for(let i= today; i < days.length; i++){ // menicka const day= days[i]; out+= `\n\n## ${day}\n`; out+= menicka.map(dayToMd(day)).join("\n"); } const gen= [ "", "" ]; const target= "README.md"; const readme= s.cat(target); const readme_before= readme.indexOf(gen[0])-1; const readme_today= today===0 ? -1 : readme.indexOf(`## ${days[today]}`, readme_before)-2; out= [ readme.slice(0, readme_before), readme_today < 0 ? gen[0]+out_head : readme.slice(readme_before+1, readme_today), out.replace(/(\*)/g, "\\$1"), gen[1], readme.slice(readme.indexOf("\n", readme.indexOf(gen[1]))+1) ].join("\n"); if(dryRun) echo(out); else s.echo(out).to(target); if(is_git) gitCommit([ target ], "pull"); $.exit(0); }) .parse(); function dayToMd(day){ return function({ symbol, name, url, dny }){ let has= Reflect.has(dny, day); if(!has && (day==="sobota" || day==="neděle") && Reflect.has(dny, "víkend")){ has= true; day= "víkend"; } const section= `[${symbol} ${name}](${url})`; if(!has) return `- ${section}: —`; let out= `- ${section}:`; const { polevky, hlavni }= dny[day]; const food= f=> out+= `\n - ${f}`; polevky.forEach(food); hlavni.forEach(food); return out; }; } function gitCommit(files, des= "not specified"){ if(!files.length || !s.run`git diff --numstat`.trim()) return echo("Nothig todo"); echo("Diff to save"); s.run`git config user.name "Bot"`; s.run`git config user.email "${"zc.murtnec@naj.elrdna".split("").reverse().join("")}"`; s.run`git add ${files}`; s.run`git commit -m "Updated by bot – ${des}"`; s.run`git push`; s.run`git config --remove-section user`; } import { JSDOM, VirtualConsole } from "jsdom"; async function fetchHTML(url){ const res= await fetch(url); if(res.status !== 200) throw new Error(`Fetch failed with status ${res.status}`); let text; if(res.headers.get("Content-Type").includes("charset=windows-1250")) text= await res.arrayBuffer().then(buff=> new TextDecoder('windows-1250').decode(buff)); else text= await res.text(); const virtualConsole = new VirtualConsole(); virtualConsole.on("error", () => { // No-op to skip console errors. }); return (new JSDOM(text, { virtualConsole })).window; } async function menickoMamafoodbistro(){ const url= "https://www.mamafoodbistro.cz/#poledne"; const { document }= await fetchHTML(url); const menicko= document.querySelectorAll("section")[2].getElementsByClassName("sqs-html-content")[1]; const dny= {}; for(const den of menicko.getElementsByTagName("h4")){ const polevka= den.nextElementSibling; if(!polevka) break; let hi= polevka; const hlavni= []; while(( hi= hi.nextElementSibling ) && hi.tagName !== "H4") hlavni.push(hi); Reflect.set(dny, den.textContent.trim().toLowerCase(), { polevky: [ polevka.textContent ], hlavni: hlavni.map(el=> el.textContent), }); } return { name: "MAMAFOOD", symbol: "🍎", url, dny }; } async function menickoCukrovarka(){ const url= "https://www.menicka.cz/api/iframe/?id=8542&continuous=true"; const { document }= await fetchHTML(url); const food= el=> !el ? "—" : el.getElementsByClassName("food")[0].textContent; const dny= {}; for(const den of document.getElementsByClassName("content")){ let name= den.getElementsByTagName("h2")[0].textContent.trim(); name= name.slice(0, name.indexOf(" ")).toLowerCase(); const [ polevka ]= den.getElementsByClassName("soup"); const hlavni= den.getElementsByClassName("main"); Reflect.set(dny, name, { polevky: [ food(polevka) ], hlavni: [ ...hlavni ].map(food), }); if(name==="neděle") break; } return { name: "Jídelna Čakovice", symbol: "🏭", url, dny }; } async function menickoGlobus(){ const url= "https://www.globus.cz/praha-cakovice/sluzby-a-produkty/restaurace#klasicke-menu"; const { document }= await fetchHTML(url); const menicko= document.getElementById("klasicke-menu"); const dny= {}; for(const den of menicko.getElementsByTagName("li")){ const name= den.getElementsByTagName("h3")[0].textContent.trim(); const vse= [ ...den.getElementsByTagName("tr") ].map(el=> el.getElementsByTagName("td")[1].textContent.trim()); Reflect.set(dny, name, { polevky: vse.slice(0, 2), hlavni: vse.slice(2), }); } return { name: "Globus", symbol: "🏪", url, dny }; }