Skip to content

Commit 532a55b

Browse files
committed
Add comprehensive tooling and infrastructure
- ESLint + Prettier for code quality and formatting - Jest testing framework with initial unit tests - Husky pre-commit hooks for automatic formatting/linting - Husky pre-push hooks for full validation - GitHub Actions CI/CD pipeline - Status badges in README - CLAUDE.md for AI assistant context - Updated documentation with badges
1 parent a9fc83f commit 532a55b

File tree

9 files changed

+488
-1
lines changed

9 files changed

+488
-1
lines changed

.github/workflows/ci.yml

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main, develop]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
test:
11+
name: Test on Node.js ${{ matrix.node-version }}
12+
runs-on: ubuntu-latest
13+
14+
strategy:
15+
matrix:
16+
node-version: [18.x, 20.x, 22.x]
17+
18+
steps:
19+
- name: Checkout code
20+
uses: actions/checkout@v4
21+
22+
- name: Setup Node.js
23+
uses: actions/setup-node@v4
24+
with:
25+
node-version: ${{ matrix.node-version }}
26+
cache: 'npm'
27+
28+
- name: Install dependencies
29+
run: npm ci
30+
31+
- name: Type check
32+
run: npm run typecheck
33+
34+
- name: Lint
35+
run: npm run lint
36+
37+
- name: Format check
38+
run: npm run format:check
39+
40+
- name: Run tests
41+
run: npm run test:coverage
42+
43+
- name: Upload coverage to Codecov
44+
if: matrix.node-version == '20.x'
45+
uses: codecov/codecov-action@v3
46+
with:
47+
files: ./coverage/lcov.info
48+
flags: unittests
49+
name: codecov-umbrella
50+
51+
- name: Build
52+
run: npm run build
53+
54+
build:
55+
name: Build and Package
56+
runs-on: ubuntu-latest
57+
needs: test
58+
59+
steps:
60+
- name: Checkout code
61+
uses: actions/checkout@v4
62+
63+
- name: Setup Node.js
64+
uses: actions/setup-node@v4
65+
with:
66+
node-version: '20.x'
67+
cache: 'npm'
68+
69+
- name: Install dependencies
70+
run: npm ci
71+
72+
- name: Build
73+
run: npm run build
74+
75+
- name: Archive production artifacts
76+
uses: actions/upload-artifact@v3
77+
with:
78+
name: dist
79+
path: dist/

.husky/pre-commit

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
npx lint-staged

.husky/pre-push

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
npm run check-all

