Skip to content

Commit 84e02f6

Browse files
authored
Support for Cub Scout adventure deck (#1)
Refactors the project to support building Anki decks for both Scouting America merit badges and Cub Scout Adventures, renaming the repository and codebase from `scout-merit-badges-anki` to `scout-anki`. It introduces a more flexible CLI, updates documentation and configuration, and adds a new processor for Cub Scout adventures. The changes streamline deck building, clarify usage, and enable the generation of multiple deck types.
1 parent bdf9d16 commit 84e02f6

32 files changed

+1123
-964
lines changed

.github/copilot-instructions.md

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
# Copilot Instructions for scout-merit-badges-anki
1+
# Copilot Instructions for scout-anki
22

33
## Repository Overview
44

5-
This is a Python CLI tool that generates Anki flashcard decks (.apkg files) for learning Scouting America merit badges by image. The tool processes local archive files (.zip, .tar.gz) containing merit badge data and images, maps badges to their corresponding images using sophisticated pattern matching, and creates structured Anki decks with stable IDs to prevent duplicates on reimport.
5+
This is a Python CLI tool that generates Anki flashcard decks (.apkg files) for Scouting content. Supports learning Scouting America merit badges and Cub Scout adventures by image. The tool processes local archive files (.tar.gz) containing badge/adventure data and images, maps content to images using direct `image_filename` field mapping, and creates structured Anki decks with stable IDs to prevent duplicates on reimport.
66

77
**Repository Stats:**
88
- Language: Python 3.11+ (currently using 3.12)
@@ -59,7 +59,13 @@ make cov-report
5959
uv run pytest --cov-report=html && open htmlcov/index.html
6060

6161
# Run CLI tool for testing
62-
uv run scout-merit-badges-anki --help
62+
uv run scout-anki --help
63+
64+
# Build merit badge deck
65+
uv run scout-anki build merit-badges extracted/
66+
67+
# Build cub adventure deck
68+
uv run scout-anki build cub-adventures extracted/
6369
```
6470

6571
### Pre-commit Hooks (MANDATORY)
@@ -79,7 +85,7 @@ uv run pre-commit run --all-files
7985
### Validation Commands
8086
```bash
8187
# Test CLI functionality (dry run - safe to run)
82-
uv run scout-merit-badges-anki build --dry-run --quiet *.zip *.tar.gz
88+
uv run scout-anki build --dry-run --quiet *.zip *.tar.gz
8389

8490
# Download and test with latest release
8591
make fetch-and-build
@@ -115,7 +121,7 @@ make clean # Removes build artifacts, .venv, __pycache__, *.apkg files, coverag
115121
tests/
116122
├── test_cli_simple.py # Basic CLI tests (4 tests)
117123
├── test_cli_comprehensive.py # CLI functionality with mocking (2 tests)
118-
└── test_scout_merit_badges_anki.py # Directory processing integration (2 tests)
124+
└── test_scout_anki.py # Directory processing integration (2 tests)
119125
```
120126

121127
### Coverage by Module
@@ -152,7 +158,7 @@ When adding new functionality:
152158

153159
## Project Architecture
154160

155-
### Core Modules (`scout_merit_badges_anki/`)
161+
### Core Modules (`scout_anki/`)
156162
- `cli.py` - Click-based command line interface with build command
157163
- `archive.py` - Archive processing (ZIP/TAR.GZ) and file extraction
158164
- `mapping.py` - Sophisticated image-to-badge mapping logic with pattern matching
@@ -213,7 +219,7 @@ Uses deterministic hashing in `schema.py` to generate stable Anki model/deck IDs
213219
```bash
214220
# 1. Clone repository
215221
git clone <repo-url>
216-
cd scout-merit-badges-anki
222+
cd scout-anki
217223

218224
# 2. Set up environment (REQUIRED)
219225
uv sync
@@ -243,7 +249,7 @@ git commit -m "Your commit message"
243249
### Testing Changes
244250
```bash
245251
# Test CLI functionality without creating files
246-
uv run scout-merit-badges-anki build --dry-run *.zip *.tar.gz
252+
uv run scout-anki build --dry-run *.zip *.tar.gz
247253

248254
# Download and test with latest release
249255
make fetch-and-build
@@ -295,11 +301,11 @@ make test
295301
## File Structure Reference
296302

297303
```
298-
scout-merit-badges-anki/
304+
scout-anki/
299305
├── .github/
300306
│ ├── copilot-instructions.md # This file - development guidelines
301307
│ └── workflows/ # CI/CD pipelines
302-
├── scout_merit_badges_anki/ # Main package
308+
├── scout_anki/ # Main package
303309
│ ├── __init__.py # Package metadata
304310
│ ├── __main__.py # Entry point for python -m
305311
│ ├── cli.py # Command line interface

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ __pycache__/
55
venv
66
.eggs
77
.pytest_cache
8+
.ruff_cache
89
*.egg-info
910
.DS_Store
1011

Makefile

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
1-
.PHONY: fmt lint test test-cov test-no-cov cov-report build-deck clean setup-pre-commit check-all help fetch-releases extract-archives fetch-and-build
1+
.PHONY: fmt lint test test-cov test-no-cov cov-report build-merit-badges build-cub-adventures build-all clean setup-pre-commit check-all help fetch-releases extract-archives fetch-and-build-merit-badges fetch-and-build-cub-adventures
22

33
help:
44
@echo "Available commands:"
5-
@echo " fetch-and-build - Fetch, extract, and build deck in one command"
6-
@echo " fetch-releases - Fetch scout-archive releases using gh CLI"
7-
@echo " extract-archives - Extract downloaded archives to extracted/ directory"
8-
@echo " build-deck - Build Anki deck from extracted directory"
9-
@echo " setup-pre-commit - Install pre-commit hooks"
10-
@echo " check-all - Run all pre-commit hooks on all files"
11-
@echo " fmt - Format code with ruff"
12-
@echo " lint - Lint code with ruff"
13-
@echo " test - Run tests with coverage reporting (80% target)"
14-
@echo " test-no-cov - Run tests without coverage reporting"
15-
@echo " cov-report - Generate and open HTML coverage report"
16-
@echo " clean - Clean up temporary files"
5+
@echo " fetch-and-build-merit-badges - Fetch, extract, and build merit badge deck"
6+
@echo " fetch-and-build-cub-adventures - Fetch, extract, and build cub adventure deck"
7+
@echo " fetch-releases - Fetch scout-archive releases using gh CLI"
8+
@echo " extract-archives - Extract downloaded archives to extracted/ directory"
9+
@echo " build-merit-badges - Build merit badge Anki deck from extracted directory"
10+
@echo " build-cub-adventures - Build cub adventure Anki deck from extracted directory"
11+
@echo " build-all - Build both merit badge and cub adventure decks"
12+
@echo " setup-pre-commit - Install pre-commit hooks"
13+
@echo " check-all - Run all pre-commit hooks on all files"
14+
@echo " fmt - Format code with ruff"
15+
@echo " lint - Lint code with ruff"
16+
@echo " test - Run tests with coverage reporting (80% target)"
17+
@echo " test-no-cov - Run tests without coverage reporting"
18+
@echo " cov-report - Generate and open HTML coverage report"
19+
@echo " clean - Clean up temporary files"
1720

1821
setup-pre-commit:
1922
uv run pre-commit install
@@ -46,10 +49,17 @@ extract-archives:
4649
mkdir -p extracted/
4750
for file in *.tar.gz; do [ -f "$$file" ] && tar -xzf "$$file" -C extracted/ || true; done
4851

49-
build-deck:
50-
uv run scout-merit-badges-anki build extracted/
52+
build-merit-badges:
53+
uv run scout-anki build merit-badges extracted/
5154

52-
fetch-and-build: fetch-releases extract-archives build-deck
55+
build-cub-adventures:
56+
uv run scout-anki build cub-adventures extracted/
57+
58+
build-all: build-merit-badges build-cub-adventures
59+
60+
fetch-and-build-merit-badges: fetch-releases extract-archives build-merit-badges
61+
62+
fetch-and-build-cub-adventures: fetch-releases extract-archives build-cub-adventures
5363

5464
clean:
5565
rm -rf build/

README.md

Lines changed: 46 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# scout-merit-badges-anki
1+
# scout-anki
22

3-
Generates an Anki deck for learning Scouting America merit badges by sight. The front of the card is an image of the merit badge. The back of the card is the name, description, and an indicator if it is required for the Eagle rank.
3+
Anki deck builder for Scouting content. Generates Anki decks for learning Scouting America merit badges and Cub Scout adventures by sight. The front of the card is an image of the merit badge or adventure loop. The back of the card is the name, description, and additional details.
44

55
## Usage
66

@@ -9,87 +9,105 @@ Generates an Anki deck for learning Scouting America merit badges by sight. The
99
First, download and extract the scout-archive release files:
1010

1111
```bash
12-
# Download and extract latest release archives
13-
make fetch-and-build
12+
# Download and extract latest release archives for merit badges
13+
make fetch-and-build-merit-badges
14+
15+
# Download and extract latest release archives for cub adventures
16+
make fetch-and-build-cub-adventures
17+
18+
# Build both deck types
19+
make fetch-releases extract-archives build-all
1420
```
1521

16-
This downloads archives, extracts them to `extracted/` directory, and creates `merit_badges_image_trainer.apkg` that can be imported into Anki.
22+
This downloads archives, extracts them to `extracted/` directory, and creates `.apkg` files that can be imported into Anki.
1723

1824
### Manual Usage
1925

2026
```bash
2127
# Download archives
22-
gh release download --repo dasevilla/scout-archive --pattern "*.zip" --pattern "*.tar.gz"
28+
gh release download --repo dasevilla/scout-archive --pattern "*.tar.gz"
2329

2430
# Extract archives
2531
mkdir -p extracted/
26-
for file in *.zip; do unzip -q "$file" -d extracted/; done
2732
for file in *.tar.gz; do tar -xzf "$file" -C extracted/; done
2833

29-
# Generate Anki deck from extracted directory
30-
scout-merit-badges-anki build extracted/
34+
# Generate merit badge Anki deck from extracted directory
35+
scout-anki build merit-badges extracted/
36+
37+
# Generate cub adventure Anki deck from extracted directory
38+
scout-anki build cub-adventures extracted/
3139
```
3240

3341
### Advanced Usage
3442

3543
```bash
36-
# Custom output file
37-
scout-merit-badges-anki build extracted/ --out my_badges.apkg
44+
# Merit badges with custom output file
45+
scout-anki build merit-badges extracted/ --out my_badges.apkg
46+
47+
# Cub adventures with custom output file
48+
scout-anki build cub-adventures extracted/ --out my_adventures.apkg
3849

3950
# Dry run to preview without creating file
40-
scout-merit-badges-anki build extracted/ --dry-run
51+
scout-anki build merit-badges extracted/ --dry-run
52+
scout-anki build cub-adventures extracted/ --dry-run
4153

4254
# Custom deck and model names
43-
scout-merit-badges-anki build extracted/ --deck-name "My Badges" --model-name "Badge Quiz"
55+
scout-anki build merit-badges extracted/ --deck-name "My Badges" --model-name "Badge Quiz"
56+
scout-anki build cub-adventures extracted/ --deck-name "My Adventures" --model-name "Adventure Quiz"
4457
```
4558

4659
### Command Reference
4760

4861
#### `build` - Generate Anki deck
4962

5063
```bash
51-
scout-merit-badges-anki build [DIRECTORY] [OPTIONS]
64+
scout-anki build DECK_TYPE DIRECTORY [OPTIONS]
5265
```
5366

5467
**Arguments:**
68+
- `DECK_TYPE` - Type of deck to build: `merit-badges` or `cub-adventures`
5569
- `DIRECTORY` - Directory containing extracted badge data and images
5670

5771
**Options:**
58-
- `--out PATH` - Output file path (default: `merit_badges_image_trainer.apkg`)
59-
- `--deck-name TEXT` - Anki deck name (default: `Merit Badges Image Trainer`)
60-
- `--model-name TEXT` - Anki model name (default: `Merit Badge Image → Text`)
72+
- `--out PATH` - Output file path (auto-generated based on deck type if not specified)
73+
- `--deck-name TEXT` - Anki deck name (auto-generated based on deck type if not specified)
74+
- `--model-name TEXT` - Anki model name (auto-generated based on deck type if not specified)
6175
- `--dry-run` - Preview without creating .apkg file
6276
- `-q, --quiet` - Only show errors
6377
- `-v, --verbose` - Increase verbosity
6478

6579
## How It Works
6680

67-
1. **Reads local archive files** (.zip, .tar.gz) containing badge data and images
68-
2. **Extracts badge data** from JSON files using flexible schema normalization
69-
3. **Maps badges to images** using explicit filenames or smart pattern matching
81+
1. **Reads local archive files** (.tar.gz) containing Scouting data and images
82+
2. **Extracts content data** from JSON files using flexible schema normalization
83+
3. **Maps content to images** using direct `image_filename` field mapping
7084
4. **Creates Anki deck** with stable IDs to prevent duplicates on reimport
7185
5. **Bundles media files** into a complete .apkg package
7286

7387
### Image Mapping Strategy
7488

75-
The tool uses a sophisticated strategy to match badges with images:
89+
The tool uses direct field mapping for reliable image association:
7690

77-
1. **Explicit mapping**: If JSON specifies an image filename, match by basename
78-
2. **Pattern matching**: Look for `<badge-slug>-merit-badge.*` format
79-
3. **Exact slug match**: Match badge slug directly to image filename
80-
4. **Shortest path preference**: When multiple candidates exist, choose the shortest filename
91+
1. **Direct mapping**: Uses the `image_filename` field from JSON data
92+
2. **100% success rate**: All badges and adventures now have explicit image filenames
93+
3. **No pattern matching needed**: Simplified from complex inference logic
8194

8295
### Card Format
8396

97+
**Merit Badges:**
8498
- **Front**: Merit badge image (centered, 85% width)
85-
- **Back**: Badge name and description
99+
- **Back**: Badge name, description, and Eagle required indicator
100+
101+
**Cub Adventures:**
102+
- **Front**: Adventure loop image (centered, 85% width)
103+
- **Back**: Adventure name, rank, type, and description
86104

87105
## Development
88106

89107
To contribute to this tool, first checkout the code. Then set up the development environment:
90108

91109
```bash
92-
cd scout-merit-badges-anki
110+
cd scout-anki
93111
uv sync
94112
```
95113

@@ -107,22 +125,6 @@ To run the tests:
107125
make test
108126
```
109127

110-
### Development Commands
111-
112-
```bash
113-
make setup-pre-commit # Install pre-commit hooks (REQUIRED)
114-
make fmt # Format code with ruff and fix linting issues
115-
make lint # Lint code with ruff (check only, no fixes)
116-
make check-all # Run all pre-commit hooks on all files
117-
make test # Run tests (8 focused tests)
118-
make test-no-cov # Run tests without coverage (faster for development)
119-
make fetch-releases # Download scout-archive releases using gh CLI
120-
make extract-archives # Extract downloaded archives to extracted/ directory
121-
make build-deck # Build Anki deck from extracted directory
122-
make fetch-and-build # Fetch, extract, and build deck in one command
123-
make clean # Clean temporary files
124-
```
125-
126128
## Data Source
127129

128-
This tool works with releases from the [scout-archive](https://github.com/dasevilla/scout-archive) repository, which contains merit badge data and images updated roughly weekly.
130+
This tool is built using data from the [scout-archive](https://github.com/dasevilla/scout-archive) repository, which is updated roughly weekly.

pyproject.toml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[project]
2-
name = "scout-merit-badges-anki"
2+
name = "scout-anki"
33
version = "0.1.0"
4-
description = "Generates an Anki deck for learning Scouting America merit badges by image"
4+
description = "Anki deck builder for Scouting content"
55
readme = "README.md"
66
authors = [{name = "Devin Sevilla"}]
77
license = "Apache-2.0"
@@ -13,13 +13,13 @@ dependencies = [
1313
]
1414

1515
[project.urls]
16-
Homepage = "https://github.com/dasevilla/scout-merit-badges-anki"
17-
Changelog = "https://github.com/dasevilla/scout-merit-badges-anki/releases"
18-
Issues = "https://github.com/dasevilla/scout-merit-badges-anki/issues"
19-
CI = "https://github.com/dasevilla/scout-merit-badges-anki/actions"
16+
Homepage = "https://github.com/dasevilla/scout-anki"
17+
Changelog = "https://github.com/dasevilla/scout-anki/releases"
18+
Issues = "https://github.com/dasevilla/scout-anki/issues"
19+
CI = "https://github.com/dasevilla/scout-anki/actions"
2020

2121
[project.scripts]
22-
scout-merit-badges-anki = "scout_merit_badges_anki.cli:cli"
22+
scout-anki = "scout_anki.cli:cli"
2323

2424
[build-system]
2525
requires = ["hatchling"]
@@ -58,7 +58,7 @@ minversion = "7.0"
5858
addopts = [
5959
"--strict-markers",
6060
"--strict-config",
61-
"--cov=scout_merit_badges_anki",
61+
"--cov=scout_anki",
6262
"--cov-report=term-missing",
6363
"--cov-report=html:htmlcov",
6464
"--cov-report=xml",
@@ -70,7 +70,7 @@ markers = [
7070
]
7171

7272
[tool.coverage.run]
73-
source = ["scout_merit_badges_anki"]
73+
source = ["scout_anki"]
7474
omit = [
7575
"*/tests/*",
7676
"*/test_*",

0 commit comments

Comments
 (0)