Skip to content

feat: server-side EPUB-to-XTC conversion#26

Open
shakogegia wants to merge 26 commits intomainfrom
feature/server-side-conversion
Open

feat: server-side EPUB-to-XTC conversion#26
shakogegia wants to merge 26 commits intomainfrom
feature/server-side-conversion

Conversation

@shakogegia
Copy link
Copy Markdown
Owner

Summary

  • Moves EPUB-to-XTC conversion from the browser to a standalone server-side worker process
  • Users can close the browser tab and conversion continues in the background
  • Multiple books can be converted simultaneously (queued, processed one at a time)
  • Progress shown inline on the Convert button and in the library list
  • "Convert all" button and POST /api/convert/all endpoint for batch conversion

Architecture

  • Worker script (src/worker/convert.ts) — standalone Node.js process that polls SQLite for pending jobs, loads CREngine WASM + node-canvas, renders pages, and saves XTC files
  • Job queueconversion_jobs SQLite table, shared between Next.js and the worker via WAL mode
  • API routesPOST /api/convert (submit), GET /api/convert (list active), GET /api/convert/[jobId] (poll), POST /api/convert/all (batch)
  • ConversionProvider context — manages job state, polling, and resume-on-refresh
  • Preview stays fully client-side (CREngine WASM in browser)

Key changes

  • src/worker/convert.ts — standalone conversion worker
  • src/contexts/conversion-context.tsx — React context for job tracking
  • src/lib/xtc-assembler.ts — extracted XTC binary assembly (shared by client + worker)
  • src/lib/image-processing.ts — refactored to accept raw pixel data (no DOM dependency)
  • src/lib/conversion-jobs.ts — job CRUD operations
  • src/app/api/convert/ — job submission, status polling, batch conversion endpoints
  • src/components/converter/ — inline progress on Convert button, library badges, Convert all
  • Dockerfile — Cairo deps, worker process alongside Next.js
  • package.json — added canvas, tsx, npm-run-all2; pnpm dev starts both processes

Test plan

  • Load EPUB, click Convert — worker processes it, progress shows on button
  • Close tab during conversion, reopen — progress resumes
  • Convert multiple books — they queue and process sequentially
  • "Convert all" button queues all eligible books
  • curl -X POST /api/convert/all works from server side
  • Docker build succeeds and runs both processes

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com

shakogegia and others added 26 commits April 7, 2026 13:17
…MLCanvasElement

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Polling-based Node.js worker that processes EPUB-to-XTC conversion jobs
from SQLite. Uses CREngine WASM + node-canvas with the same rendering
pipeline as the browser client. Adds tsx dependency for running TypeScript
directly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ion and polling

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add 30-minute polling timeout to prevent infinite loops
- Reset stuck 'processing' jobs on worker startup
- Remove dead saveToLibrary callback
- Fix Dockerfile to copy full node_modules (pnpm symlinks)
- Add SQLite busy_timeout for concurrent access

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Move all job submission, polling, and tracking into ConversionProvider
- DevicePreview and LibraryTab consume context directly via useConversion()
- Remove activeJobs prop threading through Sidebar
- Rename button to 'Convert', use refresh icon
- Add 'Convert' option in library dropdown menu
- Hide XTC badge when book is converting
- Outline style for 'Send to device' toast action button
- GET /api/convert returns all active jobs with book titles
- ConversionProvider fetches active jobs on mount and starts polling
- Extracted shared startPolling helper to avoid duplication
- Removed sessionStorage-based resume (server is source of truth)
- Fixed completion toast to find the correct book by ID instead of list order
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant