Skip to content

Commit

Permalink
You can now add Noun cards to Anki
Browse files Browse the repository at this point in the history
  • Loading branch information
kmoragap committed Dec 4, 2024
1 parent 81faf9c commit a1dc89c
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 19 deletions.
14 changes: 10 additions & 4 deletions anki/anki_utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from anki.collection import Collection
from templates.card_template import get_front_template, get_back_template
from templates.card_template import get_front_template, get_back_template, get_noun_front_template, get_noun_back_template

def add_card_to_anki(data, config):
col = Collection(config.ANKI_COLLECTION_PATH)
Expand All @@ -16,9 +16,15 @@ def add_card_to_anki(data, config):
note = col.new_note(model)
note.deck_id = deck_id

# Create card content using templates
note.fields[0] = get_front_template(data, config.COLORS)
note.fields[1] = get_back_template(data, config.COLORS)
if 'verb' in data:
front_template = get_front_template(data, config.COLORS)
back_template = get_back_template(data, config.COLORS)
else:
front_template = get_noun_front_template(data, config.COLORS)
back_template = get_noun_back_template(data, config.COLORS)

note.fields[0] = front_template
note.fields[1] = back_template

col.add_note(note, deck_id)
#print(f"'{data['verb']}' successfully added to deck '{config.DECK_NAME}'.")
Expand Down
41 changes: 29 additions & 12 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import config
from scraper.verb_scraper import extract_verb_data, extract_multiple_verbs
from scraper.noun_scraper import extract_noun_data, extract_multiple_nouns
from anki.anki_utils import add_card_to_anki

def main():
Expand All @@ -20,21 +21,36 @@ def main():
input(f"{Fore.YELLOW}Press Enter to continue once Anki is closed...{Style.RESET_ALL}")

if len(sys.argv) < 2:
print(f"{Fore.RED}Error: At least one verb is required as an argument{Style.RESET_ALL}")
print(f"{Fore.YELLOW}Usage: python main.py <verb1> <verb2> ... <verbN>{Style.RESET_ALL}")
print(f"\n{Fore.CYAN}💡 Pro tip: You can add multiple verbs at once!{Style.RESET_ALL}")
print(f"{Fore.RED}Error: Arguments required{Style.RESET_ALL}")
print(f"{Fore.YELLOW}Usage for verbs: python main.py <verb1> <verb2> ... <verbN>{Style.RESET_ALL}")
print(f"{Fore.YELLOW}Usage for nouns: python main.py --noun <noun1> <noun2> ... <nounN>{Style.RESET_ALL}")
print(f"\n{Fore.CYAN}💡 Pro tip: You can add multiple words at once!{Style.RESET_ALL}")
return

is_noun = False
if sys.argv[1] == '--noun':
if len(sys.argv) < 3:
print(f"{Fore.RED}Error: At least one noun is required after --noun{Style.RESET_ALL}")
return
is_noun = True
words = sys.argv[2:]
else:
words = sys.argv[1:]

word_type = "nouns" if is_noun else "verbs"
print(f"{Fore.CYAN}🔍 Searching for information for the {word_type}: {Fore.WHITE}{', '.join(words)}...{Style.RESET_ALL}")

words = sys.argv[1:]
print(f"{Fore.CYAN}🔍 Searching for information for the verbs: {Fore.WHITE}{', '.join(words)}...{Style.RESET_ALL}")
if is_noun:
data = extract_multiple_nouns(words, config)
else:
data = extract_multiple_verbs(words, config)

data = extract_multiple_verbs(words, config)
for word, verb_data in data.items():
if verb_data:
print(f"{Fore.GREEN}✅ Adding card for the verb: {word}{Style.RESET_ALL}")
add_card_to_anki(verb_data, config)
for word, word_data in data.items():
if word_data:
print(f"{Fore.GREEN}✅ Adding card for the {word_type[:-1]}: {word}{Style.RESET_ALL}")
add_card_to_anki(word_data, config)
else:
print(f"{Fore.RED}❌ No information found for the verb: {word}{Style.RESET_ALL}")
print(f"{Fore.RED}❌ No information found for the {word_type[:-1]}: {word}{Style.RESET_ALL}")

print("\n")
print(f"{Fore.BLUE}📚 Enjoy your language learning journey!{Style.RESET_ALL}")
Expand All @@ -46,5 +62,6 @@ def main():
print("\n")
print(f"{Fore.CYAN}🌟 Spread the word! Share VerbForm with your friends!{Style.RESET_ALL}")
print("\n")

if __name__ == "__main__":
main()
main()
80 changes: 80 additions & 0 deletions scraper/noun_scraper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import requests
from bs4 import BeautifulSoup
from verb_scraper import download_audio
import os

