From 0f1f9e84cbed6b0e9027627cc14355db81c4fa83 Mon Sep 17 00:00:00 2001 From: alexander Date: Sun, 25 Jan 2026 23:20:56 +0100 Subject: [PATCH] Added devision by semester --- .gitignore | 1 + src/build.py | 11 +++- src/config.py | 1 + src/inventory.py | 33 ++++++++-- src/sources/__init__.py | 2 + src/sources/codeberg.py | 4 +- src/sources/gitea.py | 4 +- src/sources/plain.py | 5 +- src/sources/util.py | 25 +++++--- static/css/main.css | 44 ++++++++++++-- static/css/main.css.map | 2 +- styles/main.scss | 44 ++++++++++++-- templates/index.html.j2 | 130 ++++++++++++++++++++++++++++------------ 13 files changed, 237 insertions(+), 69 deletions(-) diff --git a/.gitignore b/.gitignore index 451ad7c..3921f9b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .venv out prod +cache node_modules __pycache__/ diff --git a/src/build.py b/src/build.py index 4896946..cb596cc 100644 --- a/src/build.py +++ b/src/build.py @@ -19,7 +19,7 @@ def build(trigger_list: list[str] | None = None): # Clear output directory shutil.rmtree(settings.paths.output, ignore_errors=True) shutil.copytree(settings.paths.static, settings.paths.output) - inv: list[CSItem] = prepare_cheatsheets(inv_raw, settings.paths.output) + inv, cats, no_cat = prepare_cheatsheets(inv_raw) if not os.path.exists(settings.paths.prod): os.mkdir(settings.paths.prod) @@ -38,8 +38,15 @@ def build(trigger_list: list[str] | None = None): thisYear = datetime.datetime.now().year + print(cats) + with open(f"{settings.paths.output}/index.html", "w", encoding="utf-8") as f: - f.write(index.render(items=inv, thisYear=thisYear)) + f.write(index.render(cats=list( + sorted( + map(lambda c: (c[0], list(c[1].items())), cats.items()), + key=lambda x: x[0] + ) + ), no_cat=no_cat, thisYear=thisYear)) with open(f"{settings.paths.output}/impressum.html", "w", encoding="utf-8") as f: f.write(env.get_template("impressum.html.j2").render(thisYear=thisYear)) diff --git a/src/config.py b/src/config.py index cc1b698..11df98b 100644 --- a/src/config.py +++ b/src/config.py @@ -10,6 +10,7 @@ class PathsConfig(BaseSettings): static: str = Field(default="static", description="Static files directory") output: str = Field(default="out", description="Output directory") prod: str = Field(default="prod", description="Production directory") + cache: str = Field(default="cache", description="Cache directory") class Settings(BaseSettings): diff --git a/src/inventory.py b/src/inventory.py index 5f1e5a0..b529728 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -1,5 +1,6 @@ import os import traceback +import re from sources import CSInventoryConfig, CSItem, CheatsheetSourceType from sources.plain import process_plain_url @@ -23,7 +24,7 @@ def load_cheatsheet_inventory(file: str) -> CSInventoryConfig: return res -def prepare_cheatsheets(config: CSInventoryConfig, outdir: str) -> list[CSItem]: +def prepare_cheatsheets(config: CSInventoryConfig) -> list[CSItem]: res: list[CSItem] = [] logger = get_worker_thread_logger() @@ -34,13 +35,13 @@ def prepare_cheatsheets(config: CSInventoryConfig, outdir: str) -> list[CSItem]: try: match item.source.type: case CheatsheetSourceType.GITEA_SOURCE: - new_items += process_gitea(item, outdir) + new_items += process_gitea(item) case CheatsheetSourceType.PLAIN_URL: - new_items.append(process_plain_url(item, outdir)) + new_items.append(process_plain_url(item)) case CheatsheetSourceType.CODEBERG_SOURCE: - new_items += process_codeberg(item, outdir) + new_items += process_codeberg(item) case _: logger.warning("Unknown Source Type: %s", item.source.type) @@ -54,7 +55,29 @@ def prepare_cheatsheets(config: CSInventoryConfig, outdir: str) -> list[CSItem]: new_item: CSItem = new_item logger.debug(f"-> {new_item.title} ({new_item.url})") res.append(new_item) + + no_cat: list[CSItem] = [] + cats: dict[int, dict[str, list[CSItem]]] = {} - return res + for item in res: + m = re.match(r"[sS][eE][mM]([eE][sS][tT][eE][rR])?(\d+)-(.*)", item.title.strip()) + if m: + semester = int(m.group(2)) + module = str(m.group(3)).lower().strip() \ + .replace("_", " ").replace("-", " ").title() + + if semester not in cats: + cats[semester] = {} + + if module not in cats[semester]: + cats[semester][module] = [] + + item.semester = semester + item.module = module + cats[semester][module].append(item) + else: + no_cat.append(item) + + return res, cats, no_cat diff --git a/src/sources/__init__.py b/src/sources/__init__.py index 6f1bc7d..3b10bd9 100644 --- a/src/sources/__init__.py +++ b/src/sources/__init__.py @@ -59,4 +59,6 @@ class CSItem(BaseModel): id: str git_repo: str git_repo_type: str + semester: int | None = 0 + module: str | None = "" diff --git a/src/sources/codeberg.py b/src/sources/codeberg.py index 176561e..dde82b1 100644 --- a/src/sources/codeberg.py +++ b/src/sources/codeberg.py @@ -7,7 +7,7 @@ from pathlib import Path from logger import get_worker_thread_logger -def process_codeberg(item: CSInventoryItem, outdir: str) -> list[CSItem] | None: +def process_codeberg(item: CSInventoryItem) -> list[CSItem] | None: logger = get_worker_thread_logger() logger.info(f"Processing Gitea cheatsheet: {item.source.owner}/{item.source.repo}@{item.source.tag}") source: CSSourceGitea = item.source @@ -29,7 +29,7 @@ def process_codeberg(item: CSInventoryItem, outdir: str) -> list[CSItem] | None: for fetch_url, real_url in assets_urls: if item.cache: - cache_url = cache_cheatsheet(fetch_url, outdir) + cache_url = cache_cheatsheet(fetch_url) if cache_url: real_url = cache_url else: diff --git a/src/sources/gitea.py b/src/sources/gitea.py index 4e0bc5c..449866a 100644 --- a/src/sources/gitea.py +++ b/src/sources/gitea.py @@ -6,7 +6,7 @@ from pathlib import Path from logger import get_worker_thread_logger -def process_gitea(item: CSInventoryItem, outdir: str) -> list[CSItem] | None: +def process_gitea(item: CSInventoryItem) -> list[CSItem] | None: logger = get_worker_thread_logger() logger.info(f"Processing Gitea cheatsheet: {item.source.owner}/{item.source.repo}@{item.source.tag}") source: CSSourceGitea = item.source @@ -28,7 +28,7 @@ def process_gitea(item: CSInventoryItem, outdir: str) -> list[CSItem] | None: for fetch_url, real_url in assets_urls: if item.cache: - cache_url = cache_cheatsheet(fetch_url, outdir) + cache_url = cache_cheatsheet(fetch_url) if cache_url: real_url = cache_url else: diff --git a/src/sources/plain.py b/src/sources/plain.py index 83e3a57..1d1de9d 100644 --- a/src/sources/plain.py +++ b/src/sources/plain.py @@ -1,12 +1,13 @@ from sources import CSInventoryItem, CSSourcePlainURL, CSItem from sources.util import cache_cheatsheet, get_datestring +from config import get_settings -async def process_plain_url(item: CSInventoryItem, outdir: str) -> CSItem | None: +async def process_plain_url(item: CSInventoryItem) -> CSItem | None: source: CSSourcePlainURL = item.source res_url = source.url if item.cache: - cache_url = await cache_cheatsheet(source.url, outdir) + cache_url = await cache_cheatsheet(source.url) if cache_url: res_url = cache_url else: diff --git a/src/sources/util.py b/src/sources/util.py index 1748b32..872e549 100644 --- a/src/sources/util.py +++ b/src/sources/util.py @@ -4,12 +4,13 @@ import os from pathlib import Path from logger import get_worker_thread_logger from urllib.parse import urlparse +from config import get_settings def get_datestring() -> str: - return datetime.datetime.now().strftime("%d.%m.%y") + return datetime.datetime.now().strftime("%d.%m.%y (%H:%M:%S)") - -def cache_cheatsheet(url, outdir: str) -> str | None: +def cache_cheatsheet(url) -> str | None: + settings = get_settings() logger = get_worker_thread_logger() logger.info(f"Caching cheatsheet from {url}") @@ -27,14 +28,22 @@ def cache_cheatsheet(url, outdir: str) -> str | None: url_base_name = Path(urlparse(url).path).stem - filesname = os.path.join("cache", f"{url_base_name}.pdf") + filesname = os.path.join(f"{url_base_name}.pdf") - if not os.path.exists(os.path.join(outdir, "cache")): - os.mkdir(os.path.join(outdir, "cache")) + if not os.path.exists(os.path.join(settings.paths.cache)): + os.mkdir(os.path.join(settings.paths.cache)) - with open(os.path.join(outdir, filesname), "wb") as f: + + if not os.path.exists(os.path.join(settings.paths.output, "cache")): + os.mkdir(os.path.join(settings.paths.output, "cache")) + + + with open(os.path.join(settings.paths.output, "cache", filesname), "wb") as f: + f.write(data) + + with open(os.path.join(settings.paths.cache, filesname), "wb") as f: f.write(data) logger.info(f"Saved file to {filesname}") - return filesname + return os.path.join("cache", filesname) diff --git a/static/css/main.css b/static/css/main.css index 9302980..6dcdcf4 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -47,8 +47,7 @@ nav.navbar a:hover { } /* Main content area padding */ -body > h1, -body > table { +body > h1, body > h2, body > h3, body > table, body > p { margin-left: 20px; margin-right: 20px; } @@ -61,17 +60,30 @@ h1 { padding-bottom: 10px; } +h2 { + color: #444; + font-size: 1.2em; + text-align: center; + font-weight: bold; + margin-top: 20px; + border-top: 1px solid #999; + padding-top: 10px; + padding-bottom: 5px; +} + h3 { color: #333; - text-align: center; + text-align: start; font-weight: normal; + margin-bottom: 5px; margin-top: 5px; } table { width: calc(100% - 40px); border-collapse: collapse; - margin-top: 20px; + margin-top: 0; + margin-bottom: 20px; background-color: #ffffff; } @@ -84,11 +96,35 @@ th, td { text-align: left; } +thead { + height: 15px; +} + th { background-color: #c0c0c0; font-weight: bold; } +tr > :nth-child(1), tr > :nth-child(1) { + width: 40%; +} + +tr > :nth-child(2), tr > :nth-child(2) { + width: 15%; +} + +tr > :nth-child(3), tr > :nth-child(3) { + width: 15%; +} + +tr > :nth-child(4), tr > :nth-child(4) { + width: 15%; +} + +tr > :nth-child(5), tr > :nth-child(5) { + width: 15%; +} + tbody tr:hover { background-color: #e8e8ff; } diff --git a/static/css/main.css.map b/static/css/main.css.map index 23b8b3d..e311719 100644 --- a/static/css/main.css.map +++ b/static/css/main.css.map @@ -1 +1 @@ -{"version":3,"sourceRoot":"","sources":["../../styles/main.scss"],"names":[],"mappings":"AAAA;AAAA;AAAA;AAAA;AAKA;EACI;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EAEA;;;AAGJ;AACA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;;;AAGJ;AACA;AAAA;EAEI;EACA;;;AAGJ;EACI;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI;;;AAGJ;EACI;EACA;;;AAGJ;EACI;EACA;;;AAGJ;EACI;;;AAGJ;AACA;EACI;EACA;EACA;EACA;EACA;EACA","file":"main.css"} \ No newline at end of file +{"version":3,"sourceRoot":"","sources":["../../styles/main.scss"],"names":[],"mappings":"AAAA;AAAA;AAAA;AAAA;AAKA;EACI;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EAEA;;;AAGJ;AACA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;;;AAGJ;AACA;EACI;EACA;;;AAGJ;EACI;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;EACA;;;AAGJ;EACI;;;AAGJ;EACI;EACA;;;AAGJ;EACI;;;AAGJ;EACI;EACA;;;AAGJ;EACI;;;AAGJ;EACI;;;AAGJ;EACI;;;AAGJ;EACI;;;AAGJ;EACI;;;AAGJ;EACI;;;AAGJ;AACA;EACI;EACA;EACA;EACA;EACA;EACA","file":"main.css"} \ No newline at end of file diff --git a/styles/main.scss b/styles/main.scss index e203879..0849718 100644 --- a/styles/main.scss +++ b/styles/main.scss @@ -50,8 +50,7 @@ nav.navbar a:hover { } /* Main content area padding */ -body > h1, -body > table { +body > h1, body > h2, body > h3, body > table, body > p { margin-left: 20px; margin-right: 20px; } @@ -64,17 +63,30 @@ h1 { padding-bottom: 10px; } +h2 { + color: #444; + font-size: 1.2em; + text-align: center; + font-weight: bold; + margin-top: 20px; + border-top: 1px solid #999; + padding-top: 10px; + padding-bottom: 5px; +} + h3 { color: #333; - text-align: center; + text-align: start; font-weight: normal; + margin-bottom: 5px; margin-top: 5px; } table { width: calc(100% - 40px); border-collapse: collapse; - margin-top: 20px; + margin-top: 0; + margin-bottom: 20px; background-color: #ffffff; } @@ -87,11 +99,35 @@ th, td { text-align: left; } +thead { + height: 15px; +} + th { background-color: #c0c0c0; font-weight: bold; } +tr > :nth-child(1), tr > :nth-child(1) { + width: 40%; +} + +tr > :nth-child(2), tr > :nth-child(2) { + width: 15%; +} + +tr > :nth-child(3), tr > :nth-child(3) { + width: 15%; +} + +tr > :nth-child(4), tr > :nth-child(4) { + width: 15%; +} + +tr > :nth-child(5), tr > :nth-child(5) { + width: 15%; +} + tbody tr:hover { background-color: #e8e8ff; } diff --git a/templates/index.html.j2 b/templates/index.html.j2 index 3fd3a67..55b313a 100644 --- a/templates/index.html.j2 +++ b/templates/index.html.j2 @@ -10,7 +10,7 @@ {% include "navbar.j2" %}