CLAUDE.md

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
# Libby Downloader - Development Guide
2+
3+
This document provides context for AI assistants (Claude) working on this codebase.
4+
5+
## Project Overview
6+
7+
A TypeScript CLI tool for downloading audiobooks from Libby with realistic user simulation to minimize detection risk. Built as a safer, more responsible alternative to the original TamperMonkey script.
8+
9+
## Architecture
10+
11+
### Core Modules
12+
13+
1. **auth/** - Authentication and session management
14+
- `libby-auth.ts` - Manual login flow, cookie persistence
15+
16+
2. **browser/** - Puppeteer automation with stealth
17+
- `manager.ts` - Browser lifecycle, session management
18+
- `stealth.ts` - User behavior simulation (mouse, scrolling, delays)
19+
20+
3. **downloader/** - Libby API interaction and chapter downloading
21+
- `libby-api.ts` - Data extraction via JSON.parse hooks, BIF object access
22+
- `chapter-downloader.ts` - Sequential downloads with rate limiting
23+
24+
4. **processor/** - Audio processing
25+
- `ffmpeg-processor.ts` - Chapter merging, metadata, chapter markers
26+
27+
5. **metadata/** - ID3 tag embedding
28+
- `embedder.ts` - Cover art, metadata embedding with node-id3
29+
30+
6. **utils/** - Shared utilities
31+
- `delay.ts` - Random delays, sleep functions
32+
- `fs.ts` - File operations, sanitization
33+
- `logger.ts` - Structured logging
34+
- `rate-limiter.ts` - Three-mode rate limiting (safe/balanced/aggressive)
35+
36+
7. **types/** - TypeScript definitions
37+
- Shared interfaces for books, chapters, configs
38+
39+
8. **cli.ts** - Main CLI entry point using Commander.js
40+
41+
## Key Technical Decisions
42+
43+
### Why Puppeteer?
44+
45+
- Real browser context prevents detection
46+
- Access to Libby's internal objects (BIF, odreadCmptParams)
47+
- Cookie persistence for session reuse
48+
- Stealth plugins for anti-detection
49+
50+
### Why Sequential Downloads?
51+
52+
- Parallel downloads are easily detected (original script's issue)
53+
- Humans read/listen sequentially, not all-at-once
54+
- Variable timing between chapters mimics real behavior
55+
56+
### Rate Limiting Strategy
57+
58+
- **Safe mode**: 8-20s delays, breaks every 3 chapters (1 book/hour max)
59+
- **Balanced mode**: 4-12s delays, breaks every 5 chapters (2 books/hour)
60+
- **Aggressive mode**: 2-6s delays, minimal breaks (5 books/hour) - HIGH RISK
61+
62+
### Why Not Use Libby's API Directly?
63+
64+
- No documented public API
65+
- Authentication is complex
66+
- TamperMonkey approach (hooking internal data) is proven
67+
- Browser context provides authenticated session automatically
68+
69+
## Code Patterns
70+
71+
### Error Handling
72+
73+
- Use try/catch with logger.error()
74+
- Clean up resources in finally blocks
75+
- Provide helpful error messages to CLI users
76+
77+
### Async Operations
78+
79+
- All I/O operations are async
80+
- Use await for sequential operations
81+
- Rate limiter enforces delays between operations
82+
83+
### Type Safety
84+
85+
- Strict TypeScript mode enabled
86+
- Explicit interfaces for all data structures
87+
- No `any` types except for page.evaluate() contexts
88+
89+
## Development Workflow
90+
91+
### Running Locally
92+
93+
```bash
94+
npm run dev -- login # Test login flow
95+
npm run dev -- list # Test book listing
96+
npm run dev -- download <id> # Test download (use safe mode!)
97+
```
98+
99+
### Before Committing
100+
101+
```bash
102+
npm run check-all # Type check + lint + format + test
103+
```
104+
105+
### Pre-commit Hook
106+
107+
Automatically formats and lints staged files.
108+
109+
### Pre-push Hook
110+
111+
Runs full validation suite before push.
112+
113+
## Testing Strategy
114+
115+
### Unit Tests
116+
117+
- Focus on pure functions (utils/delay.ts, utils/fs.ts)
118+
- Mock external dependencies (Puppeteer, FFmpeg)
119+
120+
### Integration Tests
121+
122+
- Test rate limiter behavior
123+
- Test metadata embedding with sample files
124+
125+
### Manual Testing
126+
127+
- Always test downloads in safe mode first
128+
- Use test library card if possible
129+
- Monitor for detection/bans
130+
131+
## Important Constraints
132+
133+
### Security & Ethics
134+
135+
- Tool is for educational purposes only
136+
- Users accept all responsibility for ToS violations
137+
- Emphasize detection risks in all documentation
138+
- No bypassing of DRM (only downloading already-accessible content)
139+
140+
### Performance
141+
142+
- Sequential downloads are intentionally slow
143+
- Rate limiting is critical for detection avoidance
144+
- FFmpeg operations can be memory-intensive
145+
146+
### Dependencies
147+
148+
- Requires FFmpeg installed on system (not bundled)
149+
- Large Puppeteer install (~300MB with Chromium)
150+
- Node-ID3 for metadata (simpler than FFmpeg metadata)
151+
152+
## Common Issues
153+
154+
### "Not logged in" errors
155+
156+
- Cookie expiration - re-run login
157+
- Check ~/.libby-downloader/cookies.json exists
158+
159+
### TypeScript errors in page.evaluate()
160+
161+
- page.evaluate() runs in browser context (DOM types)
162+
- Use `(window as any)` for custom properties
163+
- Cast functions to `any` when needed for flexibility
164+
165+
### FFmpeg not found
166+
167+
- User must install separately (Homebrew, apt, etc.)
168+
- Check with `ffmpeg -version` before processing
169+
170+
### Rate limit warnings
171+
172+
- User tried to download too fast
173+
- Enforce cooldown periods
174+
- Suggest safe mode
175+
176+
## Code Style
177+
178+
### Formatting
179+
180+
- Prettier with single quotes, 100 char width
181+
- 2-space indentation
182+
- Trailing commas (ES5 style)
183+
184+
### Naming
185+
186+
- PascalCase for classes
187+
- camelCase for functions/variables
188+
- SCREAMING_SNAKE_CASE for constants
189+
- Descriptive names over brevity
190+
191+
### Comments
192+
193+
- Explain "why", not "what"
194+
- TSDoc for public APIs
195+
- Inline comments for tricky logic only
196+
197+
## Future Improvements
198+
199+
### Potential Features
200+
201+
- Resume interrupted downloads
202+
- Multiple library card support
203+
- Download queue management
204+
- Better chapter title detection
205+
- M4B output format option
206+
207+
### Detection Avoidance Enhancements
208+
209+
- ML-based timing patterns
210+
- Adaptive rate limiting based on success
211+
- Session replay from real user behavior
212+
- Proxy rotation support
213+
214+
## Maintenance Notes
215+
216+
### When Libby Changes
217+
218+
- Monitor `BIF` object structure (core data source)
219+
- Check `odreadCmptParams` hook still works
220+
- Update selectors for shelf/book pages
221+
- Test login flow for changes
222+
223+
### Dependency Updates
224+
225+
- Puppeteer: Check for breaking changes in page API
226+
- Node-ID3: Verify metadata compatibility
227+
- FFmpeg: Test chapter merging still works
228+
229+
## Resources
230+
231+
- Original LibbyRip: https://github.com/PsychedelicPalimpsest/LibbyRip
232+
- Puppeteer Docs: https://pptr.dev
233+
- FFmpeg Docs: https://ffmpeg.org/documentation.html
234+
- Libby Web App: https://libbyapp.com
235+
236+
## Contributing
237+
238+
When adding new features:
239+
240+
1. Create feature branch from main
241+
2. Write tests first (TDD when possible)
242+
3. Implement feature
243+
4. Update documentation
244+
5. Run `npm run check-all`
245+
6. Create pull request with clear description
246+
247+
## Support and Issues
248+
249+
- GitHub Issues: For bug reports and feature requests
250+
- Include: OS, Node version, error logs, steps to reproduce
251+
- Privacy: Never share library card details or personal info

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Libby Downloader
22

3+
[![CI](https://github.com/pdugan20/libby-downloader/actions/workflows/ci.yml/badge.svg)](https://github.com/pdugan20/libby-downloader/actions/workflows/ci.yml)
4+
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5+
[![Node.js Version](https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen)](https://nodejs.org/)
6+
37
A command-line tool for downloading audiobooks from Libby with realistic user simulation to minimize detection risk.
48

59
## Important Warnings

jest.config.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
module.exports = {
2+
preset: 'ts-jest',
3+
testEnvironment: 'node',
4+
roots: ['<rootDir>/src'],
5+
testMatch: ['**/__tests__/**/*.ts', '**/*.test.ts', '**/*.spec.ts'],
6+
collectCoverageFrom: [
7+
'src/**/*.ts',
8+
'!src/**/*.d.ts',
9+
'!src/cli.ts', // Main CLI entry point
10+
],
11+
coverageDirectory: 'coverage',
12+
coverageReporters: ['text', 'lcov', 'html'],
13+
coverageThreshold: {
14+
global: {
15+
branches: 50,
16+
functions: 50,
17+
lines: 60,
18+
statements: 60,
19+
},
20+
},
21+
};

0 commit comments

Comments
 (0)