Skip to content

Repository files navigation

PastPaper Downloader

A cross-platform application for bulk-downloading Cambridge International (CAIE) past examination papers. Built with Svelte 5, Hono, SQLite, and Tailwind CSS.

App versions (desktop builds) coming soon. The web version is fully functional today.

Screenshots

Configure Options Review & Start Download Library
Options Review Library
Download Progress Settings
Progress Settings

Features

  • Multi-source scraping — Downloads from XtremePapers (primary) and PapaCambridge (fallback) with automatic failover
  • Bulk downloads — Select subjects, year ranges, exam sessions, and paper types in a single session
  • 200+ Cambridge subjects — IGCSE, O Level, AS and A Level syllabi with pre-configured subject bundles
  • Real-time progress — Live download progress via Server-Sent Events (SSE)
  • Smart deduplication — SHA-256 hash-based and path-based deduplication to avoid re-downloading
  • Pause / Resume / Cancel / Retry — Control downloads at both session and individual file levels
  • Download library — Browse, search, sort, and paginate all downloaded papers
  • Download history — View past session details and retry failed items
  • Archive statistics — Total files, disk usage, subjects covered, years, and content type breakdown
  • File organisation — Structured directory hierarchy: {subject}_{code}/{year}/{session}/
  • Theming — Dark and light theme toggle

Tech Stack

Layer Technology
Frontend Svelte 5, TypeScript, Tailwind CSS v4, DaisyUI v5
Backend Node.js, Hono, SQLite (better-sqlite3)
Scraping undici (HTTP), Cheerio (HTML parsing)
DevOps pnpm, Vite, esbuild, Vitest, GitHub Actions

Project Structure

PastPaper-Downloader/
├── index.html                    # Vite entry point
├── package.json                  # Dependencies and scripts
├── subjects.config.json          # 200+ Cambridge subjects
├── sources.config.json           # Scraping source definitions
├── bundles.config.json           # Quick-select subject bundles
│
├── src/
│   ├── shared/
│   │   └── types.ts              # Shared TypeScript types
│   │
│   ├── client/                   # Svelte 5 frontend
│   │   ├── main.ts               # Mount entry point
│   │   ├── App.svelte            # Root component
│   │   ├── app.css               # Tailwind + DaisyUI
│   │   ├── components/
│   │   │   ├── Sidebar.svelte        # Navigation + theme toggle
│   │   │   ├── ConfigPanel.svelte    # 3-step download wizard
│   │   │   ├── StepSubjects.svelte   # Step 1: subject selection
│   │   │   ├── StepOptions.svelte    # Step 2: year/session/type config
│   │   │   ├── StepReview.svelte     # Step 3: review and start
│   │   │   ├── ProgressPanel.svelte  # Live download progress
│   │   │   ├── ProgressTable.svelte  # Per-file progress table
│   │   │   ├── HistoryPanel.svelte   # Past session history
│   │   │   ├── SessionDetail.svelte  # Session file breakdown
│   │   │   ├── LibraryPanel.svelte   # Downloaded papers browser
│   │   │   ├── StatsPanel.svelte     # Archive statistics
│   │   │   └── Toast.svelte          # Notification toasts
│   │   └── lib/
│   │       ├── api.ts            # REST API client
│   │       ├── events.ts         # SSE event bridge
│   │       ├── stores.svelte.ts  # Svelte 5 runes state
│   │       └── utils.ts          # Formatting utilities
│   │
│   └── server/                   # Node.js Hono backend
│       ├── index.ts              # Server entry point
│       ├── config/
│       │   ├── sources.ts        # Load scraping sources
│       │   └── subjects.ts       # Load subjects
│       ├── db/
│       │   ├── client.ts         # SQLite connection + schema
│       │   └── queries.ts        # Database queries
│       ├── routes/
│       │   ├── config.ts         # /api/config/*
│       │   ├── download.ts       # /api/download/*
│       │   ├── health.ts         # /api/health
│       │   ├── library.ts        # /api/library
│       │   ├── sessions.ts       # /api/sessions/*
│       │   └── stats.ts          # /api/stats
│       ├── scrapers/
│       │   └── xtreme-papers.ts  # XtremePapers scraper
│       ├── services/
│       │   ├── deduplication.ts      # SHA-256 + path dedup
│       │   ├── download-manager.ts   # Core download engine
│       │   ├── file-organiser.ts     # Directory structure builder
│       │   └── session-registry.ts   # Session tracking
│       └── utils/
│           ├── emitter.ts            # Typed event emitter
│           ├── errors.ts             # AppError class
│           └── logger.ts             # pino logger
│
├── tests/
│   ├── unit/                     # Unit tests
│   ├── integration/              # API integration tests
│   ├── e2e/                      # Playwright E2E tests
│   └── fixtures/                 # Test HTML fixtures
│
├── docs/                         # Documentation
│   ├── screenshots/              # App screenshots
│   ├── DESIGN-BRIEF.md           # Visual design brief
│   ├── project-description.md    # Architecture overview
│   ├── dev-plan.md               # Development roadmap
│   └── agent-instructions.md     # AI agent coding guidelines
│
├── scripts/
│   ├── build-server.js           # esbuild server bundle
│   ├── dev-both.mjs              # Launch Vite + Hono dev servers
│   └── sync-subjects.ts          # Scrape XtremePapers for subjects
│
└── .github/workflows/
    └── build.yml                 # CI: build, lint, test