typst4ei

-

Eine Sammlung von Formelsammlung für/von EI Stundenten der TUM

+

Eine Sammlung von Formelsammlung für/von EI Stundenten der TUM

Disclaimer: Die Richtigkeit des Materials kann nicht garantiert werden. @@ -19,44 +19,96 @@ Aber Feedback und Korrekturen sind immer willkommen!

- - - - - - - - - - - {% for item in items %} - - - - - - - {% endfor %} - -
TitleRepoUpload DateGit commit
- {{ item.title }} - - {% if item.author %} -
by {{ item.author }} - {% endif %} -
- {% if item.git_repo %} - {{ item.git_repo_type }} - {% else %} - N/A - {% endif %} - - {{ item.date }} - - {% if item.git_repo %} - {{ item.commit }} - {% endif %} -
+ {% for item in cats %} +

{{ item[0] }}. Semester

+ + + + + + + + + + + + {% for module in item[1] %} + {% for item in module[1] %} + + + + + + + + {% endfor %} + {% endfor %} + +
TitleAutorRepoUpload DateGit commit
+ {{ module[0] }} + + {% if item.author %} + {{ item.author }} + {% else %} + N/A + {% endif %} + + {% if item.git_repo %} + {{ item.git_repo_type }} + {% else %} + N/A + {% endif %} + + {{ item.date }} + + {% if item.git_repo %} + {{ item.commit }} + {% endif %} +
+ + {% endfor%} + + {% if no_cat %} +

Verschiedenes

+ + + + + + + + + + + {% for item in no_cat %} + + + + + + + {% endfor %} + +
TitleRepoUpload DateGit commit
+ {{ item.title }} + + {% if item.author %} +
by {{ item.author }} + {% endif %} +
+ {% if item.git_repo %} + {{ item.git_repo_type }} + {% else %} + N/A + {% endif %} + + {{ item.date }} + + {% if item.git_repo %} + {{ item.commit }} + {% endif %} +
+ {% endif %} \ No newline at end of file