Created
July 2, 2026 08:49
-
-
Save mifth/b7c233d3fe7eee5ad9f5140930a8cd16 to your computer and use it in GitHub Desktop.
Anki files generator.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python3 | |
| """ | |
| Generate Anki .apkg files from .txt files | |
| Each line in .txt files should be: English;Italian | |
| """ | |
| import os | |
| import re | |
| from pathlib import Path | |
| import genanki | |
| def sanitize_filename(filename): | |
| """Convert filename to a valid deck name""" | |
| # Remove .txt extension | |
| name = filename.replace('.txt', '') | |
| # Replace underscores with spaces | |
| name = name.replace('_', ' ') | |
| # Remove 'anki italian' prefix if present | |
| name = re.sub(r'^anki\s+italian\s+', '', name, flags=re.IGNORECASE) | |
| # Capitalize words | |
| name = ' '.join(word.capitalize() for word in name.split()) | |
| return name | |
| def create_apkg(txt_file, output_dir): | |
| """Generate .apkg file from a .txt file""" | |
| try: | |
| txt_path = Path(txt_file) | |
| deck_name = sanitize_filename(txt_path.name) | |
| # Generate a consistent numeric ID based on filename | |
| deck_id = abs(hash(txt_path.name)) % (10 ** 10) | |
| model_id = abs(hash(txt_path.name + '_model')) % (10 ** 10) | |
| font_size = 24 | |
| # Create model (card template) | |
| model = genanki.Model( | |
| model_id, | |
| 'Italian Vocabulary', | |
| fields=[ | |
| {'name': 'Front'}, | |
| {'name': 'Back'}, | |
| ], | |
| templates=[ | |
| { | |
| 'name': 'Card 1', | |
| 'qfmt': f'<div style="text-align: center; font-size: {font_size}px; padding: 20px; margin: 0; line-height: 1.2;">{{{{Front}}}}</div><div style="text-align: center; font-size: {font_size}px; padding: 20px; margin: 0; visibility: hidden;">{{{{Back}}}}</div>', | |
| 'afmt': f'<div style="text-align: center; font-size: {font_size}px; padding: 20px; margin: 0; line-height: 1.2;">{{{{Front}}}}</div><hr id=answer style="margin: 20px 0;"><div style="text-align: center; font-size: {font_size}px; padding: 20px; margin: 0;">{{{{Back}}}}</div>', | |
| }, | |
| ]) | |
| # Create deck | |
| deck = genanki.Deck(deck_id, deck_name) | |
| # Parse txt file and add notes | |
| notes = [] | |
| with open(txt_file, 'r', encoding='utf-8') as f: | |
| for line in f: | |
| line = line.strip() | |
| if not line or ';' not in line: | |
| continue | |
| parts = line.split(';', 1) | |
| if len(parts) == 2: | |
| front, back = parts | |
| front = front.strip() | |
| back = back.strip() | |
| if front and back: | |
| note = genanki.Note( | |
| model=model, | |
| fields=[front, back] | |
| ) | |
| notes.append(note) | |
| # Add all notes to deck | |
| for note in notes: | |
| deck.add_note(note) | |
| # Generate output filename | |
| output_filename = txt_path.stem + '.apkg' | |
| output_path = os.path.join(output_dir, output_filename) | |
| # Package the deck | |
| genanki.Package(deck).write_to_file(output_path) | |
| print(f'✓ Created {output_filename} ({len(notes)} cards)') | |
| except Exception as e: | |
| print(f'✗ Error processing {txt_file}: {e}') | |
| def main(): | |
| """Process all .txt files in the current directory""" | |
| current_dir = Path(__file__).parent | |
| output_dir = current_dir | |
| # Find all .txt files | |
| txt_files = sorted(current_dir.glob('anki_*.txt')) | |
| if not txt_files: | |
| print('No .txt files found matching anki_*.txt pattern') | |
| return | |
| print(f'Found {len(txt_files)} .txt files') | |
| print('Generating .apkg files...\n') | |
| for txt_file in txt_files: | |
| create_apkg(txt_file, output_dir) | |
| print(f'\n✓ All .apkg files generated in {output_dir}') | |
| if __name__ == '__main__': | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment