Instagram truncates long captions server-side (ends with '…').
When yt-dlp returns a truncated caption, automatically fall back to
the Playwright extractor which runs JS in a real browser and can
click the 'more' button to expand the full caption.
Falls back gracefully: if Playwright fails, the truncated text is
still used rather than failing the whole extraction.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- +layout.svelte: replace Svelte logo favicon with actual InstaChef icons;
add two <meta name="theme-color"> tags with media queries so the browser
chrome (mobile top bar) matches --bg for light (#FFF8F5) and dark (#110510);
add <meta name="color-scheme" content="dark light">
- manifest.json: split 'any maskable' into separate 'any' and 'maskable' entries;
maskable uses icon-512-maskable.png (icon with 10% safe-zone padding on gradient bg)
- New icons:
- icon-256/512.png → replaced with transparent-background versions
- icon-256/512-transparent.png → white bg removed via flood-fill BFS
- icon-256/512-dark.png → transparent icon on brand gradient (#833AB4→#E1306C)
- icon-512-maskable.png → 80% icon centered on gradient (PWA maskable safe zone)
- favicon-32.png → 32x32 transparent icon for browser tab
- favicon.png (192×192) → updated to transparent InstaChef icon
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Previously cookies.txt was only regenerated when auth.json was newer. But yt-dlp
overwrites cookies.txt during extraction with its own header ('generated by yt-dlp')
and potentially fewer/different cookies, losing the sessionid from auth.json.
Fix: remove mtime comparison — always regenerate cookies.txt from auth.json on each
extraction call. This ensures the full session cookie set is always present.
Also remove the now-unused statSync import.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- POST /api/queue now returns the full QueueItem (with createdAt, phases, etc.)
instead of a stripped {id,url,status,enqueuedAt} subset
- TimelineRow.relTime() now handles undefined/NaN gracefully, falls back to 'just now'
- TimelineRow timestamp uses item.createdAt ?? item.enqueuedAt as fallback
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
submitUrl() was using the full {duplicate, item} response object
as the queue item, causing 'Cannot read properties of undefined
(reading length)' crash when rendering phases in RecipeSheet/
TimelineRow.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- layout.css: add button.ic-btn-reset rule so all icon buttons
(bell, back, close, retry, etc.) get proper background:none reset
instead of browser-default white/grey appearance in dark mode
- instagram-extractor.ts: auto-convert secrets/auth.json
(Playwright storage format) to Netscape cookies.txt at runtime
whenever auth.json is newer; ensures sessionid and all Instagram
session cookies are passed to yt-dlp, fixing empty media response
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tests passed locally because .env provided OPENAI_BASE_URL and
OPENAI_API_KEY. In the Docker build stage there is no .env, so
createLLM() threw 'OPENAI_BASE_URL environment variable is not set'
before the mocked OpenAI client ever ran, causing 3 test failures.
Add vi.mock('$env/dynamic/private', ...) with stub values so the
tests are self-contained and environment-independent.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Playwright Chromium is not available in node:24-alpine, causing the
vitest 'client' project (browser tests) to fail with an unhandled
browserType.launch error and exit code 1.
- Dockerfile: switch tester stage command to
'npm run test:unit -- --run --project=server'
so only Node.js unit tests run during Docker builds
- page.svelte.spec.ts: update stale 'renders h1' assertion to match
the new InstaChef design (no h1; check for 'InstaChef' logo text)
Browser component tests still run locally when Playwright/Chromium
is available.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Increase max_tokens from 10 to 1024 for detection so thinking
models have room to reason. Also fall back to reasoning_content
if content is empty, since some local models (e.g. Gemma 4
thinking variants) put their answer there.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add instagram-extractor.ts: yt-dlp subprocess backend for Instagram
caption extraction. No in-process browser state, maintained against
Instagram frontend churn, supports cookies.txt for auth-walled reels.
- Add feature flag EXTRACTOR_BACKEND (ytdlp|playwright) in QueueProcessor
so the old Playwright path remains available as fallback.
- Add 9 unit tests and 2 live-network integration tests for the new extractor.
- Dockerfile: install yt-dlp via pip3 alongside existing Chromium deps.
- docker-compose: expose EXTRACTOR_BACKEND env var (default: ytdlp).
Also in this commit:
- LLM: configurable per-request timeout via LLM_REQUEST_TIMEOUT_MS (default 120s);
set maxRetries=0 to surface errors immediately; llama-swap /running health probe.
- QueueProcessor: thread progress callback through parser phase.
- LlmHealthIndicator: surface llama-swap loaded-model name.
- Logging: improve error serialization in queue-processor tests.
- .env.example: document llama-swap endpoint and model options.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Exported cleanText() and extractFromDOM() for unit testing
- Fixed metadata prefix regex to handle optional quotes
- Created comprehensive unit tests with mocked Playwright Page (15 tests, 12ms)
- All 275 tests passing
- Fixed NodeJS.Timer → NodeJS.Timeout in scheduler.ts line 13
- Fixed NodeJS.Timer[] → NodeJS.Timeout[] in fixtures.ts line 151
- Resolves TypeScript compile errors from iteration 0 review
- All 260 tests passing, build succeeds with no errors
- Fixed health endpoint to use getAll() instead of getAllItems()
- Removed call to non-existent getStats() method
- Added local stats computation with total count
- Health endpoint now returns 200 OK (was returning 500)
- Docker healthcheck now passes successfully
- No more TypeError in Docker logs
Resolves health check failure that was blocking Docker monitoring.
- Fix InvalidCharacterError in push notifications with proper VAPID key validation
- Add attractive PWA install prompt component with cross-browser support
- Make notification settings always visible regardless of queue status
- Implement PWA install manager with user engagement detection
- Use SvelteKit navigation APIs instead of browser history API
- Add comprehensive error handling and logging
- Include cross-browser compatibility and responsive design
- Add development tooling improvements
Fixes push notification bugs and significantly improves PWA user experience
with modern, accessible interface components and proper error handling.
- Remove dev-dist/registerSW.js (no longer needed without vite-pwa plugin)
- Fix import order in layout.svelte
- Complete migration to native SvelteKit PWA
Story 4: Enable SvelteKit Service Worker Registration
- Enable serviceWorker.register: true in svelte.config.js
- SvelteKit now handles service worker registration automatically
- Service worker builds successfully as service-worker.mjs
- Build and preview work without conflicts
- Ready for comprehensive testing
Migration to native SvelteKit PWA implementation complete
Refs: docs/plans/MigrateToNativeSvelteKitPWA.md
Story 3: Migrate Service Worker to SvelteKit Native
- Replace workbox imports with SvelteKit $service-worker module
- Use build, files, version arrays for manual cache management
- Implement manual asset caching and cache cleanup
- Replace NavigationRoute with manual fetch handling
- Preserve all push notification event handlers exactly
- Preserve background sync and message handling functionality
- Service worker builds successfully as service-worker.mjs
SvelteKit native implementation ready - now need to enable registration
Refs: docs/plans/MigrateToNativeSvelteKitPWA.md
Story 2: Remove SvelteKitPWA Plugin Dependencies
- Remove @vite-pwa/sveltekit from package.json dependencies
- Remove SvelteKitPWA plugin import and configuration from vite.config.ts
- Clean up plugin configuration including manifest, workbox, and devOptions
- Build process now works without plugin (service worker migration needed next)
Dependencies reduced by 309 packages
Build fails on workbox imports as expected - ready for Story 3
Refs: docs/plans/MigrateToNativeSvelteKitPWA.md