Metadata-Version: 2.5
Name: cambridge-dictionary-audio
Version: 0.4.0
Summary: Download UK and US pronunciations from Cambridge Dictionary
Project-URL: Homepage, https://github.com/0then0/cambridge-dictionary-audio
Project-URL: Repository, https://github.com/0then0/cambridge-dictionary-audio
Project-URL: Issues, https://github.com/0then0/cambridge-dictionary-audio/issues
License-Expression: Apache-2.0
License-File: LICENSE
License-File: LICENSE-MIT
License-File: NOTICE
Keywords: audio,cambridge,cli,dictionary,pronunciation
Classifier: Environment :: Console
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3.15
Classifier: Topic :: Education
Requires-Python: <3.16,>=3.10
Requires-Dist: beautifulsoup4<5,>=4.15.0
Requires-Dist: genanki<0.14,>=0.13.1
Requires-Dist: requests<3,>=2.34.2
Requires-Dist: rich<16,>=15.0.0
Requires-Dist: textual<9,>=8.2.8
Description-Content-Type: text/markdown

# Cambridge Dictionary Audio CLI

Download American and British pronunciation recordings from Cambridge Dictionary
without a desktop interface. US pronunciation and English interface messages are
the defaults. Python 3.10–3.15 is supported on Windows, macOS and Linux.

## Installation

```sh
uv tool install cambridge-dictionary-audio
```

