From 62264791ae8c3bc94d7654e2f78d2b3b1beeac01 Mon Sep 17 00:00:00 2001 From: Wolfang Torres Date: Fri, 19 Jun 2026 20:18:04 +0800 Subject: [PATCH] update to fisrt version --- pyproject.toml | 12 +- src/anki_creator_flask/__about__.py | 2 +- src/anki_creator_flask/__init__.py | 8 +- src/anki_creator_flask/homescreen.py | 8 +- src/anki_creator_flask/mainapp.py | 160 ++++++++++- src/anki_creator_flask/templates/app.html | 190 +++---------- src/anki_creator_flask/templates/create.html | 241 +++++++++++++++++ .../templates/file_list.html | 256 ++++++++++++++++++ src/anki_creator_flask/templates/process.html | 219 +++++++++++++++ 9 files changed, 919 insertions(+), 177 deletions(-) create mode 100644 src/anki_creator_flask/templates/create.html create mode 100644 src/anki_creator_flask/templates/file_list.html create mode 100644 src/anki_creator_flask/templates/process.html diff --git a/pyproject.toml b/pyproject.toml index 4e59490..3206b72 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,7 +27,9 @@ classifiers = [ ] dependencies = [ "flask", - "gunicorn" + "gunicorn", + "python-dotenv", + "anki-hsk-creator", ] [project.optional-dependencies] @@ -35,7 +37,8 @@ dev = [ "pytest", "black", "pylint", - "flakehell" + "flake8", + "flake8-pyproject", ] [project.urls] @@ -53,6 +56,7 @@ extra-dependencies = [ [tool.hatch.envs.default.scripts] format = "black --target-version=py314 src tests && isort src tests" +lint = "flake8 src" [tool.hatch.envs.types] extra-dependencies = [ @@ -128,7 +132,7 @@ msg-template="{path}:{module}:{line}: [{msg_id}({symbol}), {obj}] {msg}" logging-format-style="new" logging-modules="logging" -[tool.flakehell] +[tool.flake8] max_line_length = 88 format = "grouped" show_source = false @@ -143,7 +147,7 @@ exclude = [ "*.egg-info", ] -[tool.flakehell.plugins] +[tool.flake8.plugins] mccabe = ["+C*"] pycodestyle = ["+E*", "+W*", "-E203", "-E501", "-W503"] pyflakes = ["+F*"] diff --git a/src/anki_creator_flask/__about__.py b/src/anki_creator_flask/__about__.py index ab19860..3617157 100644 --- a/src/anki_creator_flask/__about__.py +++ b/src/anki_creator_flask/__about__.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: 2026-present Wolfang Torres # # SPDX-License-Identifier: GPL-3.0-or-later -__version__ = "0.0.1" +__version__ = "1.0.0" diff --git a/src/anki_creator_flask/__init__.py b/src/anki_creator_flask/__init__.py index a5581a2..3113118 100644 --- a/src/anki_creator_flask/__init__.py +++ b/src/anki_creator_flask/__init__.py @@ -2,17 +2,21 @@ from pathlib import Path # Pip +from dotenv import load_dotenv from flask import Flask # Local from .homescreen import homescreen from .mainapp import mainapp +load_dotenv() -def create_app(*args): + +def create_app(): + """Creates the Flask App""" # create and configure the app app = Flask(__name__, instance_relative_config=True) - app.config["APPLICATION_ROOT"] = "/hsk" + app.config["APPLICATION_ROOT"] = "/hskankicreator" # ensure the instance folder exists instance_path = Path(app.instance_path) diff --git a/src/anki_creator_flask/homescreen.py b/src/anki_creator_flask/homescreen.py index 2a5cfe0..0524c1c 100644 --- a/src/anki_creator_flask/homescreen.py +++ b/src/anki_creator_flask/homescreen.py @@ -6,18 +6,20 @@ homescreen = Blueprint( "homescreen", __name__, template_folder="templates", - url_prefix="/hsk", + url_prefix="/hskankicreator", static_folder="static", ) @homescreen.route("/") def index(): - return render_template(f"index.html") + """main page""" + return render_template("index.html") @homescreen.route("/favicon.ico") def favicon(): + """favicon""" return send_from_directory( current_app.static_folder, "favicon.ico", mimetype="image/vnd.microsoft.icon" ) @@ -26,7 +28,7 @@ def favicon(): @homescreen.route("/", defaults={"page": "index"}) @homescreen.route("/") def show(page): - print(page) + """general entry for other pages""" try: return render_template(f"{page}.html") except TemplateNotFound: diff --git a/src/anki_creator_flask/mainapp.py b/src/anki_creator_flask/mainapp.py index b845b61..5dfcff6 100644 --- a/src/anki_creator_flask/mainapp.py +++ b/src/anki_creator_flask/mainapp.py @@ -1,28 +1,168 @@ +# Standard Library +from pathlib import Path + # Pip -from flask import Blueprint, render_template, request +from anki_hsk_creator import api +from anki_hsk_creator.constants import DICT_TYPE, PHRASES_TYPE +from anki_hsk_creator.utility import ProcessFile +from flask import ( + Blueprint, + make_response, + redirect, + render_template, + request, + send_from_directory, + url_for, +) mainapp = Blueprint( "mainapp", __name__, template_folder="templates", - url_prefix="/hsk/app", + url_prefix="/hskankicreator/app", static_folder="static", ) -@mainapp.route("/", methods=["GET", "POST"]) -def show(): +@mainapp.route("/", methods=["GET"]) +def app(): + """Main app entry pages""" + return render_template("app.html") + + +@mainapp.route("/list", methods=["GET"]) +@mainapp.route("/list/", methods=["GET"]) +@mainapp.route("/list/", methods=["GET"]) +def file_list(listing_path=""): + """Path for file lister""" + listing_path = Path(listing_path) + root_files = {file: [] for file in api.list_input_files()} + level = root_files + level_path = Path() + for part in listing_path.parts: + level_path = level_path / part + level[level_path] = {file: [] for file in api.list_input_files(level_path)} + level = level[level_path] + + if listing_path: + file_data = api.analize_input_files(listing_path) + else: + file_data = api.analize_input_files(None) + return render_template( + "file_list.html", + file_data=file_data, + root_files=root_files, + listing_path=listing_path, + ) + + +@mainapp.route("/download/", methods=["GET"]) +def download(listing_path): + """Download a file from DATA_FOLDER / DOWNLOAD""" + download_path = api.get_output_folder() / listing_path + return send_from_directory(download_path.parent, download_path.name) + + +@mainapp.route("/resource/", methods=["GET"]) +def resource(listing_path): + """Gets a file from DATA_FOLDER / RESOURCES""" + download_path = api.get_resources_folder() / listing_path + return send_from_directory(download_path.parent, download_path.name) + + +@mainapp.route("/create", methods=["GET", "POST"]) +@mainapp.route("/create/", methods=["GET", "POST"]) +@mainapp.route("/create/", methods=["GET", "POST"]) +def create(listing_path=""): + """Main text editor""" if request.method == "GET": + if api.is_file(listing_path): + text = api.read_input_file(listing_path) + else: + text = "" args = request.args.to_dict() deck_type = args.get("deck_type", "") - language = args.get("language", "") - output_type = args.get("output_type", "") - if not deck_type or not language or not output_type: + language_id = args.get("language_id", "") + if not deck_type and not language_id: state = "new" + elif not deck_type or not language_id: + state = "partial" else: state = "complete" - elif request.method == "POST": - state = "ready" + # output_type = args.get("output_type", "") + # if not deck_type or not language_id or not output_type: + return render_template( + "create.html", + data={ + "text": text, + "deck_type": deck_type, + "language_id": language_id, + "state": state, + }, + ) + else: + listing_path = Path(listing_path) form = request.form.to_dict() + args = request.args.to_dict() + process_file = api.create_input_file( + listing_path.name.split(".")[0], + "." + args["deck_type"], + form["text"], + listing_path.parent, + ) + if args["deck_type"] in DICT_TYPE: + api.pre_process_a_dictionary_file(process_file, args["language_id"]) + return redirect( + url_for( + "mainapp.process", + listing_path=process_file.relative_dictionary_resource_file, + language_id=args["language_id"], + ), + code=303, + ) + elif args["deck_type"] in PHRASES_TYPE: + final_file = api.process_a_phrases_file(process_file, args["language_id"]) + response = make_response( + send_from_directory(final_file.parent, final_file.name) + ) + response.set_cookie("download_started", "true", max_age=10) + return response - return render_template(f"app.html", data=locals()) + +@mainapp.route("/process/", methods=["GET", "POST"]) +def process(listing_path): + """Post process tsv file""" + listing_path = Path(listing_path) + input_file = listing_path.parent + input_file = input_file.parent / f"{input_file.name}.txt" + process_file = ProcessFile(input_file) + languages = process_file.available_dictionary_languages + args = request.args.to_dict() + language_id = args.get("language_id", listing_path.stem.split(".")[1]) + if request.method == "GET": + if not language_id: + state = "new" + text = "" + else: + state = "complete" + text = api.read_dictionary_file(process_file, language_id) + output_type = args.get("output_type", "") + return render_template( + "process.html", + languages=languages, + data={ + "output_type": output_type, + "language_id": language_id, + "state": state, + "text": text, + }, + ) + elif request.method == "POST": + form = request.form.to_dict() + api.write_resource_file(process_file, language_id, form["text"]) + final_file = api.process_a_dictionary_file(process_file, language_id) + response = make_response( + send_from_directory(final_file.parent, final_file.name) + ) + response.set_cookie("download_started", "true", max_age=10) + return response diff --git a/src/anki_creator_flask/templates/app.html b/src/anki_creator_flask/templates/app.html index 0c3d578..bfa0823 100644 --- a/src/anki_creator_flask/templates/app.html +++ b/src/anki_creator_flask/templates/app.html @@ -10,7 +10,10 @@ /> - +
-

Select the deck type

+

HSK Anki Creator

-
-

- Paste here the word list -

-
-
-
- -
-
-
    -
  • - -
  • -
-
-
+
-
-
    -
  • -

    Deck Type

    -
    - - -
    -
    - - -
    -
    - - -
    -
  • -
  • -

    Language

    - -
  • -
  • -

    Output

    -
    - - -
    -
    - - -
    -
  • -
  • - -
    - Reset Settings -
  • -
-
+
@@ -136,63 +62,13 @@ - - - - - - - - + + + + + + + + diff --git a/src/anki_creator_flask/templates/create.html b/src/anki_creator_flask/templates/create.html new file mode 100644 index 0000000..c55a86b --- /dev/null +++ b/src/anki_creator_flask/templates/create.html @@ -0,0 +1,241 @@ + + + + + HSK card creator + + + + + + + + + + + +
+
+

Loading, please wait...

+
+ + +
+ +
+
+

Select the deck type

+
+ +
+

+ Paste here the word list +

+
+
+
+ +
+
+
    +
  • + +
  • +
+
+
+ +
+
+
    +
  • +

    Deck Type

    +
    + + +
    +
    + + +
    +
    + + +
    +
  • +
  • +

    Language

    + +
  • +
  • + +
    + Reset Settings +
    + Back +
  • +
+
+
+
+ + + +
+ + + + + + + + + + + + diff --git a/src/anki_creator_flask/templates/file_list.html b/src/anki_creator_flask/templates/file_list.html new file mode 100644 index 0000000..8182451 --- /dev/null +++ b/src/anki_creator_flask/templates/file_list.html @@ -0,0 +1,256 @@ + + + + + HSK card creator + + + + + + + + + + + +
+ +
+ +
+

Files

+
+ +
+

Current Path: {{ listing_path or "-" }}

+
    +
  • + Input files: +
      + {% for file in file_data['input'] %} +
    • + {% if file.suffixes %} + + {{ file.name }} + + {% else %} {{ file.name }} {% endif %} +
    • + {% endfor %} +
    +
  • +
  • + Resources files: +
      + {% for file in file_data['resources'] %} {% if file.suffix == + ".wav" %} + + {% elif file.suffix == ".tsv" %} +
    • + {{ file.name }} +
    • + {% else %} +
    • {{ file.name }}
    • + {% endif %} {% endfor %} +
    +
  • +
  • + Output files: +
      + {% for file in file_data['output'] %} +
    • + {% if file.suffix %} + {{ file.name }} + {% else %} {{ file.name }} {% endif %} +
    • + {% endfor %} +
    +
  • +
+
+ +
+
+
    + + {% for file1 in root_files %} +
  • +
    + + {{ file1 }} + +
      + {% for file2 in root_files[file1] %} {% if file2.suffix %} +
    • + {{ file2.name }} +
    • + {% else %} +
    • +
      + + {{ file2.name }} + +
        + {% for file3 in root_files[file1][file2] %} +
      • + {{ file3.name }} +
      • + {% endfor %} +
      +
      +
    • + {% endif %} {% endfor %} +
    +
    +
  • + {% endfor %} +
+
+
+
+ + + +
+ + + + + + + + + + + + diff --git a/src/anki_creator_flask/templates/process.html b/src/anki_creator_flask/templates/process.html new file mode 100644 index 0000000..de58f5e --- /dev/null +++ b/src/anki_creator_flask/templates/process.html @@ -0,0 +1,219 @@ + + + + + HSK card creator + + + + + + + + + + + +
+
+

Loading, please wait...

+
+ + +
+ +
+
+

Select the deck type

+
+ +
+

+ Delete unwanted Rows and Modify definitions +

+
+
+
+ +
+
+
    +
  • + +
  • +
+
+
+ +
+
+
    +
  • +

    Language

    + +
  • +
  • +

    Output

    +
    + + +
    +
    + + +
    +
  • +
  • + +
    + Back +
  • +
+
+
+
+ + + +
+ + + + + + + + + + + +