diff --git a/.gitignore b/.gitignore
index b756e26..b1100fa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,9 +19,8 @@ static/resources/DecimalJs*
static/resources/SortableJS
static/resources/Standalone
-# Secrets
+# Golang revamp
src/
bin/
app/
-.run/
*.tmpl
diff --git a/.run/app.py - Minify.run.xml b/.run/app.py - Minify.run.xml
new file mode 100644
index 0000000..a6b2b2a
--- /dev/null
+++ b/.run/app.py - Minify.run.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.run/compile-js-site.run.xml b/.run/compile-js-site.run.xml
new file mode 100644
index 0000000..f6e1040
--- /dev/null
+++ b/.run/compile-js-site.run.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.run/delete-minified-js.run.xml b/.run/delete-minified-js.run.xml
new file mode 100644
index 0000000..349a1c2
--- /dev/null
+++ b/.run/delete-minified-js.run.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.run/delete-pycache.run.xml b/.run/delete-pycache.run.xml
new file mode 100644
index 0000000..cd882e9
--- /dev/null
+++ b/.run/delete-pycache.run.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.run/go build np_web_main.run.xml b/.run/go build np_web_main.run.xml
new file mode 100644
index 0000000..92d1861
--- /dev/null
+++ b/.run/go build np_web_main.run.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.run/nodejs-setup.run.xml b/.run/nodejs-setup.run.xml
new file mode 100644
index 0000000..2086341
--- /dev/null
+++ b/.run/nodejs-setup.run.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.run/package-for-release.run.xml b/.run/package-for-release.run.xml
new file mode 100644
index 0000000..b2a2857
--- /dev/null
+++ b/.run/package-for-release.run.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app.py b/app.py
index 47b7699..789b69f 100644
--- a/app.py
+++ b/app.py
@@ -24,7 +24,7 @@ from website.renderers.lists import render_list_ul
from website.renderers.splide import render_splide
from website.renderers.standalone import get_standalone_common_headers
from website.sidebar import reload_sidebar_entries, get_sidebar_entries
-from website.sitemap import reload_sitemap_entries, get_sitemap_entries
+from website.sitemap import reload_sitemap_entries, get_sitemap_entries, get_sitemap_xml
try:
from rich import print
@@ -164,11 +164,15 @@ def route_robots_txt():
@app.route('/sitemap.txt')
-def route_sitemap():
- # FIXME: Add the domain !!!
+def route_sitemap_txt():
return Response("\n".join(get_sitemap_entries()), mimetype="")
+@app.route('/sitemap.xml')
+def route_sitemap_xml():
+ return Response(get_sitemap_xml(request.headers['Host']), mimetype="application/xml")
+
+
@app.route('/', defaults={'lang': None})
@app.route('/en/', defaults={'lang': "en"})
@app.route('/fr/', defaults={'lang': "fr"})
diff --git a/data/sitemap.yml b/data/sitemap.yml
index 5545a56..1eb0741 100644
--- a/data/sitemap.yml
+++ b/data/sitemap.yml
@@ -1,17 +1,63 @@
# Sitemap definition
-- "/"
-- "/about/"
-#- "/articles/"
-- "/contact/"
-- "/content/"
-- "/content/circuitpython-ebyte-e32/"
-- "/content/docker-mini-cctv-nvr/"
-- "/content/lscom-cli-dotnet/"
-- "/links/"
-- "/privacy/"
-- "/tools/"
-- "/tools/iban-generator/"
-- "/tools/excel-password-remover/"
-- "/tools/uuid-generator/"
-- "/tools/vat-calculator/"
+# changefreq: "monthly" is implied unless specified
+
+sitemap:
+ "/":
+ lastmod: "2025-03-30T00:00:00+01:00"
+ priority: "1"
+
+ "/contact/":
+ lastmod: "2025-03-01T07:40:00+01:00"
+ priority: "0.5"
+
+ "/content/":
+ lastmod: "2025-09-13T16:19:00+02:00"
+ priority: "0.2"
+
+ "/content/circuitpython-ebyte-e32/":
+ lastmod: "2025-03-30T14:52:00+02:00"
+ priority: "0.5"
+
+ "/content/docker-mini-cctv-nvr/":
+ lastmod: "2025-03-30T14:52:00+02:00"
+ priority: "0.3"
+
+ "/content/lscom-cli-dotnet/":
+ lastmod: "2025-09-13T16:19:00+02:00"
+ priority: "0.6"
+
+ "/links/":
+ lastmod: "2025-03-01T07:40:00+01:00"
+ priority: "0.6"
+
+ "/privacy/":
+ lastmod: "2025-03-30T00:00:00+01:00"
+ priority: "0.4"
+
+ "/tools/":
+ lastmod: "2025-09-13T16:19:00+02:00"
+ priority: "0.2"
+
+ "/tools/iban-generator/":
+ lastmod: "2025-08-28T21:23:00+02:00"
+ priority: "0.6"
+
+ "/tools/excel-password-remover/":
+ lastmod: "2025-09-13T16:19:00+02:00"
+ priority: "0.9"
+
+ "/tools/uuid-generator/":
+ lastmod: "2025-08-28T21:23:00+02:00"
+ priority: "0.3"
+
+ "/tools/vat-calculator/":
+ lastmod: "2025-09-18T00:15:00+02:00"
+ priority: "0.6"
+
+#"/about/":
+# lastmod: ""
+# priority: ""
+#"/articles/":
+# lastmod: ""
+# priority: ""
diff --git a/templates/base_www.jinja b/templates/base_www.jinja
index 9c3ae93..459b843 100644
--- a/templates/base_www.jinja
+++ b/templates/base_www.jinja
@@ -11,7 +11,8 @@
-
+
+
@@ -21,7 +22,6 @@
-
diff --git a/update.sh b/update.sh
new file mode 100644
index 0000000..07a89d4
--- /dev/null
+++ b/update.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+cd "$(dirname "$0")"
+
+EXCLUDE=("release.tar" "docker-compose.yml" "update.sh")
+
+for item in * .*; do
+ # Skip current and parent directory entries
+ [[ "$item" == "." || "$item" == ".." ]] && continue
+
+ delete=true
+
+ for pattern in "${EXCLUDE[@]}"; do
+ if [[ "$item" == $pattern ]]; then
+ delete=false
+ break
+ fi
+ done
+
+ if [ "$delete" = true ]; then
+ echo "Deleting '$item'"
+ rm -rf "$item"
+ fi
+done
+
+tar -xvf release.tar
+
+rm data/tools/ico-maker.yml
+rm data/tools/png-analyser.yml
+
+docker-compose up --build --force-recreate -d
diff --git a/website/sitemap.py b/website/sitemap.py
index 91d2cc1..5614c4e 100644
--- a/website/sitemap.py
+++ b/website/sitemap.py
@@ -1,28 +1,65 @@
+from dataclasses import dataclass
+
from .l10n.utils import ALLOWED_LANGS
import yaml
-__SITEMAP_ENTRIES: list[str] = list()
+
+@dataclass
+class SitemapEntry:
+ lastmod: str
+ priority: str
+ changefreq: str = "monthly"
+
+
+__SITEMAP_ENTRIES: dict[str, SitemapEntry] = dict()
+
+__XML_SITEMAP_CACHE = None
def reload_sitemap_entries(definition_file: str) -> None:
global __SITEMAP_ENTRIES
- __SITEMAP_ENTRIES = list()
+ __SITEMAP_ENTRIES = dict()
with open(definition_file, 'r') as f:
- raw_sitemap_entries = yaml.safe_load(f)
+ raw_sitemap_entries: dict = yaml.safe_load(f)["sitemap"]
for allowed_lang in [""] + ALLOWED_LANGS:
- for sitemap_entry in raw_sitemap_entries:
- __SITEMAP_ENTRIES.append(
- ("/" + str(allowed_lang) + "/" + str(sitemap_entry))
- .replace("//", "/")
- .replace("//", "/")
- )
- # __SITEMAP_ENTRIES.append(sitemap_entry)
- # for allowed_lang in ALLOWED_LANGS:
+ for sitemap_entry_path in raw_sitemap_entries:
+
+ entry = SitemapEntry(**raw_sitemap_entries[sitemap_entry_path])
+ if not(allowed_lang == ""):
+ entry.priority = "0.0"
+
+ __SITEMAP_ENTRIES[
+ ("/" + str(allowed_lang) + "/" + str(sitemap_entry_path))
+ .replace("//", "/")
+ .replace("//", "/")
+ ] = entry
def get_sitemap_entries() -> list[str]:
- return __SITEMAP_ENTRIES
+ return list(__SITEMAP_ENTRIES.keys())
+
+
+def get_sitemap_xml(domain) -> str:
+ global __XML_SITEMAP_CACHE
+
+ if __XML_SITEMAP_CACHE is None:
+ __XML_SITEMAP_CACHE = (
+ """\n""" +
+ "".join([
+ f"""
+
+ https://{domain}{k}
+ {v.lastmod}
+ {v.priority}
+ {v.changefreq}
+ """
+ for k, v in __SITEMAP_ENTRIES.items()
+ ]) +
+ "\n").replace(" 0.0\n ", "")
+
+ return __XML_SITEMAP_CACHE
+