Alternatively, use `pipx install cambridge-dictionary-audio` or install with pip
inside a virtual environment. This package contains the CLI only and does not
install Qt. Desktop installers are available from the
[GitHub releases](https://github.com/0then0/cambridge-dictionary-audio/releases).

## Usage

```sh
cambridge-audio hello
cambridge-audio "good morning" --accent both --output-dir audio
cambridge-audio hello --lang ru --translation russian
cambridge-audio --help
cambridge-audio
cambridge-audio --lang ru
```

Files are saved in `downloads/` under the current working directory. Use
`--output-dir` to change the destination and `--overwrite` to replace existing
files. Completed MP3s are published atomically; an interrupted write leaves no
partial recording. Running `cambridge-audio` without a word opens the terminal workspace.
`python -m cambridge_audio` is also supported.

## Request pacing and rate limits

Cambridge requests share a one-second minimum interval within the process.
HTTP 429 responses are retried at most twice. The client honors `Retry-After`
(seconds or an HTTP date); otherwise delays start at two and four seconds with
up to half a second of random jitter. HTTP 403 responses are not retried.
If a server cooldown exceeds 30 seconds, the operation stops and reports the
remaining wait; subsequent requests in the same process honor that cooldown.
GUI/TUI cancellation interrupts these waits, and Ctrl+C interrupts CLI waits.

A client caches up to 64 successful HTML pages for its lifetime. This reduces
repeated lookups while preserving fresh MP3 downloads when explicitly requested.
Saved recordings and translations retain their existing persistent cache behavior.

## Terminal workspace

The workspace has a searchable library and a recording detail panel. Narrow
terminals use a vertical layout. Enter in search finds meanings or opens saved
audio offline; Enter in the library plays the selected recording. Selecting both
accents downloads only missing files. **Download again** asks before replacing audio.
Downloads and playback run in the background so navigation remains responsive.

- **Tab / Shift+Tab**: navigate controls; **Up / Down**: select a recording.
- **Ctrl+L**: search; **Ctrl+P**: play/stop; **Ctrl+R**: refresh the library.
- **Ctrl+S**: settings; **F1**: help; **F2**: About; **Ctrl+Q**: quit.
- **Ctrl+C**: cancel the download, stop playback or quit when idle. The current request finishes
  before cancellation, and completed files are retained.

All commands also have shortcuts independent of the keyboard layout: **F3** search,
**F4** play/stop, **F5** refresh, **F6** settings, **F7** export, **F8** translation,
**F9** WikDict, **F10** meanings, **F11** cancel, **F12** quit.
Ctrl shortcuts accept Russian and Ukrainian letters at the same key positions.
If the terminal does not report Ctrl with non-Latin letters, use the function keys.

Settings offer English/Russian interface messages, light/dark themes, accent,
destination, a Russian translation toggle, autoplay and phrase synthesis. Apply
saves these preferences for future TUI launches; Cancel discards dialog changes.
Explicit CLI flags override saved values for the current run without rewriting
the file until preferences are changed in the UI. Plain and one-shot CLI commands
keep their existing defaults. The main translation checkbox also saves its state.

Preferences are stored as UTF-8 JSON in `cambridge-dictionary-audio/tui-settings.json`
under `~/Library/Application Support` on macOS, `%APPDATA%` on Windows, or
`$XDG_CONFIG_HOME` (default `~/.config`) on Linux. Invalid fields fall back to
defaults; failed writes preserve the previous file and show an error in the TUI.

Translation is
optional and always targets Russian. The checkbox shows or hides cached results
immediately. Missing translations are fetched in the background without downloading
audio again. The panel shows loading and request errors. English definitions stay
visible with translation off. Metadata remains in JSON beside MP3s, shared with the
GUI. Old foreign-language caches and edits are preserved. A legacy translation
without a language is not assumed to be Russian. Existing MP3s without metadata
remain playable; empty files are ignored.

## License and attribution

This fork is distributed under Apache-2.0. Code inherited from
[astrosander/cambridge-dictionary-audio](https://github.com/astrosander/cambridge-dictionary-audio)
retains its MIT license and copyright notice. The distribution includes both
licenses and the attribution notice.

The project is independent of Cambridge University Press & Assessment.
Downloaded recordings remain subject to their owners' rights and Cambridge's
[website terms](https://dictionary.cambridge.org/terms-of-use).

## Choose a meaning and audio

Enter a word and choose **Find** in the GUI or TUI. Meanings appear beneath the
result, grouped by part of speech. Selecting a meaning immediately shows its full
definition, IPA and available translation. Use US/UK and **Play** before
**Save meaning**. **Other pronunciation** appears only when the selected meaning
has several distinct recordings for that accent. Already saved choices are marked.
A missing accent is not replaced with another accent's recording.

Opening a saved word works offline. To search all meanings again, use
**Choose meaning** in the GUI or **Ctrl+O** in the TUI. Select saved collection
entries individually to edit their translation or export them. Technical IDs are
shown only by the CLI's diagnostic listing, not in ordinary interface labels.

```sh
cambridge-audio lead --list-variants
cambridge-audio lead --sense SENSE_ID --audio AUDIO_ID --preview
cambridge-audio lead --sense SENSE_ID --audio AUDIO_ID
cambridge-audio lead --variant CHOICE_ID
```

The listing contains the combined choice ID, `sense=…` and `audio=…`.
`--sense` chooses a meaning; `--audio` chooses its recording. If more than one
choice remains, the CLI lists choices and exits with status 1. `--variant` remains
supported. `--preview` plays from a temporary cache without adding a collection
entry. Without it, one unambiguous CLI choice is saved immediately. `--accent both`
saves both accents when each has one choice; an explicit audio/choice ID selects
only that recording. `--overwrite` requests a fresh download. The plain interactive
prompt shows numbered choices rather than technical IDs.

Meanings stay linked to their source dictionary blocks: for example, the metal
and verb senses of “lead” keep their respective recordings. Two meanings of
“bank” may reference one MP3. Audio identity uses accent and source URL, never IPA
alone. Selecting another meaning reuses verified local audio, including after a
restart. Missing audio, invalid signatures and checksum mismatches trigger repair.
Explicitly replacing shared audio affects all entries referencing that file.

### Storage and existing collections

New collection entries have permanent local IDs and separate JSON v3 metadata.
Their `audio_file` may point to the same MP3. Keep JSON files and MP3s together
when moving or backing up the collection. For CLI selection, use the entry's JSON
path with `--recording`; an MP3 path is accepted only when it identifies one meaning.
Filenames remain portable across Windows, macOS and Linux.

Cambridge block and sense IDs identify source entries when available. Changing a
definition, translation or pronunciation list does not change these identities.
Without source IDs, the fallback uses the page, headword, part of speech and block
occurrence, then a definition fingerprint. Such a fallback cannot safely identify
a rewritten or reordered ambiguous source entry. Existing local IDs remain stored;
unmatched choices are never automatically merged. Select the saved record and
choose its updated meaning explicitly when a source match is unavailable. In the
CLI use `cambridge-audio WORD --update-recording PATH_TO_ENTRY.json --sense SENSE_ID
--audio AUDIO_ID --output-dir downloads` (as one command). The saved local ID and
personal translation are retained.

Old v1/v2 sidecars, MP3-only collections and symlink aliases remain readable.
Opening them does not rewrite them. A later metadata save upgrades only that
sidecar atomically, retaining the original collection/export ID, user translations,
source selections and unknown translation languages. Failed replacement retains
the previous JSON; repeating an update is safe. Old duplicate MP3s are not removed
or consolidated automatically. Deleting one collection entry retains audio used
by another entry.

## Translation lookup and editing

Lookup order: personal translation for this sense and language, usable saved
cache, Cambridge bilingual dictionary, installed local WikDict. Audio saving and
playback do not depend on a successful translation. A local fallback keeps the
Cambridge error visible. Missing translation, network failure, blocking, missing
local dictionary and corrupt local dictionary produce separate statuses.

The application supports English words and definitions with optional Russian
translations. The GUI has a **Show Russian translation** checkbox, an offline
dictionary status and **Install WikDict**; no free-form language field is shown.
The TUI offers the same Russian translation toggle in its recording panel and
Settings. English definitions remain visible when translation is off. Interface
language (`--lang en` / `--lang ru`) is independent of this toggle.

The checkbox shows and hides cached Russian results immediately, without repeating
requests for a usable cache. CLI: `--translation russian` enables translation;
`ru` and `русский` are accepted aliases. Other translation languages are rejected
before network access. Existing foreign-language caches and personal edits remain
in JSON with their original language and source; they are not relabeled or deleted.

WikDict source senses are not asserted to match a Cambridge definition. The result
shows the source's part of speech and gloss and explicitly marks unverified sense
alignment. If several source senses remain, choose one before exporting.

GUI: **Edit translation**, **Reset translation**, **Choose translation sense**.
TUI: **Ctrl+T** opens editing, reset and source-sense choices.
CLI examples, without any audio download:

```sh
cambridge-audio --recording downloads/hello.us.mp3 --translation russian --translate-saved
cambridge-audio --recording downloads/hello.us.mp3 --translation russian --set-translation "привет"
cambridge-audio --recording downloads/hello.us.mp3 --translation russian --reset-translation
cambridge-audio --recording downloads/hello.us.mp3 --translation russian --choose-translation SOURCE_SENSE_ID
```

Personal edits apply to a sense and language, shared by saved pronunciations of
that same sense in the folder. Other meanings and languages are untouched. They
survive restart, automatic lookup and redownload. Reset removes only the personal
edit so the original cached dictionary result becomes available again.

## Install the local dictionary

The supported translation direction is **English → Russian**, both for
Cambridge online lookup and the verified local WikDict package.

```sh
cambridge-audio --dictionary-info
cambridge-audio --install-dictionary
cambridge-audio --recording downloads/hello.us.mp3 --translation russian --translate-saved --offline
```

The CLI prints the version, download size, source URL and license before
installation. GUI: **Install WikDict**. TUI: **Ctrl+D**. Both show the package
information before confirmation; the GUI reports downloaded bytes. Installation
is explicit; normal lookup never downloads a dictionary. No API key is needed.
Each GUI click checks the installed package locally. A verified installation or
a damaged package prompts for explicit confirmation before downloading again;
declining leaves the existing file untouched.
Use `--dictionary-dir PATH` to override the platform data directory in CLI/TUI.

The pinned package is `en-ru.sqlite3`, version `2_2026-06`, **20.9 MB** (20,938,752 bytes)
(about 20 MiB). SHA-256:
`3f65395883b996131c9b7a7b7b7c14c1b4458c892fae0050decd71dc0a3b4b0a`.
The application downloads only this pair, without the large English morphology
DB or a full Wiktionary dump. It queries exact source forms; a Cambridge headword
is used as a lemma only when explicitly supplied by Cambridge, with no stemming.

The download is staged beside the destination, bounded by the expected size,
verified by size, pinned SHA-256 and SQLite integrity/schema checks, then replaced
atomically. An interrupted download or failed update leaves an existing package
intact. Lookup verifies the installed package and opens it read-only. Attribution
is installed in `WIKDICT-LICENSE.txt` beside the database.

Default locations:

- Windows: `%LOCALAPPDATA%/cambridge-dictionary-audio/dictionaries`.
- macOS: `~/Library/Application Support/cambridge-dictionary-audio/dictionaries`.
- Linux: `$XDG_DATA_HOME/cambridge-dictionary-audio/dictionaries`, defaulting to
  `~/.local/share/cambridge-dictionary-audio/dictionaries`.

See [data sources and licenses](data-sources.md). WikDict data is CC BY-SA 4.0,
separate from the application's Apache-2.0 code.

## Export to Anki

Choose the selected entry or the whole collection, then **Export to Anki** and
save one `.apkg`. Import it in Anki with **File → Import**. No running Anki,
manual field setup or copying into `collection.media` is needed for export.

```sh
cambridge-audio --output-dir downloads --export-anki exports/my-deck.apkg
cambridge-audio --recording downloads/ENTRY.us.json --export-anki exports/selected.apkg
cambridge-audio --output-dir downloads --export-anki exports/tsv --export-format tsv
```

The package contains one note per selected collection entry, a fixed note type,
one card template and deduplicated MP3 media. The front shows the word. The back
shows the chosen translation, definition, part of speech, IPA, accent and audio,
followed by sources and data-license attribution. The template defines light and
Anki night-mode colours. Text is HTML-escaped, including user translations.

The note type, field IDs, template ID/ordinal and note GUIDs are stable. GUIDs use
the permanent local collection ID, not editable fields or storage paths. Reimport
into the same Anki collection updates matching notes when the incoming version is
newer; Anki 23.10+ also provides update controls. Keep the note type's fields and
single card template intact. Existing card scheduling is retained by Anki's note
update mechanism. This utility does not export study progress or reverse cards.
Edits to the exported note fields in Anki may be replaced on update. Other notes
are not matched by their word or translation.

Missing/damaged MP3s or unresolved translation choices fail the export before
replacing the previous package. Existing files are replaced only if recognized as
this application's exports. Sources and license notices are included in each
note's Source field, the deck description and `SOURCES.txt` inside the package.

### Additional TSV export

GUI: select **TSV** in the save dialog. TUI: use a destination ending in `.tsv`;
this creates a folder with that suffix removed. CLI: use `--export-format tsv`
and a folder path. The folder contains `collection.tsv`, `media/`, `IMPORT.txt`
and `SOURCES.txt`. Follow `IMPORT.txt` to create the nine fields, copy the MP3s
and import with Tab separation and HTML enabled. ID remains the first field;
repeat TSV imports match the same note type and ID and retain scheduling.
Do not map the first field to Anki's internal GUID.

### Existing notes imported from TSV

Importing an ordinary new `.apkg` over older TSV notes can create duplicates:
TSV matched the first field, while packages match Anki GUIDs. Changing note type
alone does not establish that correspondence. Do not delete cards with learning
history to work around this difference. Continuing to update those notes with TSV
is supported.

For an explicit transition with the original nine fields and one normal card:

1. In Anki, export the relevant old deck as **Anki Deck Package (.apkg)** with
   **Support older Anki versions** enabled. Retain a backup. This is a copy of the
   collection; the utility does not open your live Anki database.
2. Run the following once, using the same local collection that produced the TSV:

   ```sh
   cambridge-audio --output-dir downloads --anki-reference old-from-anki.apkg
   cambridge-audio --output-dir downloads --export-anki updated.apkg
   ```

3. Import `updated.apkg` in the original Anki profile. Use update-existing-notes
   behaviour, and keep note types unchanged. The package uses the exported GUID
   and original note type for each mapped ID, rather than creating a new identity.

The command reports the number of mapped notes. Only exact first-field IDs are
mapped. Duplicate IDs, incompatible schemas and conflicting prior mappings are
rejected before writing. Unmatched local entries remain new package notes; compare
the mapped count with the old notes you intend to move. Store the generated
`.anki-mapping.json` with the collection and use it for all later exports. Migration
does not rewrite the reference package, delete notes or touch review history.
Collections with extra fields or multiple card templates should keep using TSV.

Package structure and identity mapping are covered by automated tests. Real Anki
import, repeated import and retention of review history were not exercised in this
environment because Anki was unavailable; these tests do not establish actual
importer compatibility on every Anki version. Import rules are described in the
[Anki package manual](https://docs.ankiweb.net/manual/importing/packaged-decks)
and [text import manual](https://docs.ankiweb.net/manual/importing/text-files).
