cyoa-cli
v1.0.1
Published
A CLI tool to download CHYOA stories and their parent stories as markdown files, with WebP image conversion, base64 embedding, single-file output, interactive login and session persistence
Maintainers
Readme
CYOA Downloader CLI
Bun-native (but npm-compatible) TypeScript CLI for downloading stories from https://chyoa.com and exporting them as Markdown (single file or per chapter) with optional local image downloading, WebP conversion, and embedded image data.
Key Features
- Download a story plus all ancestor (parent) chapters
- Clean HTML → Markdown conversion
- Local image download with automatic WebP conversion (can disable)
- Optionally embed images as base64 directly in Markdown
- Separate files per chapter or one combined file
- Interactive browser login (Puppeteer) with session reuse (24h)
- Manual cookie mode (skip browser)
- Cloudflare bypass via real browser
- Deterministic file + directory naming
Installation
Global (Bun - fastest startup):
bun add -g cyoa-cliGlobal (npm):
npm install -g cyoa-cliVerify:
cyoa-cli --helpQuick Start
Download a public story:
cyoa-cli "https://chyoa.com/chapter/example.123456"If authentication is required you will be prompted to open a login browser—press y and log in once; session is cached.
Basic Examples
Download with interactive login (auto prompt):
cyoa-cli "https://chyoa.com/chapter/example.123456"Supply manual cookie:
cyoa-cli "https://chyoa.com/chapter/example.123456" -c "laravel_session=YOUR_VALUE"Single combined file:
cyoa-cli "https://chyoa.com/chapter/example.123456" --single-fileEmbed images (no image dir):
cyoa-cli "https://chyoa.com/chapter/example.123456" --embed-imagesKeep original image formats:
cyoa-cli "https://chyoa.com/chapter/example.123456" --no-webpDisable browser (legacy HTTP mode):
cyoa-cli "https://chyoa.com/chapter/example.123456" --no-puppeteerClear saved session:
cyoa-cli --clear-sessionConnectivity test only:
cyoa-cli --testCLI Overview
Positional:
- url Story (chapter) URL. Can omit flags and just pass it.
Options:
- -c, --cookie Provide session cookie string (e.g. "laravel_session=...; other=...")
- -o, --output Base output directory (default: downloaded_stories)
- --single-file Combine all chapters into one Markdown file
- --embed-images Inline images as base64 (skips image directory)
- --no-webp Do not convert images to WebP
- --no-puppeteer Skip browser (direct HTTP; may fail with Cloudflare/protected content)
- --clear-session Delete cached session file and force fresh auth
- --test Simple reachability test (no download)
- --test-cookies Verify provided cookies before full run
- --username / --password Reserved (not implemented)
- -h, --help Show help
Output Layout
Default (per chapter + WebP):
downloaded_stories/
story_title/
00_first_parent.md
01_next.md
02_target.md
images/
img_0.webp
img_1.webpSingle file:
downloaded_stories/
story_title/
story_title_complete.md
images/...Embedded images:
downloaded_stories/
story_title/
00_first_parent.md
01_next.md
02_target.md (all image data inlined)How It Works
- Start from supplied chapter URL.
- Walk parent chain (oldest ancestor → target).
- Fetch HTML (browser automation unless --no-puppeteer).
- Extract + sanitize text content.
- Download images (unless embedding).
- Convert to WebP (unless --no-webp) or embed as base64.
- Rewrite image references.
- Emit Markdown (ordered by ancestry or combined).
Authentication
Preferred: interactive login (auto prompt when needed):
- Run without cookies.
- Accept prompt (y).
- Browser opens—log in normally.
- Return to terminal; press Enter.
- Session saved for ~24h at: ~/.config/cyoa-cli/session.json
Manual cookies (advanced):
- Log in at chyoa.com.
- Inspect cookies (DevTools → Application/Storage).
- Copy e.g. laravel_session.
- Pass via: --cookie "laravel_session=VALUE"
Force reset:
cyoa-cli --clear-sessionError Notes
Common cases:
- 403 / missing content: needs auth (login or provide cookie)
- 404: malformed or removed story URL
- Cloudflare blocked: use default (Puppeteer) mode
- Image conversion errors: try --no-webp
- Infinite parent loop: cycle detection aborts with message
Limitations
- Username/password flags not yet implemented (interactive + cookies only)
- Very large chains increase runtime
- Browser automation slower than pure HTTP (but more reliable)
- Requires Chromium/Chrome install for Puppeteer
Development
Install deps:
bun installWatch mode:
bun run devBuild bundle (emits index.js):
bun run buildRun built output:
bun index.js "https://chyoa.com/chapter/example"Project files:
- index.ts (entry + CLI)
- package.json
- README.md
Publishing
Bun:
# bump version in package.json
bun run build
bun publish --access publicnpm:
# bump version
bun run build
npm publishInstall (end users):
- bun add -g cyoa-cli
- npm install -g cyoa-cli
License
MIT
