Files
felhom.eu/documentation/audits/website-refresh-2026-10-08/shots/tools/recipe-importer.js
T
admin 67b3fd23d1
gates / gates (push) Failing after 13m1s
website refresh: true numbers (56 apps), claims checked against the capability map, ten missing apps, an English twin of every public page (public, choice B), 404 page; site gates 13-18 + 11 decoys; R-902 opened
Part A: claim table documentation/audits/website-refresh-2026-10-08/claims.md; "100% open source" corrected
from the licence read; unbacked claims cut (firewall, RAID, snapshots, new-machine restore, self-managed
mode, household VPN, "never lost"). Part B: dawarich, docmost, grimmory, homebox, karakeep, mealie, metube,
radicale, recipe-importer, sparkyfitness cards; plant-it and wger cut (not offered). Part C: /en/ twins,
nav language switch, hreflang both ways, sitemap with xhtml:link, og-image-en.png. Part D: site_gates.py
twins/lang/same-apps/no-Hungarian/FAQ-JSON-LD/tail. Operator ruling 9 + choice B in 10-localisation.md §11,
§10.7. Register: R-902 (contact mailer source in no repo); R-813, R-784, R-559 annotated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
2026-10-08 08:29:17 +02:00

47 lines
2.9 KiB
JavaScript

// Recipe Importer screenshots for the website card: on scratch guest 9202, headless Chrome through the box's own
// traefik, passing the setup gate as the household. No recipe site is contacted (a scraped recipe would be a third
// party's text and picture). The app's own settings form is saved with an INVENTED Mealie address and a placeholder
// key (no Mealie exists behind it), which is what opens its import page; the shots are its import and settings pages.
const puppeteer = require('puppeteer');
const fs = require('fs');
const sleep = ms => new Promise(r => setTimeout(r, ms));
const S = JSON.parse(fs.readFileSync('/out/secrets.json'));
const D = process.env.DOMAIN, URL = `https://${process.env.SUB}.${D}`;
const DEMO_URL = 'https://www.example.com/receptek/rakott-krumpli';
(async () => {
const b = await puppeteer.launch({args: ['--no-sandbox', '--ignore-certificate-errors', '--lang=hu-HU',
'--host-resolver-rules=MAP * ' + process.env.TRAEFIK]});
const p = await b.newPage();
await p.setCookie({name: 'felhom_session', value: S.session, domain: `felhom.${D}`, path: '/', secure: true});
await p.setViewport({width: 1280, height: 800});
await p.goto(URL + '/settings', {waitUntil: 'networkidle2'});
await sleep(1000);
const set = async (sel, v) => { const f = await p.$(sel); if (f) { await f.click({clickCount: 3}); await f.type(v); } else console.log('no field', sel); };
await set('input[name=mealie_url]', 'https://recipes.example.hu');
await set('input[name=mealie_api_key]', 'demo-placeholder');
await Promise.all([p.waitForNavigation({waitUntil: 'networkidle2'}).catch(() => {}),
p.$eval('input[name=mealie_url]', el => el.form.submit())]);
await sleep(1000);
console.log('after save', p.url());
await p.screenshot({path: '/out/settings.png'});
await p.goto(URL + '/import', {waitUntil: 'networkidle2'});
await sleep(1500);
console.log('import ->', p.url());
const ta = await p.$('textarea, input[type=url], input[name=url]');
if (ta) await ta.type(DEMO_URL); else console.log('no url field');
await sleep(500);
await p.screenshot({path: '/out/import.png'});
// the bulk tab: several invented addresses at once
await p.click('::-p-text(Tömeges importálás)').catch(e => console.log('no bulk tab', e.message));
await sleep(800);
const bulk = await p.$$('textarea');
const vis = [];
for (const t of bulk) if (await t.isVisible()) vis.push(t);
if (vis.length) await vis[0].type(['https://www.example.com/receptek/rakott-krumpli', 'https://www.example.com/receptek/gulyasleves',
'https://www.example.com/receptek/turos-csusza', 'https://www.example.com/receptek/meggyes-pite'].join('\n'));
else console.log('no visible bulk textarea');
await sleep(500);
await p.screenshot({path: '/out/bulk.png'});
await b.close();
})().catch(e => { console.error(e); process.exit(1); });