From f17140e7d3854f409d0de828b8f83c5d5d720419 Mon Sep 17 00:00:00 2001 From: renaud gaudin Date: Fri, 19 Apr 2024 16:21:02 +0000 Subject: [PATCH] removed dashboard (moved to dedicated repo) --- .github/workflows/docker_dashboard.yaml | 34 --- dashboard/.gitignore | 6 - dashboard/Dockerfile | 72 ----- dashboard/README.md | 56 ---- dashboard/assets/close-down-orange.png | Bin 9916 -> 0 bytes dashboard/assets/dashboard-tailwind-src.css | 169 ----------- dashboard/assets/dashboard.js | 251 ---------------- dashboard/assets/favicon-dark.png | Bin 7380 -> 0 bytes dashboard/assets/favicon-light.png | Bin 6277 -> 0 bytes dashboard/assets/favicon.ico | Bin 24379 -> 0 bytes dashboard/assets/favicon.png | Bin 1916 -> 0 bytes dashboard/assets/favicon.svg | 19 -- dashboard/assets/hotspot-logo.png | Bin 13990 -> 0 bytes dashboard/assets/kiwix-bird-white.png | Bin 3510 -> 0 bytes dashboard/assets/kiwix-bird-white.svg | 40 --- dashboard/assets/open-down-orange.png | Bin 9736 -> 0 bytes dashboard/entrypoint.sh | 14 - dashboard/fallback.html | 7 - dashboard/gen-home.py | 219 -------------- dashboard/home.yaml | 5 - dashboard/lighttpd.conf | 5 - dashboard/refresh-zims.py | 165 ----------- dashboard/tailwind.config.js | 68 ----- dashboard/templates/base.html | 292 ------------------ dashboard/templates/download.html | 312 -------------------- dashboard/templates/home.html | 221 -------------- 26 files changed, 1955 deletions(-) delete mode 100644 .github/workflows/docker_dashboard.yaml delete mode 100644 dashboard/.gitignore delete mode 100644 dashboard/Dockerfile delete mode 100644 dashboard/README.md delete mode 100644 dashboard/assets/close-down-orange.png delete mode 100644 dashboard/assets/dashboard-tailwind-src.css delete mode 100644 dashboard/assets/dashboard.js delete mode 100644 dashboard/assets/favicon-dark.png delete mode 100644 dashboard/assets/favicon-light.png delete mode 100644 dashboard/assets/favicon.ico delete mode 100644 dashboard/assets/favicon.png delete mode 100644 dashboard/assets/favicon.svg delete mode 100644 dashboard/assets/hotspot-logo.png delete mode 100644 dashboard/assets/kiwix-bird-white.png delete mode 100644 dashboard/assets/kiwix-bird-white.svg delete mode 100644 dashboard/assets/open-down-orange.png delete mode 100755 dashboard/entrypoint.sh delete mode 100644 dashboard/fallback.html delete mode 100755 dashboard/gen-home.py delete mode 100644 dashboard/home.yaml delete mode 100644 dashboard/lighttpd.conf delete mode 100644 dashboard/refresh-zims.py delete mode 100644 dashboard/tailwind.config.js delete mode 100644 dashboard/templates/base.html delete mode 100644 dashboard/templates/download.html delete mode 100644 dashboard/templates/home.html diff --git a/.github/workflows/docker_dashboard.yaml b/.github/workflows/docker_dashboard.yaml deleted file mode 100644 index a201b74..0000000 --- a/.github/workflows/docker_dashboard.yaml +++ /dev/null @@ -1,34 +0,0 @@ -name: Publish dashboard Image - -on: - push: - branches: - - 'main' - paths: - - 'dashboard/*' - tags: - - 'dashboard-*' - -jobs: - dashboard: - name: Publish dashboard Image - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v3.4.0 - - name: Publish dashboard Image - uses: openzim/docker-publish-action@v10 - with: - image-name: offspot/dashboard - on-master: dev - build-args: - VERSION={tag} - tag-pattern: /^dashboard-([0-9.]+)$/ - restrict-to: offspot/container-images - platforms: | - linux/amd64 - linux/arm64 - context: dashboard - registries: ghcr.io - credentials: - GHCRIO_USERNAME=${{ secrets.GHCR_USERNAME }} - GHCRIO_TOKEN=${{ secrets.GHCR_TOKEN }} diff --git a/dashboard/.gitignore b/dashboard/.gitignore deleted file mode 100644 index 36d2079..0000000 --- a/dashboard/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -assets/fontawesome -/assets/dashboard.css -/*.yaml -/download -/download.html -/index.html diff --git a/dashboard/Dockerfile b/dashboard/Dockerfile deleted file mode 100644 index d9af489..0000000 --- a/dashboard/Dockerfile +++ /dev/null @@ -1,72 +0,0 @@ -FROM alpine:3.19 -LABEL org.opencontainers.image.source https://github.com/offspot/container-images - -RUN \ - apk add --no-cache curl dumb-init yaml python3 lighttpd \ - # FontAwesome font - && curl -L -O https://use.fontawesome.com/releases/v6.5.1/fontawesome-free-6.5.1-web.zip \ - && unzip -o fontawesome-free-6.5.1-web.zip \ - fontawesome-free-6.5.1-web/css/* \ - fontawesome-free-6.5.1-web/webfonts/* \ - -d /var/www/assets/ \ - && mv /var/www/assets/fontawesome-free-6.5.1-web /var/www/assets/fontawesome \ - && rm -f fontawesome-free-6.5.1-web.zip \ - # python dependencies - && python3 -m venv /usr/local/bin/gen-home_env \ - && /usr/local/bin/gen-home_env/bin/pip3 install --no-cache-dir -U pip \ - && /usr/local/bin/gen-home_env/bin/pip3 install \ - --no-cache-dir \ - Jinja2==3.1.2 PyYAML==6.0.1 humanfriendly==10.0 iso639-lang==2.2.3 libzim==3.4.0 \ - # install tailwind CSS cli - && curl -L -o /usr/local/bin/tailwindcss https://github.com/tailwindlabs/tailwindcss/releases/download/v3.4.3/tailwindcss-linux-arm64 \ - && chmod +x /usr/local/bin/tailwindcss \ - && apk del curl - -ENV FQDN "generic.hotspot" -ENV NAME "My Hotspot" -# path in which to find code (templates) -ENV SRC_DIR "/src" -# path to packages YAML file -ENV PACKAGES_PATH "/src/home.yaml" -# path to write home HTML and assets file -ENV DEST_DIR "/var/www" -# folder storing ZIM files. unless DONT_UPDATE_PACKAGES, ZimPackages not in the folder -# will be removed (disabled) from packages.yaml -# discovered ZIM (not in YAML) will be added -ENV ZIM_DIR "/data/zims" -# set to skip packages.yaml update on start (reading ZIM_PATH folder) -ENV DONT_UPDATE_PACKAGES "" - -# templates to write ZIM Package links to reader and ZIM downloads. -# Available patterns (to be replaced): `{fqdn}`, `{zim_name}`, `{zim_filename}` -ENV KIWIX_READER_LINK_TPL "//kiwix.{fqdn}/viewer#{zim_name}" -ENV KIWIX_DOWNLOAD_LINK_TPL "//zim-download.{fqdn}/{zim_filename}" - -# WARN: this break apk but saves a lot of space -# it's OK on prod but comment it during dev if you need packages -RUN apk del apk-tools ca-certificates-bundle - -COPY gen-home.py refresh-zims.py tailwind.config.js /src/ -COPY templates /src/templates -COPY assets /var/www/assets -COPY fallback.html /var/www/fallback.html -COPY home.yaml /src/ -COPY lighttpd.conf /etc/lighttpd/ -COPY entrypoint.sh /usr/local/bin/ - -WORKDIR /src - -RUN \ - # gen final CSS - tailwindcss -i /var/www/assets/dashboard-tailwind-src.css -o /var/www/assets/dashboard.css \ - && rm -f /var/www/assets/dashboard-tailwind-src.css \ - && rm -f /usr/local/bin/tailwindcss \ - # store python bytecode in image - && /usr/local/bin/gen-home_env/bin/python3 -m compileall /src/gen-home.py /src/refresh-zims.py && mv /src/__pycache__/*.pyc /usr/local/bin/gen-home_env/lib/ - -WORKDIR /var/www - -HEALTHCHECK --interval=10s --timeout=2s CMD ["/bin/ls", "/tmp/.ready"] -ENTRYPOINT ["/usr/bin/dumb-init", "--", "/usr/local/bin/entrypoint.sh"] -CMD ["lighttpd", "-D", "-f", "/etc/lighttpd/lighttpd.conf"] - diff --git a/dashboard/README.md b/dashboard/README.md deleted file mode 100644 index f168efe..0000000 --- a/dashboard/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# dashboard - -Caddy-based file server serving static file with home-page generated on startup - -## Configuration - -Configuration is done via a YAML file describing the contents that should be exposed. - -| Variable | Usage | -| ---------------------- | ------------------------------------------------------------------------------------------ | -| `metadata` | A dict containing hompage-level metadata | -| **`metadata.name`** | Hotspot name | -| **`metadata.fqdn`** | Domain name of the hotspot. Used to build links | -| `packages` | A list of `package` dicts describing each content package | -| **`package.title`** | Main name of content | -| `package.kind` | Kind of package, to adjust display and filters | -| `package.description` | Short description of the content | -| `package.languages` | List of ISO-639-3 language code the content relates to | -| `package.tags` | List of Tag strings helping users guess what to expect from content | -| `package.icon` | Base64 encoded 48x48px PNG image | -| **`package.url`** | URL to access the content on the hotspot. Accepts some variables | -| `package.download.url` | URL to download the content from (for hotspot users) | -| `package.download.size`| Size of the download file to download. Informative only | - -Main goal of this tool being linking to content, `package.url` accepts different helpers which are rewritten automatically: - -- `{fqdn}` is replaced by the content of `metadata.fqdn`. -- `{service-fqdn}` is replaced by the service's subdomain. Ex: `{kiwix-fqdn}` may become `kiwix.myname.hotspot`. -- URLs not starting with a scheme (`urllib.parse.urlparse`) will be prefixed with `//`. -- `//` is the only scheme-less prefix allowed. -- Use `http://` or `https://` to enforce protocol. -- You can use external links (at your own risk of it not working) -- Other protocols alike. - -### Sample - -```yaml ---- -metadata: - name: My Hotspot - fqdn: renaud.Hotspot -packages: - kind: zim - title: ArchWiki - description: Arch Linux documentation - languages: - - eng - tags: - - archlinux - url: //{kiwix-fqdn}/archlinux_en_all_maxi_2022-04 - download: - url: //{zimdl-fqdn}/archlinux_en_all_maxi_2022-04.zim - size: 32M -``` - -In addition, the `DEBUG` environ can be set to enable Caddy debug output. \ No newline at end of file diff --git a/dashboard/assets/close-down-orange.png b/dashboard/assets/close-down-orange.png deleted file mode 100644 index f8aae176b8c5bfcf27eb19af2b957d4c945e6ef3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9916 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 diff --git a/dashboard/assets/dashboard-tailwind-src.css b/dashboard/assets/dashboard-tailwind-src.css deleted file mode 100644 index 3ef9fea..0000000 --- a/dashboard/assets/dashboard-tailwind-src.css +++ /dev/null @@ -1,169 +0,0 @@ -/* Tailwind source file in dashboard-tailwind-src.css - -To be compiled using `npx tailwindcss` -eg: npx tailwindcss -i ./assets/dashboard-tailwind-src.css -o ./assets/dashboard.css -*/ -@tailwind base; -@tailwind components; -@tailwind utilities; - -:root { - --rounded-btn: 0.5rem; -} - -/*START: daisyui select (adapted; need to reimpl in tw) */ -select { - font-family: inherit; - font-feature-settings: inherit; - font-variation-settings: inherit; - font-size: 100%; - font-weight: inherit; - line-height: inherit; - color: inherit; - margin: 0; - padding: 0; - padding-right: 0px; - padding-left: 0px; - - text-transform: none; -} - -.select { - display: inline-flex; - cursor: pointer; - -webkit-user-select: none; - -moz-user-select: none; - user-select: none; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - height: 3rem; - min-height: 3rem; - padding-left: 1rem; - padding-right: 2.5rem; - font-size: 0.875rem; - line-height: 1.25rem; - line-height: 2; - border-radius: var(--rounded-btn, 0.5rem); - border-width: 1px; - border-color: transparent; - --tw-bg-opacity: 1; - background-color: oklch(1 0 0); - background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%); - background-position: calc(100% - 20px) calc(1px + 50%), calc(100% - 16.1px) calc(1px + 50%); - background-size: 4px 4px, 4px 4px; - background-repeat: no-repeat; -} - -[dir="rtl"] .select { - background-position: - calc(0% + 12px) calc(1px + 50%), - calc(0% + 16px) calc(1px + 50%); -} - - -.max-w-xs { - max-width: 20rem; -} -.select-sm { - height: 2rem; - min-height: 2rem; - padding-left: 0.75rem; - padding-right: 2rem; - font-size: 0.875rem; - line-height: 2rem; -} -.select-bordered { - border-color: var(oklch(var(--bc)/0.2)); -} - -/*END: daisyui select */ - -@layer components { - .kiwix-home-btn { - @apply hover:bg-kwordergrey-600 hover:text-white bg-kwordergrey-500 text-kwwhite; - } - .kiwix-home-btn-active { - @apply border-white text-kwordergrey-500 bg-white drop-shadow-md hover:text-kwordergrey-500 hover:bg-white hover:cursor-default; - } - - .kiwix-download-btn { - @apply hover:bg-kworange-800 hover:text-white bg-kworange-500 text-kwwhite; - } - .kiwix-download-btn-active { - @apply border-white text-kworange-100 bg-white drop-shadow-md hover:text-kworange-100 hover:bg-white hover:cursor-default; - } - - .kiwix-order-dir-btn { - @apply mr-1 last:mr-0 cursor-pointer p-0 text-[0.9em] leading-[1.1em] h-[1.7em] w-[1.7em] rounded-md drop-shadow-none; - } - - .kiwix-sort-btn { - @apply mr-0 last:mr-0 cursor-pointer box-border px-[2em] py-0 text-[0.9em] leading-[1.1em] h-[2em] rounded-2xl min-w-[3em] md:min-w-[6em] relative z-40 pr-[1.8em] drop-shadow-none; - } - .kiwix-sort-btn-active { - @apply z-50 pr-[2em] hover:cursor-default; - } - - .kiwix-download-filter-label { - @apply text-white; - } - - .kiwix-reader-platform-btn { - @apply cursor-pointer border-white border bg-kwordergrey-500 md:bg-kwordergrey-500 md:bg-kwreaderbggrey text-white text-sm rounded-xl px-3 py-1 sm:me-1 lg:me-3 last:me-0 hover:bg-kwordergrey-600 md:hover:bg-kwreaderhover hover:text-white hover:border-white; - } - - .kiwix-reader-platform-btn-active { - @apply text-kwreaderbggrey bg-white drop-shadow-md hover:text-kwreaderbggrey hover:bg-white hover:border-white hover:cursor-default; - } - - .kiwix-home-innerglow { - box-shadow: inset 0 0 1em #a6b2bd; - } - - .kiwix-download-innerglow { - box-shadow: inset 0 0 1em #c60; - } - - .kiwix-mini-download-open-outerglow { - box-shadow: 0 0 1em 0.5em #c60; - } - - .kiwix-mini-download-close-uppershadow { - box-shadow: #f39325 0 -0.4rem 0.9rem 0; - } - - .kiwix-mini-download-open-downshadow { - box-shadow: inset 0 0.3em 0.3em #c60; - } - - .bg-center-top { - background-position-x: center; - background-position-y: top; - } - - .content-max-w { - @apply sm:max-w-screen-sm md:max-w-screen-md lg:max-w-screen-md xl:max-w-screen-lg 2xl:max-w-screen-xl; - } - - .content-w { - @apply sm:w-[640px] md:w-[768px] lg:w-[1024px] xl:w-[1280px] 2xl:w-[1536px] w-[90%] mx-auto; - } - - .mini-height-card-90 { - height: calc((90vw /8.79) * 4.69); - } - .mini-height-card-60 { - height: calc((60vw /8.79) * 4.69); - } - .inherit { - position: inherit; - } - .hide-after-2:nth-child(3), .hide-after-2:nth-child(4) { - @apply hidden; - } -} - -body { - font-family: Inter, Roboto, 'Helvetica Neue', 'Arial Nova', 'Nimbus Sans', Arial, sans-serif; -} diff --git a/dashboard/assets/dashboard.js b/dashboard/assets/dashboard.js deleted file mode 100644 index e639f87..0000000 --- a/dashboard/assets/dashboard.js +++ /dev/null @@ -1,251 +0,0 @@ -// matches polyfill -this.Element && function(ElementPrototype) { - ElementPrototype.matches = ElementPrototype.matches || - ElementPrototype.matchesSelector || - ElementPrototype.webkitMatchesSelector || - ElementPrototype.msMatchesSelector || - function(selector) { - var node = this, nodes = (node.parentNode || node.document).querySelectorAll(selector), i = -1; - while (nodes[++i] && nodes[i] != node); - return !!nodes[i]; - } -}(Element.prototype); -// closest polyfill -this.Element && function(ElementPrototype) { - ElementPrototype.closest = ElementPrototype.closest || - function(selector) { - var el = this; - while (el.matches && !el.matches(selector)) el = el.parentNode; - return el.matches ? el : null; - } -}(Element.prototype); - -// helper for enabling IE 8 event bindings -function addEvent(el, type, handler) { - if (el.attachEvent) el.attachEvent('on'+type, handler); else el.addEventListener(type, handler); -} - -function hasClass(el, className) { - return el.classList ? el.classList.contains(className) : new RegExp('\\b'+ className+'\\b').test(el.className); -} - -function addClass(el, className) { - if (el.classList) el.classList.add(className); - else if (!hasClass(el, className)) el.className += ' ' + className; -} - -function removeClass(el, className) { - if (el.classList) el.classList.remove(className); - else el.className = el.className.replace(new RegExp('\\b'+ className+'\\b', 'g'), ''); -} - -function toggleClass(el, className) { - if (hasClass(el, className)) - removeClass(el, className); - else - addClass(el, className); -} - -// live binding helper using matchesSelector -function live(selector, event, callback, context) { - addEvent(context || document, event, function(e) { - var found, el = e.target || e.srcElement; - while (el && el.matches && el !== context && !(found = el.matches(selector))) el = el.parentElement; - if (found) callback.call(undefined, el, e); - }); -} - -function getCookie(name) { - var v = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)'); - return v ? v[2] : null; -} - -function setCookie(name, value, deleteAfter) { - document.cookie = name + '=' + value + ';path=/;max-age=' + deleteAfter; -} - -function deleteCookie(name) { setCookie(name, '', -1); } - -const Filtering = class { - order_by = 'name'; - order_dir = 'desc'; - only_lang = ''; - only_category = ''; - - constructor(order_by, order_dir, only_lang, only_category) { - this.order_by = order_by || this.order_by; - this.order_dir = order_dir || this.order_dir; - this.only_lang = only_lang || this.only_lang; - this.only_category = only_category || this.only_category; - } - - toString() { - return `order_by=${this.order_by}, order_dir=${this.order_dir}, only_lang=${this.only_lang}, only_category=${this.only_category}` - } - - sortByNameAsc(a, b) { - a = a.getAttribute('data-name').toLowerCase(); - b = b.getAttribute('data-name').toLowerCase(); - if (a == b) - return 0; - return a > b ? -1 : 1; - } - - sortByNameDesc(a, b) { - a = a.getAttribute('data-name').toLowerCase(); - b = b.getAttribute('data-name').toLowerCase(); - if (a == b) - return 0; - return a < b ? -1 : 1; - } - - sortBySizeAsc(a, b) { - a = parseInt(a.getAttribute('data-size')); - b = parseInt(b.getAttribute('data-size')); - if (a == b) - return 0; - return a < b ? -1 : 1; - } - - sortBySizeDesc(a, b) { - a = parseInt(a.getAttribute('data-size')); - b = parseInt(b.getAttribute('data-size')); - if (a == b) - return 0; - return a > b ? -1 : 1; - } - - sortByDOMOrder(a, b) { - return 0; - } - - getSortFunction() { - if (this.order_by == 'name') - return (this.order_dir == 'asc') ? this.sortByNameAsc : this.sortByNameDesc; - if (this.order_by == 'size') - return (this.order_dir == 'asc') ? this.sortBySizeAsc : this.sortBySizeDesc; - return this.sortByDOMOrder; - } - - render(withSorting) { - const elems = document.getElementById('entries').getElementsByClassName('hotspot-entry'); - for (var i=0; i0XFw$@{pYU-7Zq~)xd&Ig$2F1qvp9usuCnHY;5*@<*PX!(d^go#x z{U*=~0L`-wdu$FT49pCT#(jBJAkCq%#lGQE{@W@K(WbHbNAV9+`&9BDGS5hr>g67y zO<_9@`<13XI?QO#Pdndz*WeJ6iTIZIzNI8@u=5s9Hu*=gDX@ig|2JQCht?t0o9gT9 z9YouwzurFR?x>@H1YHq)>jybKLelAR76pNsccWm!tPW2UdL~;@23CGu=w6rZj+LSApsM1?fYESb zM0v^l4z;99PI{}lews)c1B?q!z!1dCy=7XIfBU_7f2KS>{~Ot>4srU499MX~as9>4 zy$z)tmrK~)UXhtd_D)!J1XjFBWx2G^TTZByh>4=gz^&=_#>`4qkMwq#phwailcR~om{)3EmWaR@Ng zgO(4pn7zvsl^=@d9E%4CNLyLtF%jU{95Rb?sZo&3Y^dF(i2)Ob<_mkp6)kP?jL@1< zdL!yO77xt->Xz*6W6H438sLb4F_mUa{D0a?YB&AgR7v4&#c^3w9Nt46iw1LQqP+6k zkvfEnZokTCF1Pml4H!Ju?U8B$?M#`Qx`6ZP6%u?^7C975v%inO{F}@lOUtlEuS%i8 zUeEbw0$QdA%#`}UQPKf>NkFR4Z`>*@Q=#|tcV?pe3LBNxoaPiG< zV6xT{aa{%tEOdoEhXwccqF#IGi#vx

5iLCuk)(rc+PsfM}lRRWuqXY+H#=A*oV~ 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 diff --git a/dashboard/assets/favicon-light.png b/dashboard/assets/favicon-light.png deleted file mode 100644 index dccc1a84131415ecef4601a214326c508bf67c89..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6277 zcmd5=`9G9h*gvz_#xVA!FqFn5WuhWt26+l$N{R}DP}#F*8)Sr%C`-b$&?0L+mWZ)c zqKJ}g!%&ociNTn8Z_hvQ{`kK4FXx==I@fZ}`P|?0Jy#;x>X-;>8wvm*Vs`xKDFEP5 z7Y+pZp=LSs>pIlP2b$Ui+W5K$hB#k!14b8pUEGw-yq!JVPPsW>4D)YuI|6{5n%PmK z)1m#-L*-W$-e-f6!oU~>#eKCW0sZE^k;2O6C9YM=d#` zg(L{sCK)-)(3^$jKb1#nG;8?jdY|PbEUv`O{m}BKL2bboO1j&GL@zbd$A2qfb zqN6XM>WZ`wk-1iDi6X(kk7wt#7o)vDb$FTt1P+KcRUW^@3-b41WE zNxQvw)7ulPJBX`u*ca-oO9rXQ-k!Xvk$J_*{!h6sj8l;1HS2XJf$eO{B~2*=9;7ZC z?WfC;VALm=Bv>o7AHin}uJb(1usB=v1v!)y7!2w*Uq7_ic)+`J8{1GfQH+nY;L^>k zWXD|fI<VR{2(+_|Pi<*~r^`?a5#1K00h?AkljHas@xg+#ja7YezKM(nDWCX>R8Fyt zN|}}vit1{I+|B{-#!c0chiI&*6)>n-qPdys&V@E+Y++-0I!bC9(*^5`ljMLxS4joc zWk*K@r`T@4qXieFpFHUQqs6v*W;)FdUM;Pelz)oF>+l07D#X|}Wg7F=1)8vyVBV_( zO9FIs4#l2630KZzg(!K=Bk#Xc-sNee~l?__L6a|EdN z%zXo!I>p6gRtWjkw#^k$(y?G}ebuklj9?|kQ$qEr+8GNde_qe8sf6`?!381C=z+1* z2?Igg(hKciS|u1JV>8EpRFi^f%Y;bOTvX;=Dj(l$iH16vPTP?Y={}6HO`RCgr-R$(L z9Io^QOXN)|q{i6FjfS9(Z2NHw>#-T|eVak&XUY)n=xQOZCov z8hoU>JDRp@%Y-6dwQ%kAg`#t<3`tX%LA79&)4>OuX-qj3)vfHyZ6A-7J#Ffdl* z_w(I9a`@y*8bdYzR(VCaO5yaah&03Lm6taiPKEP-yw!Sl-=(Qdw|8#yQ3n(rp{m+1 ze$P`|;k)^7v0G%(%b=G%Blip@U3R!NknH^r{_^b@~8dvdP($(6v)GdcDj zs|m918-z)T#_ST3c>2q0XxVYIvSHs!%p~f@qeBAy(>j|WE1y(Rr?S%0>l`ElZ%jA5!-<=UQ3a@i5(2MVEB{mrNM*qQwtf_+e#(Lh_w zF_!WD&+FW#SK>)0!=m=Ul|FuFTTLA_q@Ngwgs=F9nNTK#-&ye%e5Z>HHb6Xe2PMDq z&ba0R0tGwS<@xOE(8bb8g&)G>bkTZG zik2_G2Kr2|zW$!h?aC$#IVO7*CkFNpCuUgX)gJcjl%*gujAReL@7ta5Y-I68zf7JQ z<3k@_H}(@XziuL~=t8Z1=x|H)0e@#a^-j%YRt_%jQ28N+u=N(PiyrqRcvZh~aJi+W zX`&5u$c2ECkQC;sOBJdS)Vu!}4^Cg+?3ooXzdvp#^WpC5;f=?;O9c@Ur}p zgW+8p#7`+ARp~S?_ibxi3HCrx_E){Lbb7apQ=(;Ie-#4ukY87FNUYhc*(OLJZlF9bt% zO5%DrVEy&o@RZt7Yw`KAW@)cw#3WP0k}>`$FRft*V=5BVlo^#xj5}Qu@A|z>7+^jg z+vOvspt_cM4*8&_6I2|q5IVVd7I_K6T^z1OqP`uMJnm#HPXCD^>`NvL?TUH4i+Ajp z()?1Q!%fC44abd4$s9)O#=`INtKE-x^4?oM z7i8n4L045UEAQVIn`$9SJ~gkw0G|k$+NlCR z+ol!qmP{wy>C=mIwSr|m4GQNr941!4pi)5ct-Wu6xe4rhaUYL&Od!HEnk%f6Zip1 zwJ>A4l{Pn4>L0(NB$A@iIIBwIChnn6X?|L-HeXR3oa}ZeW7S5>&L(!EM}0EF4LO>& z1L`|)Ov-@lt^-10^#MXrLfY;?!6M3IgIwMWw`9u}G zqt~jw1N!6cm9c>%3+*&_+GDQ_@KM^Ai*54uB-dg;o+=0@2FHvIgLXJy1(ICoRy{N> zP$pEBAXto!7X>}G2?M>%K{7DAAY+HjK?Z@WX%Qt4&Qlt^ON1mqe_+qEw&Z*vLpU@E z?v8f6#QrB%cy(Z^suwfKPe+h%^gz^2HzVi|zpj-Xj8ypT+L3ovhonfySi568MVb%T z!Lw+6e{PqqZVr=yVp2}xn8cV<+%A|R;P-fp?W$tu!kzfHLy_fyM`& zH>HXKgCsLz)Wi3Q4*`Fr`4Dxx$wNRte~wG?aaoMsR=10wo&nzN{Jb(&yXhp4Qr7l2 zQ;w<~$-!~mb)|rU^+UZDxSsSvu~Fj+~V*XQG%KioC|YuN?kJOLBf3C0o2E8HviK*07}Y(Ndq2^3D4 zLd)GUQB0=1!VRn*pM~p($~)Yos22ZEWYS_X32k`Amv-GRb!dIsQu6u9Y6 z!(uNGuTd2vFSuTKJ)7&DKq)Z+3FXMH1}Bk5RreyzZVg_%JeN{w!S94@zhX1*P;G$a zQ>3=_Pr`4m1SGd{HxBICl`q=3^i?FQDhW0OQ`SHGTv&PWcBoy?^H}e@F8jr9_eag> zDOpak2w@gF*LwZ;{@%miqWsXadEC}#d3pzq7J4Yo{JG zWH2?}o>cX`GxWaZhasj+u*x^4I^oT&c#B)7a`AAz99xYzhgOA>;M?Zhu3b~N-=AkX z9p?nnujZR`>4G107UGOaivp(977Pm3hLwUz5b;RWXfpCW-KW9U9w1Xls92e9tt=goxW&Nt4j$@LjZ$nm1F25iYSMhDdo&LA2bn)b=>K>s$ z#MW51LjX0!e;o4K7go%Ci7oshk_x3zW}^{#y39t0g7!uIr~I89egsb;TC`#10>s65 zId$JL7@Gu6iev_-@nz%XsIE9Wl9M@?u}{XCeJe^y!tcVSM|1DSV?O2pTTUew^-Ui;rC40 z`Hyc!lBgT34nN~Fri}6xzT;fN=#G)DA5BdJ<6xI=!)4)k)o47W(oedMiLrSdLAld# zAdsA*Hyzy6S71-PS+ZSBa{YaZcnVJ`b4lIgOd*8&r_mivz5~%kxL(UaIVHJbd-M63 z*&*D}fM+w}f2mo`pTCWUo#=m=nBLo2tX9m_vE+2GFTF|3>9vL`J{R+*r*KM7nI6a3 z%t0BrW>4q6M*z^IJ(ibnpL0ToT1pLCi*Omo)Cqv9C~{|cE_v!S`m~`8m~^jo;H{L-xF^fz1sK;Yof#uB+~ib|kSH21Lrt#HcQ<+4DtBY0>%_`(VIaTiES2 zhbS{KTE#pGK>EL_9OmJ3cH)3Bp5E}JR1lCBWs?9ZR9wKZ47^!uu z#K9T>-5Tg$!X|_p>bin#`omAa^lM-CyA02z?NybPD@w@PS={L3{e(DiA+)|_AP=R*M~d-5LtdcTPhKVs^3#=hPvrw`7c_(VWbDSIy>hMmN;Am42-{sac=6 zur59^cOH;>ltG6E_?~-5hwQ)Z(*##-4=$XmSQ#dc&)S%PW6}-z+z|JoW7rB_SL1$9BZ7i+ zw5yo4>@_wFZ?E`K?+{x{cN7D-Of&PF=eU4OUprb0E3bYYQ3vKneHdCNJc^m+^`I<4 z*HvjM2j0I4$Yd42T!{wDDB#y(Ovz63@=4@RCLhqdeGK!pCSR_hTdRa z0rT%dQ+Z$Y-DT%(O7ifmi$-E&OLw1*C5CU5w3X&mUuL;U<}6SA`;d}VrFV}w8WSa`#*cjq=^6k diff --git a/dashboard/assets/favicon.ico b/dashboard/assets/favicon.ico deleted file mode 100644 index 875b403b2542347d5ea3cba7d3dcad8a552f06b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24379 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 b&G=?N9edgL_TC2gHGsx$ZMA#5OauN0+qQ`= diff --git a/dashboard/assets/favicon.png b/dashboard/assets/favicon.png deleted file mode 100644 index 08283c76fdb9699ab534099d9bf5ef23e919319b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1916 zcmV-?2ZQ*DP)yL?i(qJ3e=_b5>2Q^L~LwPDyd4eViB>Lm|AG7h!4e$wh2|M6&C{9 z7^qu(@u6-|V^ZAk!CDo!Y6YVxaYF_7K2XHvE^}ue=KQ`_X6DSFIm@@4b3q^w2m}Iw zKp+qZ1OkCTAP@)y0)ar_o@V&dgK&m0iZ~LOMlv&*Nix$&AdXQCC7d4k)66cC_|cna zQplo!1DxV2cX`YUH};r&T;&u8DCB!mh$aNT#wLqD4wCqpA};aJtsGM9A(tp-71MFx zZ*5^Z62o`wrkrPrWpQTDsbCM8#L&@N!Zc?v-|#z?n#khJD%s7q493^&(zGUu<^07{ z-K2Tdo^p~EjHIzbciR zjZU0;yGbg|mB{1ZK%*6>-VWf9`|T{CTGLPbE|)1~H-)Sriwx43!)#_Vhcq(CVhsiC zrj$$E(X@+Kv%vfBD3tvg1tt!&iFD#|&>cUTcx*`%{OHbL;+fAz4rvrb*-xl9@+5LY z)yLQJH@`BQp>$9@Dt2Hfv)IH*YE>SOrb%l+8`i4$*njzrWWtmUg)WAGP?9O+vWl%; zOB>H!t3;)Tm9df-9iql<8O2J@sMP8b_gyWPYbrdXoV7&LN>}%}6(h-^T!q$OW2~!( zr1D7N%^$Omsap9ul6=L_*y|yY>eok2e|9SD zRG9>sDn=eeCRY@_)6RzRvnvM`+~^7mOq!SKNV+1C4$`$Q9bBSd?XZYWrcOk4B2$4c zS%M#YE_*0jPp~BtnZc}+J^f6BbFwZhCel*b-bjjNuI5OSu~L|gkL4-_e3&I;m6r;E zUgkr$S)^k*;~lnonWGH^7$Di7sU*qr#W+cl;{lf$P=8T>{*iFOKKjxa=*wOSZ+odh z9)NHzdZ?UOs)0vtT!GFK4;3gEdH2nW!Z`0{SRSv5AKr%%OeT#V$z?0M*h3LT>|qyM z$>j&WW-=q_Lt71={)w9*`vPIkF6rlD%0K4(&tDkveJxeQlz z%^t=vr_Vb_Ki9pp?5#iFL4Zod4kKAivBHq)4gO#W(JB=q1hB)&%+=R@4(#>N(@GVJ zM>>%}fkM~uZ4a=31QpzzW~_MazGpn=%6f6)<-nY-IE?iXo4Kx8KH@r?`B-siE}bX; z-|qyyrCiXSbat?wD20o%g`CnQvvrDvyrZbCBUs0F=F?uUY4klda7)+p-z_%qzBSeu z4hkjCPHI~%g>ti`deM)3m9tgei?q@8ByB7KEaA2(vh81+DXNXE$ET2-&LGs98Dx--Ylwg7gBA8Gj z7|m2N$m1a8Ds9kv#t?l3N>?n*Y4VuPAc>*WwhSVPd`>GCYQA3MkK6`6;V=tv$lM6f z0tX8@{4#puz0K7tZ6c>U_%hi<&{Xl$n-W2`tjfe{`sg(ZC3-oGmXe~f`xrn9rCv?} ziF(dsiIVFjjxtH3?b^Of;;7_W6kX*3m?9zabCDSu?`8L8hKH1AU6g2w5o_rLw~@nI zvQ;P>mqG`!-Tt#`NHEG9o8a;+j$;hdwI#z`BmrOW(AdaOJolY!Q(10+2i=C{PPV+< zC*J6IP~01n{tW|TFcaU{V^XcZlj@9E?!9c%2?iS4mVqzRo-epdtXYDt!ziMP3UWU1N8?UZqw8fv&r8QV#r zn-Hc>oNO0md6oPmM4IFwFMGu}N7D=}k`&8XWLJ5XNsb0Cv!guIy$YC4x0^g6Ue++) zQsXEaE8%@bQGuQ0=`W*_vG(olC5@LXS!us4yU63iahZpY`q)FDo-z+^x@V4>L+y!_ zom-Ezhd{Bi1&XzYK;vW!G|nCZMadQ@${qssmARjzR=@HUV`=GT`>;DZPfNS3gz{wx zly9Gvbc`&4V(cSOGZ|+VmDuMOe(JuVXI_@@#$Yp6c_q*)Y)30eM~u|jUY$>6Gzozc zCE9D?$&3cmnjDYvO6KmvOJ0000 - - - - - - diff --git a/dashboard/assets/hotspot-logo.png b/dashboard/assets/hotspot-logo.png deleted file mode 100644 index 78ac7a3d79b31c53db1494e6c0119884162fab43..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13990 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 F{{_tv&`tmV diff --git a/dashboard/assets/kiwix-bird-white.png b/dashboard/assets/kiwix-bird-white.png deleted file mode 100644 index 02e65f54f0bfe71d7e74248a86d0d3f8b3b282c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3510 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 - - - - - - diff --git a/dashboard/assets/open-down-orange.png b/dashboard/assets/open-down-orange.png deleted file mode 100644 index 532f6acb5cdd46f69c8cd85ecb530651fcaf3ea8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9736 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 Kpz|)@3jZI2oji*G diff --git a/dashboard/entrypoint.sh b/dashboard/entrypoint.sh deleted file mode 100755 index 93c904f..0000000 --- a/dashboard/entrypoint.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh -set -e - -VENV=/usr/local/bin/gen-home_env - -# refresh ZIM packages collection (maybe) -$VENV/bin/python3 $VENV/lib/refresh-zims.cpython-311.pyc - -# generate homepage from collection -$VENV/bin/python3 $VENV/lib/gen-home.cpython-311.pyc - -touch /tmp/.ready - -exec "$@" diff --git a/dashboard/fallback.html b/dashboard/fallback.html deleted file mode 100644 index 60b7e56..0000000 --- a/dashboard/fallback.html +++ /dev/null @@ -1,7 +0,0 @@ - - -Error - -

Error!

-

Homepage was not generated. Try restarting hotspot.

- diff --git a/dashboard/gen-home.py b/dashboard/gen-home.py deleted file mode 100755 index a38675a..0000000 --- a/dashboard/gen-home.py +++ /dev/null @@ -1,219 +0,0 @@ -#!/usr/bin/env python3 - -""" gen-home: generate static home page from Packages YAML - - - Reads Packages YAML from `PACKAGES_PATH` - - Prepares an HTML output with templates defined in `SRC_DIR`/templates - - Writes and index.html in `DEST_DIR` - - Optionally (`DEBUG`) outputs index to stdout as well - - Dependencies: - - PyYAML - - Jinja2 - - humanfriendly -""" - -import os -import pathlib -import re -import traceback -import urllib.parse -from collections.abc import Iterable - -import humanfriendly -import iso639 -from jinja2 import Environment, FileSystemLoader, select_autoescape -import yaml - -try: - from yaml import CSafeLoader as SafeLoader -except ImportError: - # we don't NEED cython ext but it's faster so use it if avail. - from yaml import SafeLoader - - -src_dir = pathlib.Path(os.getenv("SRC_DIR", "/src")).expanduser().resolve() -packages_path = ( - pathlib.Path(os.getenv("PACKAGES_PATH", "home.yaml")).expanduser().resolve() -) -dest_dir = pathlib.Path(os.getenv("DEST_DIR", "/var/www")).expanduser().resolve() -templates_dir = src_dir.joinpath("templates") -env = Environment( - loader=FileSystemLoader(templates_dir), autoescape=select_autoescape() -) - - -def format_fsize(size: str | int) -> str: - one_gib = 2**30 - one_mib = 2**20 - hundred_mib = one_gib / 10 - - def round_to(size: int, scale: int) -> int: - return (size // scale) * scale - - if not str(size).isdigit(): - size = humanfriendly.parse_size(str(size)) - size = int(size) - - if size > one_gib and size >= 100 * one_gib: - size = round_to(size, one_gib) - elif size > one_gib: - size = size = round_to(size, hundred_mib) - else: - size = round_to(size, one_mib) - try: - return humanfriendly.format_size( - int(size), keep_width=False, binary=True - ).replace("iB", "B") - except Exception: - return str(size) - - -env.filters["fsize"] = format_fsize - - -def normalize(url: str) -> str: - if not url.strip(): - return "" - uri = urllib.parse.urlparse(url) - if not uri.scheme and not url.startswith("//"): - url = f"//{url}" - - url = re.sub(r"{([a-z]+)-fqdn}", r"\1.{fqdn}", url) - url = url.replace("{fqdn}", Conf.fqdn) - return url - - -class Conf: - debug: bool = bool(os.getenv("DEBUG", False)) - fqdn: str = "" - name: str = "" - footer_note: str = "" - - @classmethod - def from_doc(cls, document): - for key in ("name", "fqdn", "footer_note"): - setattr(cls, key, document.get(key, "--")) - - @classmethod - def to_dict(cls): - return { - key: getattr(cls, key) for key in ("debug", "fqdn", "name", "footer_note") - } - - -class Link(dict): - MANDATORY_FIELDS = ["name", "url"] - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self["url"] = normalize(self.get("url", "")) - - -class Reader(dict): - MANDATORY_FIELDS = ["platform", "url", "size"] - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self["url"] = normalize(self.get("url", "")) - - @property - def name(self) -> str: - return { - "windows": "Windows", - "android": "Android", - "macos": "macOS", - "linux": "Linux", - }.get(self["platform"].lower(), self["platform"]) - - @property - def icon(self) -> str: - return { - "windows": "windows", - "android": "android", - "macos": "apple", - "linux": "linux", - }.get(self["platform"].lower(), "robot") - - -class Package(dict): - MANDATORY_FIELDS = ["title", "url"] - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self["url"] = normalize(self.get("url", "")) - try: - self["download"]["url"] = normalize(self["download"]["url"]) - except KeyError: - ... - - @property - def tags(self) -> list[str]: - return [tag for tag in self.get("tags", []) if tag and not tag.startswith("_")] - - @property - def private_tags(self) -> list[str]: - return [tag for tag in self.get("tags", []) if tag.startswith("_")] - - @property - def visible(self): - if self.get("disabled", False): - return False - try: - return all([self[key] for key in self.MANDATORY_FIELDS]) - except KeyError: - return False - - @property - def langs(self) -> list[str]: - return [lang[:2] for lang in self.get("languages", [])] - - -def gen_home(fpath: pathlib.Path): - try: - document = yaml.load(fpath.read_text(), Loader=SafeLoader) - except Exception as exc: - print("[CRITICAL] unable to read home YAML document, using fallback homepage") - traceback.print_exception(exc) - return - - Conf.from_doc(document.get("metadata", {})) - context = Conf.to_dict() - context["packages"] = list( - filter(lambda p: p.visible, [Package(**item) for item in document["packages"]]) - ) - context["languages"] = {} - context["categories"] = set() - for package in context["packages"]: - for lang in package.get("languages", []): - context["languages"][lang] = iso639.Lang(lang).name - for tag in package.get("tags", []): - if tag.startswith("_category:"): - package["category"] = tag.split(":", 1)[-1] - context["categories"].add(package["category"]) - context["categories"] = sorted(context["categories"]) - context["readers"] = [Reader(**item) for item in document.get("readers", [])] - context["links"] = [Link(**item) for item in document.get("links", [])] - - try: - with open(dest_dir / "index.html", "w") as fh: - context["page"] = "home" - fh.write(env.get_template("home.html").render(**context)) - - with open(dest_dir / "download.html", "w") as fh: - context["page"] = "download" - fh.write(env.get_template("download.html").render(**context)) - except Exception as exc: - print("[CRITICAL] unable to gen homepage, using fallback") - traceback.print_exception(exc) - return - - print("Generated homepage") - - -if __name__ == "__main__": - gen_home(packages_path) - - if Conf.debug: - with open(dest_dir / "index.html", "r") as fh: - print(fh.read()) diff --git a/dashboard/home.yaml b/dashboard/home.yaml deleted file mode 100644 index 8672e20..0000000 --- a/dashboard/home.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -metadata: - name: Not Configured - fqdn: default.hotspot -packages: [] diff --git a/dashboard/lighttpd.conf b/dashboard/lighttpd.conf deleted file mode 100644 index 3a43905..0000000 --- a/dashboard/lighttpd.conf +++ /dev/null @@ -1,5 +0,0 @@ -server.document-root = "/var/www/" -index-file.names = ( "index.html", "fallback.html" ) - -server.modules += ("mod_alias") -alias.url += ( "/download" => "/var/www/download.html" ) diff --git a/dashboard/refresh-zims.py b/dashboard/refresh-zims.py deleted file mode 100644 index aaf757f..0000000 --- a/dashboard/refresh-zims.py +++ /dev/null @@ -1,165 +0,0 @@ -#!/usr/bin/env python3 - -""" refresh-zims: update YAML packages list using disk-discovered ZIM files - - This is an optional feature, yet it is enabled by default. - Set `DONT_UPDATE_PACKAGES` environ to disable - - Once enabled, this loops over ZIM files present on disk (at `ZIM_DIR` path) - and updates the Packages YAML (at `PACKAGES_PATH`) accordingly: - - if the package (using its ident) was in YAML: keep YAML entry - - if the ZIM was not in YAML: add entry using in-ZIM info - - entries in YAML for which ZIM is missing are disabled but kept. - - Dependencies: - - PyYAML - - libzim -""" -import base64 -import os -import pathlib -import traceback -from typing import Any - -import yaml -from libzim.reader import Archive - -try: - from yaml import CDumper as Dumper - from yaml import CSafeLoader as SafeLoader -except ImportError: - # we don't NEED cython ext but it's faster so use it if avail. - from yaml import Dumper, SafeLoader - -packages_path = ( - pathlib.Path(os.getenv("PACKAGES_PATH", "home.yaml")).expanduser().resolve() -) -zims_dir = pathlib.Path(os.getenv("ZIM_DIR", "/src")) -dont_update = bool(os.getenv("DONT_UPDATE_PACKAGES", "")) - -kiwix_reader_link_tpl = os.getenv("KIWIX_READER_LINK_TPL", "//kiwix.{fqdn}/{zim_name}") -kiwix_download_link_tpl = os.getenv( - "KIWIX_DOWNLOAD_LINK_TPL", "//zim-download.{fqdn}/{zim_filename}" -) - - -def get_metadata(archive: Archive, name: str) -> str: - if name not in archive.metadata_keys: - return "" - return archive.get_metadata(name).decode("UTF-8") - - -def get_kiwix_url(template: str, fqdn: str, name: str, filename: str) -> str: - return ( - template.replace("{fqdn}", fqdn) - .replace("{zim_name}", name) - .replace("{zim_filename}", filename) - ) - - -def get_entry_for( - fpath: pathlib.Path, document_metadata: dict[str, str] -) -> dict[str, Any]: - zim = Archive(fpath) - publisher = get_metadata(zim, "Publisher") - name = get_metadata(zim, "Name") - flavour = get_metadata(zim, "Flavour") - ident = f"{publisher}:{name}:{flavour}" - icon = None - if zim.has_illustration and 48 in zim.get_illustration_sizes(): - icon = base64.b64encode(bytes(zim.get_illustration_item(48).content)).decode( - "ASCII" - ) - return { - "kind": "zim", - "ident": ident, - "title": get_metadata(zim, "Title"), - "description": get_metadata(zim, "Description"), - "languages": get_metadata(zim, "Language").split(",") or ["eng"], - "tags": get_metadata(zim, "Tags").split(";"), - "url": get_kiwix_url( - template=kiwix_reader_link_tpl, - fqdn=document_metadata["fqdn"], - name=name, - filename=fpath.name, - ), - "download": { - "url": get_kiwix_url( - template=kiwix_download_link_tpl, - fqdn=document_metadata["fqdn"], - name=name, - filename=fpath.name, - ), - "size": fpath.stat().st_size, - }, - "icon": icon, - } - - -def refresh_zims( - packages_path: pathlib.Path, zims_dir: pathlib.Path, debug: bool | None = False -): - print(f"refreshing ZIMs from {zims_dir=}") - try: - document = yaml.load(packages_path.read_text(), Loader=SafeLoader) - document["packages"] - document["metadata"] - document["metadata"]["fqdn"] - document["metadata"]["name"] - except Exception as exc: - print("[CRITICAL] unable to read home YAML document, skiping") - traceback.print_exception(exc) - return - - # copy list of packages from YAML - conf_packages = { - package.get("ident", ""): package for package in document["packages"] - } - - # get packages from what's on the filesystem - fs_packages = {} - for zim_fpath in zims_dir.glob("*.zim"): - try: - package = get_entry_for(zim_fpath, document["metadata"]) - except Exception as exc: - print(f"Failed to read from {zim_fpath}, skiping ({exc})") - continue - else: - fs_packages[package["ident"]] = package - - # now let's start from scratch - document["packages"] = [] - - # first, adding files in config, in their original order, disabling missing ones - for ident, package in conf_packages.items(): - # make sure we keep non-ZIM packages - if ident in fs_packages or package.get("kind", "") != "zim": - package.pop("disabled", None) - else: - package["disabled"] = True - document["packages"].append(package) - - # second, add all the fs ones, but not those already in conf - for ident, package in fs_packages.items(): - # dont add twice, was already handled - if ident in conf_packages: - continue - document["packages"].append(package) - - try: - packages_path.write_text(yaml.dump(document, Dumper=Dumper)) - except Exception as exc: - print("[CRITICAL] unable to update(save) home YAML document, skiping") - traceback.print_exception(exc) - return - - -if __name__ == "__main__": - if not dont_update and zims_dir.exists() and zims_dir.is_dir(): - refresh_zims( - packages_path=packages_path, - zims_dir=zims_dir, - debug=bool(os.getenv("DEBUG", False)), - ) - else: - print(f"Not refreshing ZIMs for {dont_update=}, {zims_dir=}") diff --git a/dashboard/tailwind.config.js b/dashboard/tailwind.config.js deleted file mode 100644 index c2a026f..0000000 --- a/dashboard/tailwind.config.js +++ /dev/null @@ -1,68 +0,0 @@ -/** @type {import('tailwindcss').Config} */ -module.exports = { - content: ["./templates/**/*.{html,js}"], - safelist: [ - 'kiwix-home-btn', - 'kiwix-home-btn-active', - 'kiwix-download-btn', - 'kiwix-download-btn-active', - 'kiwix-order-dir-btn', - 'kiwix-sort-btn', - 'kiwix-sort-btn-active', - {pattern: /kiwix-.+/}, - ], - theme: { - extend: { - screens: { - 'xxs': {'min': '376px', 'max': '439px'}, - 'xs': {'min': '450px', 'max': '639px'}, - }, - colors: { - kwwhite: '#eef2f6', - kwbgwhitehover: '#f7f8fa', - kwbggrey: '#eef2f6', - kwfiltersgrey: { - DEFAULT: '#dbe1e9', - 400: '#dae0e8', - 500: '#d6dce4', - 600: '#d3d9e1', - 700: '#cfd5dd', - 800: '#cbd1d9', - 900: '#ccd3da', - }, - kwordergrey: { - 100: '#a6b2bd', - 500: '#6f8291', - 600: '#92a6b9', - }, - kwtagbggrey: '#a8aba2', - kwreaderbggrey: '#777777', - kwreaderhover: '#4c4c4c', - kwbordergrey: '#c3c5c6', - kwtextblack: '#231f20', - kwtextgrey: '#585b5d', - kwtextgreyn: '#707272', - 'kworange': { - DEFAULT: '#f39325', - 100: '#f79433', - 200: '#f39033', - 300: '#f08e33', - 400: '#ed8b33', - 500: '#cc6600', - 600: '#dc7d2c', - 700: '#da7c2c', - 800: '#d7711d', - 900: '#d77336', - } - }, - gridTemplateColumns: { - '1m': 'repeat(1, max-content)', - '1f': 'minmax(100%, 100%)', - '2m': 'repeat(2, max-content)', - '3m': 'repeat(3, max-content)', - '4m': 'repeat(4, max-content)', - '5m': 'repeat(5, max-content)', - } - } - }, -} diff --git a/dashboard/templates/base.html b/dashboard/templates/base.html deleted file mode 100644 index 946b29b..0000000 --- a/dashboard/templates/base.html +++ /dev/null @@ -1,292 +0,0 @@ - - - - - - {{ name }} - - - - - - - - - - -
- -
- - {% if page == 'home' %} -
- -
- -
-
- - - -
-
-
- {% endif %} - - -{% block entries %} -{% endblock %} - - - {% if page == 'download' %} -
- -
- -
-
- - - -
-
- -
-
- {% endif %} - - - - diff --git a/dashboard/templates/download.html b/dashboard/templates/download.html deleted file mode 100644 index 54f7e4d..0000000 --- a/dashboard/templates/download.html +++ /dev/null @@ -1,312 +0,0 @@ -{% extends "base.html" %} - -{% block entries %} -
- -
-

DOWNLOADS

-
- - {% if readers %} - - {% endif %} - - {% for package in packages %} - {% if package.download and package.download.size %} -
- -
- -
-
-

{{ package.title|truncate(30, killwords=True, end="…") }}

-
- -
- {{ package.download.size|fsize }} -
-
-
- {% if package.langs %} - {% for lang in package.langs %} - {% if loop.index0 < 2 %} - {{ lang }} - {% endif %} - {% endfor %} - {% endif %} -
-
- - - -
-
- - - -
-
- -
- {% endif %} - {% else %} -

No content packages 🙁

- {% endfor %} -
-{% endblock %} diff --git a/dashboard/templates/home.html b/dashboard/templates/home.html deleted file mode 100644 index 6f9912b..0000000 --- a/dashboard/templates/home.html +++ /dev/null @@ -1,221 +0,0 @@ -{% extends "base.html" %} - -{% block entries %} -
- {% for package in packages %} -
- - -
-
- {% if package.langs %} -
- {% for lang in package.langs %} - {% if loop.index0 <= 2 and lang != 'mu' %} -
{{ lang }}
- {% endif %} - {% endfor %} -
- {% endif %} -
-
-

{{ package.description|default("-")|truncate(80, killwords=False, end="…") }}

-
-
- -
-
{% if package.download and package.download.size %}{{ package.download.size|fsize }}{% endif %}
-
{% if package.tags %}{% for tag in package.tags %}{% if loop.index0 <= 1 %}{{ tag }}{% endif %}{% endfor %}{% endif %}
-
-
- {% else %} -

No content packages 🙁

- {% endfor %} -
-{% endblock %}