Build your own Anki audio library from German videos.
You put German videos in a folder and write down the words and phrases you want to practice. Goethe finds every place where they are spoken and cuts each one out as a small MP3 file.
πΉ videos/lesson.mp4
β faster-whisper (speech recognition, word-level timestamps)
π transcripts/lesson.json
β find your words and phrases (sentences.txt)
π every occurrence, in every video
β ffmpeg
π΅ output/mp3/Ich_heisse/Ich_heisse__lesson__00h02m15s_7d11d715.mp3
| Feature | How it works |
|---|---|
| π€ Speech recognition | faster-whisper transcribes each video with a timestamp for every word. The language comes from config.yaml. |
| π Exact matching | Finds single words and whole phrases. Case, punctuation and extra spaces do not matter; Γ/ss and umlauts are handled. Only whole words match (ich does not match inside mich). |
| π Phrases across segments | Whisper sometimes splits a sentence into two segments. Goethe searches the whole word stream, so these phrases are found too. |
| π§© Optional fuzzy fallback | Off by default. See Matching. |
| π΅ MP3 extraction | One MP3 per occurrence, cut with ffmpeg, at the bitrate you choose (32-320 kbps). |
| π Organized output | output/mp3/<search term>/, with file names that are unique across all videos (important for Anki). |
| π Resume | Videos that already have a transcript are skipped without loading the Whisper model. MP3 files that already exist are skipped too. |
| ποΈ Video formats | Whatever you list under video_formats in config.yaml (default: mp4, mkv, avi, mov). |
| π Languages | German, English, French, Spanish, Italian, Portuguese, Chinese (see below). |
| π¨ Readable output | Colored boxes that stay aligned. Colors turn off automatically when output is not a terminal or NO_COLOR is set. |
| π Log file | Everything shown on screen is also written (without colors) to logs/goethe.log. |
| Requirement | Version | How to check |
|---|---|---|
| Python | 3.8 or newer | python3 --version |
| FFmpeg | any recent version | ffmpeg -version |
| Disk space | the Whisper model is downloaded on first use: small for tiny, a few GB for large-v3 |
df -h |
Developed and tested on Ubuntu. Other Linux systems and macOS should work as well, but this was not tested.
# 1. Get the project
git clone https://github.com/duman-dp/Goethe.git
cd Goethe
# 2. Install FFmpeg (Ubuntu)
sudo apt update
sudo apt install ffmpeg
# 3. Create a virtual environment and install the Python packages
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
# 4. First-time setup: creates folders, config.yaml and sentences.txt
# (existing files are never overwritten) and checks your system
python3 setup.py- Copy your videos into
videos/. - Write the words and phrases you want into
sentences.txt, one per line. - Run:
python3 main.pyYour MP3 files are in output/mp3/.
# Lines starting with # are comments. Empty lines are ignored.
Ich heiΓe
Wie heiΓt du?
Woher
malen
- Single words and phrases can be mixed.
- A phrase matches only when its words are spoken one after another. Words more than 1.5 seconds apart are not treated as one phrase.
- Duplicates (same words, different capitalization or punctuation) are ignored with a warning.
- The file must be saved as UTF-8 (the default in almost every editor).
Goethe/
βββ videos/ β your videos
βββ transcripts/ β speech-to-text results (JSON), one per video
βββ output/
β βββ all_matches.json β every match with video, timestamps and context
β βββ mp3/ β your MP3 library
β βββ Ich_heisse/
β βββ Ich_heisse__lesson__00h02m15s_7d11d715.mp3
βββ logs/goethe.log
βββ modules/
β βββ beautiful_logger.py terminal output and log file
β βββ config.py loading and checking config.yaml
β βββ errors.py error types with readable messages
β βββ speech_recognition.py video discovery and transcription
β βββ sentence_matcher.py finding words and phrases
β βββ audio_extractor.py cutting MP3 clips, file names
β βββ setup.py first-time setup
βββ tests/ β automatic tests
βββ main.py β run this
βββ setup.py β first-time setup
βββ config.yaml
βββ sentences.txt
βββ requirements.txt
<search term>__<video name>__<hh>h<mm>m<ss>s_<id>.mp3
Ich_heisse__Lektion_Ae__00h00m00s_e7c3db2f.mp3
- Umlauts are transliterated:
Γ€βae,ΓΆβoe,ΓΌβue,Γβss. Names only containA-Z a-z 0-9 _. - The
<id>is derived from video name, search term and exact time. The same match always gets the same name; matches from different videos never collide. - Text without any Latin letters (for example Chinese search terms) gets a name like
term_a1b2c3, because it cannot be transliterated without extra software. - If two different search terms would end up with the same folder name, the second gets
_2.
All settings are optional. Missing values use the defaults shown here. Invalid values stop the program with a message that says what to change. Settings that do not exist (for example audio.output_format from older versions) are ignored with a warning.
| Setting | Default | Meaning |
|---|---|---|
audio.padding_before |
0.03 |
Seconds added before each match (0-5) |
audio.padding_after |
0.03 |
Seconds added after each match (0-5) |
audio.bitrate |
192 |
MP3 quality in kbps (32-320) |
paths.videos |
./videos |
Where your videos are |
paths.transcripts |
./transcripts |
Where transcripts are stored |
paths.output |
./output |
MP3 files go to <output>/mp3/ |
paths.logs |
./logs |
Folder for goethe.log |
speech.language |
German |
Language spoken in the videos (see below) |
speech.model_size |
small |
tiny, base, small, medium, large-v2, large-v3 (large = large-v3) |
speech.device |
cpu |
cpu, cuda (NVIDIA GPU) or auto |
speech.quiet |
false |
true = less output while transcribing |
matching.fuzzy_threshold |
100 |
100 = exact only. 50-99 = fuzzy fallback (see below) |
video_formats |
mp4, mkv, avi, mov |
File extensions that are processed (not case-sensitive) |
Relative paths are relative to the project folder.
| Model | Speed | Accuracy | Memory |
|---|---|---|---|
tiny |
fastest | lowest | lowest |
base |
very fast | low | low |
small (default) |
fast | good for clear speech | moderate |
medium |
slower | better | high |
large-v2 / large-v3 |
slowest | best | highest |
small is the default because it works on most laptops. If words are misrecognized, try medium; if your computer runs out of memory, try base or tiny. Models are downloaded the first time they are used.
| Name | Code |
|---|---|
| German | de |
| English | en |
| French | fr |
| Spanish | es |
| Italian | it |
| Portuguese | pt |
| Chinese | zh |
Write the name (German, german) or the code (de). Any other value stops the program and lists the supported languages. Other Whisper languages can be added to the LANGUAGES list in modules/config.py.
Chinese has no spaces between words, so it is matched character by character. A clip then covers the complete recognized words that contain the characters you searched for.
Exact matching (default). Goethe compares words after lower-casing and removing punctuation. Wie heiΓt du? finds "Wie heiΓt du", "wie heiΓt du!" and "wie heisst du".
Fuzzy fallback (optional). If you set matching.fuzzy_threshold below 100 (for example 80):
- Goethe first searches exactly, as usual.
- Only if a term has no exact match in a video, it looks in that video for the most similar word sequences with at least that percentage of similarity (using Python's
difflib). This helps when Whisper misspells a word. - Fuzzy matches are marked in
output/all_matches.json("exact": falseand ascore). - Terms shorter than 4 characters are never matched fuzzily.
- Lower values find more, but also more wrong clips. Start with
80-90.
β οΈ Upgrading note: older versions shippedfuzzy_threshold: 60, which had no effect. In this version it is real. If yourconfig.yamlstill says60, change it to100unless you want fuzzy matching.
This is a real run (two short test videos; colors removed):
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β π€ Step 1: Speech Recognition β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βΉοΈ Found 2 video(s)
πΉ Lektion 2.MOV
πΉ Lektion_Γ.mp4
βΉοΈ β© 2 video(s) already transcribed - skipping
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β π Step 2: Sentence Matching β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βΉοΈ Searching 13 word(s)/phrase(s) in 2 transcript(s) - exact matches only
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β π Matches: 11 total β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Ich heiΓe: 2 clip(s) β
β Wie heiΓt du: 1 clip(s) β
β Woher kommst du?: not found β
β ... β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β π΅ Step 3: Audio Extraction β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
Created 11 MP3 file(s)
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β π Summary β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Videos: 2 β
β Transcribed now: 0 β
β Transcripts used: 2 β
β Matches: 11 β
β MP3 created: 11 β
β MP3 skipped: 0 β
β MP3 failed: 0 β
β Output: output/mp3 β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- Transcripts: a video is transcribed once. If
transcripts/<video name>.jsonexists, the video is skipped and Whisper is not even loaded. To transcribe a video again (different language or model, or you replaced the video), delete its transcript file. - Transcript names: transcripts are named after the video without extension (
lesson.mp4βlesson.json). Two videos with the same name but different extensions (lesson.mp4andlesson.mkv) cannot both be used; the second is skipped with a warning. Rename one of them. - MP3 files: clips that already exist are not created again. After changing padding or bitrate, delete
output/mp3/to create all clips fresh. - Interrupting with Ctrl+C is safe: finished transcripts are kept and files are written atomically, so no half-written transcript or MP3 is left behind.
- Transcripts from older Goethe versions are still understood.
Goethe needs ffmpeg to cut MP3 files.
sudo apt update
sudo apt install ffmpeg
ffmpeg -version # should print a versionTranscription still works without ffmpeg, but no MP3 files are created.
The model is downloaded from Hugging Face the first time it is used.
- Check your internet connection and that there is enough free disk space.
- Run Goethe again; interrupted downloads continue where they stopped.
- The warning "You are sending unauthenticated requests to the HF Hub" is harmless. Optionally create a free token at https://huggingface.co/settings/tokens and set
export HF_TOKEN="hf_..."for faster downloads. - Behind a proxy or offline? Download the model on another machine and put its folder path into
speech.model_size.
Use a smaller model: set speech.model_size to base or tiny. Close other programs, and process fewer or shorter videos at once. (Videos that are already transcribed are skipped, so you can run Goethe repeatedly with a few videos each time.) Speech recognition uses the CPU heavily, so a laptop getting warm is normal.
- Check the spelling in
sentences.txt. Look intotranscripts/<video>.jsonto see what Whisper actually heard. - Try single words first, then phrases. A phrase only matches if Whisper recognized every word of it.
- Make sure
speech.languagematches the language in the videos. If you changed it, delete the old transcripts. - A bigger model (
medium) usually recognizes more words correctly. - Optionally set
matching.fuzzy_thresholdto80(see Matching).
The transcript file is damaged (for example the computer was switched off while writing in an old version). Delete that file; Goethe will transcribe the video again.
Videos must be directly inside videos/ (not in sub-folders) and have an extension listed in video_formats.
Goethe uses the folder it lives in, no matter where you start it from. Make sure main.py and the modules/ folder are together.
source venv/bin/activate
pip install -r requirements.txt
python3 setup.py # checks everything and reports what is missingThe tests need no extra packages:
python3 -m unittest discover -s tests -t . -vThey cover matching (including phrases across segments, umlauts, fuzzy fallback), file names, MP3 extraction (with ffmpeg replaced by a stand-in), configuration, video discovery and terminal alignment.
- Only video files directly inside
videos/are processed (no sub-folders). - Matching is only as good as the recognized text. Whisper can mishear or skip words, especially with background music or noise.
- Clip boundaries come from Whisper's word timestamps, which can be off by a fraction of a second. Increase
audio.padding_before/audio.padding_afterif clips start or end too abruptly. - Fuzzy matching works on spelling similarity, not on sound.
- Fork the repository
- Create a feature branch
- Run the tests
- Submit a pull request
MIT License - free to use, modify, and share.
- faster-whisper - speech recognition
- FFmpeg - audio extraction
- Hugging Face - model hosting
- GitHub: @duman-dp
- Issues: Report a bug