Setup & Installation

Prerequisites

  • Node.js 22+
  • pnpm (package manager)

Install

git clone https://github.com/KofiiDeKoder/PastPaper-Downloader.git
cd PastPaper-Downloader
pnpm install

Environment Variables

Variable Default Description
PORT 3000 Backend server port
VITE_PORT 5173 Frontend dev server port
DOWNLOAD_ROOT ./downloads Default download directory
LOG_LEVEL info Logging level (debug/info/warn/error)

Development

# Start both Vite and Hono dev servers
pnpm dev

Open http://localhost:5173

Other Commands

Command Description
pnpm dev:server Start Hono server only (port 3000)
pnpm build Build frontend for production
pnpm build:server Bundle server with esbuild
pnpm test Run Vitest tests
pnpm test:e2e Run Playwright E2E tests
pnpm type-check TypeScript type checking
pnpm lint ESLint

API Reference

Health

Method Endpoint Description
GET /api/health Server health status

Configuration

Method Endpoint Description
GET /api/config/subjects List all Cambridge subjects
GET /api/config/sources List scraping sources
GET /api/config/bundles List subject bundles
GET /api/config/settings Get app settings
PUT /api/config/settings Update app settings
GET /api/config/download-root Get configured download path

Downloads

Method Endpoint Description
POST /api/download/start Start a download session
POST /api/download/pause Pause active session
POST /api/download/resume Resume paused session
POST /api/download/cancel Cancel active session
POST /api/download/retry Retry failed files from a session
GET /api/download/progress SSE event stream for real-time progress
DELETE /api/download/:id Delete a downloaded file and record

Library & Sessions

Method Endpoint Description
GET /api/library Paginated, searchable list of downloaded papers
GET /api/sessions List all download sessions
GET /api/sessions/:id Get session details with files
GET /api/stats Global archive statistics

SSE Events

The /api/download/progress endpoint streams events with a type field in the data payload:

Event Type Description
discovery:start Paper discovery phase started
file:discovered Individual file discovered
discovery:complete Discovery phase finished
file:start File download started
file:progress Download progress update
file:complete File download completed
file:skipped File skipped (duplicate)
file:failed File download failed
queue:progress Overall queue progress
queue:paused Queue paused
queue:resumed Queue resumed
session:complete Entire session finished

Configuration Files

subjects.config.json

Contains 200+ Cambridge subjects with their syllabus codes, qualification levels, and available exam sessions.

{
  "name": "Physics",
  "code": "9702",
  "level": "AS/A Level",
  "sessions": ["s", "w", "m"]
}

Session codes: s = Summer (May/June), w = Winter (Oct/Nov), m = March

sources.config.json

Defines scraping sources with priorities, URL patterns, CSS selectors, and rate limits.

Source Priority Status
XtremePapers 2 Enabled
PapaCambridge 1 Disabled
Cambridge Official 3 Disabled

bundles.config.json

Quick-select groups for common subject combinations:

  • Sciences — Biology (9700), Chemistry (9701), Physics (9702), Sciences (0610), Chemistry (0620), Physics (0625), Physics (5090), Chemistry (5070), Physics (5054)
  • Maths — Maths (9709), Further Maths (9231), IGCSE Maths (0580), Additional Maths (0606), Maths (4024), Maths (4037)
  • Humanities — Economics (9708), History (9609), Geography (9489), Psychology (9990), English Language (9093), Accounting (9706), Business Studies (2281), Accounting (7115), Commerce (2251)
  • IGCSE Core — Maths (0580), Sciences (0610), Chemistry (0620), Physics (0625)

File Organisation

Downloaded papers are saved with this structure:

downloads/
├── physics_9702/
│   ├── 2024/
│   │   ├── s24/
│   │   │   ├── 9702_s24_qp_1.pdf
│   │   │   ├── 9702_s24_ms_1.pdf
│   │   │   └── 9702_s24_qp_2.pdf
│   │   └── w24/
│   │       ├── 9702_w24_qp_1.pdf
│   │       └── 9702_w24_ms_1.pdf
│   └── 2023/
│       └── ...
├── chemistry_9701/
│   └── ...
└── mathematics_9709/
    └── ...

Paper Type Codes

Code Type
qp Question Paper
ms Mark Scheme
er Examiner Report
sp Specimen Paper
in Insert

Contributing

See docs/agent-instructions.md for coding guidelines and docs/dev-plan.md for the development roadmap.

License

For personal educational use only. Cambridge past papers are copyrighted by Cambridge Assessment International Education.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages