diff --git a/Makefile b/Makefile index 1d0b2ec..419db79 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,12 @@ -dest_dir := /usr/local/src/cambd-cli -bin_file := /usr/bin/cambd +DIST = /usr/local/src/cambd-cli +BIN = /usr/bin/cambd install: - cp -f cambd-cli/cambd.sh $(bin_file) - chmod +x $(bin_file) - mkdir -m 777 -p $(dest_dir) - cp -f cambd-cli/cambd.py $(dest_dir)/cambd.py - @echo "\nInstall successful ✅" + cp -f cambd-cli/cambd.sh $(BIN) + chmod +x $(BIN) + mkdir -m 777 -p $(DIST) + cp -f cambd-cli/cambd.py $(DIST) + @echo "Install successful." uninstall: rm -rf $(bin_file) diff --git a/README.md b/README.md index 04b5ebd..2713aa1 100644 --- a/README.md +++ b/README.md @@ -42,22 +42,23 @@ cambd neccesseery > The above word spelling is incorrect. So cambd will suggest related words. -## Uninstall - -To uninstall you can run the below command from the `cambd-cli` directory - -```sh -sudo make uninstall -``` - ## TODO: - [x] Add loading animation - [x] Handle error for getting definition of words with spaces - [x] Show only 2 examples per definition by default -- [ ] Implement a basic local caching mechanism +- [x] Implement a basic local caching mechanism - [ ] Add flag to show all definitions. Default is 1 +## Caching + +This is how the basic caching feature is implemented + +- Search definition for given word in the CLI. +- Check if the word was already looked up before in the cache file in `$HOME`. +- If yes then return it from the cache file immediently. +- If not fetch the new definition and add it to the cache file for future usecase. + ## LICENSE [MIT](./LICENSE) License © [Rocktim Saikia](https://rocktimsaikia.com) 2022 diff --git a/cambd-cli/cambd.py b/cambd-cli/cambd.py index c1002a8..bdbdaf5 100644 --- a/cambd-cli/cambd.py +++ b/cambd-cli/cambd.py @@ -1,18 +1,22 @@ #!/bin/env python3 +import os +import re import sys +import yaml +import json import requests from bs4 import BeautifulSoup from simple_term_menu import TerminalMenu from halo import Halo -import yaml -import re spinner = Halo(text="Loading", spinner="dots") +# Don't touch this. Unless you want to deal with permission issues in other places +cached_dictionary = os.path.expanduser("~") + "/.cambd-cache.json" + spellcheck_url = "https://dictionary.cambridge.org/spellcheck/english/?q=" definition_url = "https://dictionary.cambridge.org/dictionary/english/" -# This is needed to not get detected as a bot headers = {"User-Agent": "Mozilla/5.0"} @@ -31,11 +35,36 @@ def get_suggestions(word: str) -> list[str]: return suggested_words +def is_cached(word: str): + # File exists and has content + if os.path.exists(cached_dictionary) and os.path.getsize(cached_dictionary) > 0: + with open(cached_dictionary, "r") as file: + file_data = json.load(file) + if word in file_data: + return file_data[word] + + +def cache_it(word, definitions): + # File does not exists or file is empty; + if not os.path.exists(cached_dictionary) or os.path.getsize(cached_dictionary) == 0: + with open(cached_dictionary, "w") as ofile: + json.dump({word: definitions}, ofile) + return + + # Content already exists, append + with open(cached_dictionary, "r+") as ofile: + file_data = json.load(ofile) + file_data[word] = definitions + ofile.seek(0) + json.dump(file_data, ofile) + + @spinner def get_definitions(word: str) -> list[str]: - # In browser, getting definition for word with spaces inbetween automatically formats dashes (-) replacing the spaces - # Replicating the same behaviour here too for consistency - word = word.strip().replace(" ", "-") + # Return cahced version if available + cached_word = is_cached(word) + if cached_word is not None: + return cached_word response = requests.get(definition_url + word, headers=headers) @@ -76,7 +105,8 @@ def get_definitions(word: str) -> list[str]: def main(): arg = sys.argv[1:][0] - definitions = get_definitions(arg) + word = arg.strip().replace(" ", "-").lower() + definitions = get_definitions(word) if len(definitions) == 0: suggestions = get_suggestions(arg) @@ -86,12 +116,13 @@ def main(): menu_entry_index = terminal_menu.show() if type(menu_entry_index) is int: - arg = suggestions[menu_entry_index] - definitions = get_definitions(arg) + suggested_word = suggestions[menu_entry_index] + definitions = get_definitions(suggested_word) spinner.succeed(f"Showing definition for: \033[1m{arg}\033[0m") print("\n" + yaml.dump(definitions[0], indent=3, sort_keys=False)) + cache_it(word, definitions) if __name__ == "__main__":