def extract_noun_data(word, config):
"""Main function to extract noun data from verbformen.de"""
url = f"{config.BASE_URL}/deklination/substantive/steckbrief/info/{word}.htm"
headers = {"Accept-Language": config.LANGUAGE}

response = requests.get(url, headers=headers)
if response.status_code != 200:
print(f"Error: Could not access page for word '{word}'.")
return None

soup = BeautifulSoup(response.text, "html.parser")
data = {}

noun_element = soup.find("span", class_="vGrnd")
if noun_element:
data["noun"] = noun_element.text.strip()

if audio_link := noun_element.find("a"):
audio_filename = f"{data['noun']}_noun.mp3"
data["audio_noun"] = download_audio(
audio_link["href"],
audio_filename,
config.ANKI_MEDIA_PATH,
config.BASE_URL
)

if stem_element := soup.find("p", class_="vStm"):
data["stem"] = stem_element.text.strip()

if audio_link := stem_element.find("a"):
audio_filename = f"{data['noun']}_stem.mp3"
data["audio_stem"] = download_audio(
audio_link["href"],
audio_filename,
config.ANKI_MEDIA_PATH,
config.BASE_URL
)

if translation_block := soup.find("p", class_="r1Zeile rU3px rO0px", style="font-size: 1.22em"):
if translation_span := translation_block.find("span", lang=config.LANGUAGE):
all_translations = translation_span.text.strip().split(',')
selected_translations = [t.strip() for t in all_translations[:3]]
data["translation_noun"] = ', '.join(selected_translations)

if definition_block := soup.find("p", class_="rInf r1Zeile rU3px rO0px"):
if definition_block.find("i"):
data["definition_noun"] = definition_block.text.strip()

example_block = soup.find(lambda tag: tag.name == "p" and "»" in tag.get_text())
if example_block:
spans = example_block.find_all("span")
if len(spans) >= 2:
german_example = spans[0].get_text()
german_example = german_example.replace("»", "").strip()

translation_span = spans[2]
if translation_span.find('img'):
translation_span.find('img').decompose()
example_translation = translation_span.get_text().strip()

data["example_noun"] = german_example
data["example_noun_translation"] = example_translation
else:
print("Could not extract example and translation.")

return data

def extract_multiple_nouns(nouns, config):
"""Extract data for multiple nouns"""
data = {}
for noun in nouns:
noun_data = extract_noun_data(noun, config)
if noun_data:
data[noun] = noun_data
return data
8 changes: 5 additions & 3 deletions scraper/verb_scraper.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,12 @@ def extract_verb_data(word, config):

def extract_multiple_verbs(verbs, config):
"""Extract data for multiple verbs"""
results = {}
data = {}
for verb in verbs:
results[verb] = extract_verb_data(verb, config)
return results
verb_data = extract_verb_data(verb, config)
if verb_data:
data[verb] = verb_data
return data

#def search_verb(word, config):
# """Search for verb suggestions"""
Expand Down
34 changes: 34 additions & 0 deletions templates/card_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,38 @@ def get_back_template(data, colors):
<div style="color: {colors['blue']}; margin-top: 5px;">{data.get('example_translation', '')}</div>
</div>
</div>
"""

def get_noun_front_template(data, colors):
return f"""
<div style="font-size: 24px; text-align: center; color: {colors['purple']}; margin: 20px 0; background: {colors['bg']};">
{data.get('translation_noun', '')}
</div>
"""

def get_noun_back_template(data, colors):
return f"""
<div style="font-family: Arial; line-height: 1.6; padding: 15px; background: {colors['bg']}; color: {colors['fg']};">
<div style="font-size: 28px; color: {colors['purple']}; text-align: center; margin-bottom: 20px;">
{data.get('noun', '')} {data.get('audio_noun', '')}
</div>
<div style="background: {colors['bg_highlight']}; padding: 10px; border-radius: 5px; margin: 10px 0;">
<div style="color: {colors['gray']};">Genitive and Plural:</div>
{data.get('stem', '')} {data.get('audio_stem', '')}
</div>
<details style="margin: 10px 0; background: {colors['bg_highlight']}; padding: 10px; border-radius: 5px;">
<summary style="color: {colors['blue']}; cursor: pointer;">View definition</summary>
<div style="padding: 10px 0;">
{data.get('definition_noun', '')}
</div>
</details>
<div style="background: {colors['bg_highlight']}; padding: 10px; border-radius: 5px; margin: 10px 0;">
<div style="color: {colors['gray']};">Example:</div>
<div style="margin: 5px 0; color: {colors['fg']};">{data.get('example_noun', '')}</div>
<div style="color: {colors['blue']}; margin-top: 5px;">{data.get('example_noun_translation', '')}</div>
</div>
</div>
"""

0 comments on commit a1dc89c

Please sign in to comment.