From 84f21956fa186b6700e13391dc1d37137759a3b5 Mon Sep 17 00:00:00 2001 From: biosias Date: Fri, 11 Sep 2026 12:37:41 +0200 Subject: [PATCH] Removed export file --- .claude/nginx-sitemap-crawler-plan.md | 392 ++++++++++++++++++++++++++ CLAUDE.md | 2 + cmjs/export-report.txt | 99 ------- 3 files changed, 394 insertions(+), 99 deletions(-) create mode 100644 .claude/nginx-sitemap-crawler-plan.md create mode 100644 CLAUDE.md delete mode 100644 cmjs/export-report.txt diff --git a/.claude/nginx-sitemap-crawler-plan.md b/.claude/nginx-sitemap-crawler-plan.md new file mode 100644 index 0000000..7ff6cf8 --- /dev/null +++ b/.claude/nginx-sitemap-crawler-plan.md @@ -0,0 +1,392 @@ +# Nginx Sitemap Crawler — Design Plan + +_Last updated: 2026-09-10_ + +## Tech stack + +- **Language:** pure JavaScript, running **client-side inside a + webpage** (no Node, no server-side execution anywhere in this + project — nginx serves static listings only). + +## Goal + +Maintain a browsable, near-real-time sitemap of a two-level nginx-served +directory tree, using only stock nginx config (no server-side scripts on +the nginx host), minimizing redundant requests over time, and surfacing +the most recently changed content first. + +## Constraints + +- No server-side execution on the nginx host — plain `nginx.conf` only. +- Client-side script/app is where all logic (crawling, sorting, + pagination, caching) lives. +- Tree is two levels deep (root → level-1 dirs → level-2 dirs). + +--- + +## 1. Nginx setup + +Enable machine-readable directory listings on the relevant locations: + +```nginx +location /files/ { + autoindex on; + autoindex_format json; + autoindex_localtime off; +} +``` + +- `autoindex_format json;` — makes listings parseable instead of scraping HTML. +- `autoindex_localtime off;` — keeps timestamps in GMT, consistent and + unambiguous for comparison logic (avoids DST/timezone drift issues). + +Each listing entry includes `name`, `type` (`file`/`directory`), `size`, +and `mtime`. + +--- + +## 2. Wave-based crawling + +Directory names at level 2 aren't known until level 1 is fetched, so the +crawl naturally happens in sequential **waves**, each internally +**concurrent**: + +- **Wave 1 (root)** — always fetched live on every run. Single request, + cheapest possible cost, and the sole source of truth for what + currently exists and what's changed. +- **Wave 2 (level-1 → level-2)** — fetched only as needed (see §5 + caching) and only for directories relevant to the current page (see + §4 pagination). Requests within a wave are fired concurrently, not + sequentially, to keep latency low regardless of directory count. + +--- + +### 2a. Concurrency limits — **decision: configurable, not hardcoded** + +Rather than a fixed worker count baked into the logic, concurrency is +exposed as a **single tunable setting** (e.g. `maxConcurrentRequests`) +that governs how many wave-2 requests are in flight at once within a +wave. Rationale and shape: + +- **Why configurable:** the right concurrency value depends on factors + that vary by deployment and can't be known in advance — network + distance to the nginx host (same-region vs. cross-region), how many + directories are typically in play per page (tied to §4a page size), + how many browser tabs/users might be hitting the same nginx instance + at once, and how conservative the operator wants to be about log + noise or perceived "scanning" behavior (as noted in earlier + discussion of request bursts). +- **Where it lives:** a single config value/constant near the top of + the client script (or exposed as a UI setting/advanced option), + rather than scattered magic numbers through the crawl logic. +- **Sensible default:** start conservative (e.g. 10) — safe for both + same-region and cross-region cases, and already shown earlier in + this plan to keep even a full ~500-directory cold-start crawl under + a few seconds. Users/operators who know their network is fast and + local, or who page through smaller slices (page size 10, see §4a), + can raise it; those on slower/cross-region links or shared/production + nginx instances can lower it. +- **Interaction with pagination:** since wave-2 is now scoped to just + the current page's directories (§4a), the concurrency setting mostly + matters relative to page size — e.g. at page size 10 with + concurrency 10, an entire page's wave-2 fetches resolve in a single + batch (~1 RTT); at page size 30 with concurrency 10, the same page + takes ~3 batches. Setting concurrency ≥ page size effectively + guarantees single-batch page loads, which is a reasonable rule of + thumb for operators tuning this value. +- **No hard ceiling imposed by nginx** — as established earlier, + nginx's default `worker_connections` comfortably absorbs dozens to + low hundreds of concurrent client connections, so the practical + upper bound is really about being a good citizen (log noise, shared + hosting) rather than anything nginx itself will choke on. + +--- + +## 3. Recency-based prioritization + +- A directory's `mtime` reflects changes to its **direct** children only + (additions, removals, renames) — not deeper nested edits. This is + sufficient for this use case, since the concern is new content + appearing, not deep nested edits (see "Known limitation" below). +- After wave 1 resolves, sort level-1 entries by `mtime` descending, + with directory name ascending as a stable tie-breaker (see R5). + This ordering drives both crawl priority and display order. + +--- + +## 4. Pagination + +- Slice the sorted level-1 list into fixed-size pages (default 10, + user-selectable — see §4a). +- Only fire wave-2 requests for the directories in the **currently + viewed page** — not the whole tree. +- Page navigation reuses the already-fetched, already-sorted wave-1 + list in memory; no repeated root requests needed when paging. +- Optional: prefetch the next page's wave-2 requests in the background + while the current page is being viewed, so navigation feels instant. + +--- + +### 4a. Page size — **decision: user-selectable, default 10** + +- Default page size: **10** items. +- User-selectable alternatives: **15, 20, 30**. +- Changing page size resets pagination to page 1 (avoids ambiguous + partial pages / confusing item overlap when the slice boundaries + shift). +- Since wave 1 is already fully fetched and sorted in memory (see §2, + §3), changing page size is a **pure client-side re-slice** of the + existing sorted list — no new wave-1 request needed. +- Wave-2 fetch behavior (§5, cache-aware) is unaffected by page size + itself — only which/how many level-1 directories fall into the + current slice changes, which in turn determines which cache + entries are read or fetched. + +--- + +## 5. Sitemap cache + +Persist a cache entry per directory: + +```json +{ + "path": "/files/project-a/", + "mtime": "Wed, 10 Sep 2026 14:32:01 GMT", + "children": [ "...level-2 entries..." ], + "children_fetched_at": "2026-09-10T15:00:00Z" +} +``` + +### 5a. Storage mechanism — **decision: IndexedDB** + +This runs purely client-side in a webpage — no filesystem access, so +the real choice is between browser storage APIs: **localStorage** vs. +**IndexedDB**. IndexedDB was chosen: + +- **Storage ceiling** — localStorage is capped around 5-10MB + (browser-dependent) and shared across the whole origin; IndexedDB's + ceiling is far higher (typically hundreds of MB+), removing a + constraint that could otherwise bite as the tree grows. +- **Per-record updates** — IndexedDB is an object store keyed by + record (naturally: path → cache entry), so updating one directory's + entry doesn't require re-serializing/rewriting the entire cache, the + way localStorage (full blob, `JSON.stringify` every write) would. +- **Non-blocking** — IndexedDB is async by nature, which fits a cache + that's written to progressively as crawl waves resolve, without + freezing the UI thread. localStorage is synchronous and would block + rendering on every read/write as the cache grows. +- **No manual serialization** — IndexedDB stores structured JS objects + directly; no need to `JSON.stringify`/`parse` on every access. +- **Still zero external dependencies** — native browser API, no + library required (though a thin promise-wrapper like `idb` is a + reasonable, optional ergonomics improvement later if the raw API + proves too verbose). + +**Practical shape:** +- One object store, e.g. `directoryCache`, keyed by directory `path`. +- Each record holds `{ path, mtime, children, children_fetched_at }` + as described below. +- Reads/writes are async (`Promise`-based or wrapped in one), which + aligns naturally with the already-async wave-2 fetches. + +On each run, compare each level-1 directory's **live** `mtime` (from +wave 1) against the **cached** `mtime`: + +- **Match** → skip wave 2 for that directory; serve `children` from + cache. +- **Newer or missing** → fetch wave 2 live, then update the cache entry + with the new `mtime` and `children`. + +Additional cache maintenance: + +- **Pruning** — after wave 1, any cached level-1 entries no longer + present in the live listing should be removed (handles deletions). +- **Wave 1 is never cached** — it has no parent to diff against, and + it's already the cheapest possible request (1 per run, regardless of + tree size). +- **Cold start** — first run has no cache, so it pays the full crawl + cost once. Every subsequent run should be dramatically cheaper, + bounded roughly by how much actually changed since the last run. + +--- + +## 6. Why this combination works well together + +- Sorting by `mtime` descending means the directories most likely to + have a **stale cache** (recent changes) are exactly the ones + prioritized to the front — so page 1 concentrates the real crawl + cost, while later pages are almost pure cache hits. +- Over repeated runs, total request cost trends toward being + proportional to **how much changed**, not the size of the tree. +- Progressive/skeleton rendering (page renders immediately with cached + or partial data, updates in place as fresher wave-2 results arrive) + keeps the experience responsive even while cache misses are being + resolved in the background. + +--- + +## Known accepted limitation + +Directory `mtime` only reflects direct-child changes, not deeper nested +edits (e.g. a file modified inside an existing level-2 directory won't +bump the level-1 directory's `mtime`). Accepted as a non-issue here, +since the priority signal needed is "new subdirectories appearing," +which this correctly captures. + +--- + +## Longevity Considerations + +_This project is intended as "deploy and forget" for a ~30 year +horizon. That's a materially different constraint than "get this +working now," and shapes several decisions beyond what pure +functionality would require._ + +### L1. IndexedDB eviction — not a concern +Some browsers (e.g. Safari ITP) may evict IndexedDB data for +infrequently-visited origins. **Explicitly accepted as a non-issue**: +R6's uncached fallback mode already handles any IndexedDB +unavailability gracefully (falls back to live fetching), so eviction +simply means the cache benefit doesn't materialize on that visit — not +a failure. No action needed beyond what's already in R6. + +### L2. HTML fallback if JSON listing breaks — **decision: included** +`autoindex_format json` depends on nginx config staying intact over +the project's lifetime. Configs can drift — a server migration, +reconfiguration, or someone disabling `autoindex_format json` (while +leaving `autoindex on;` itself in place) is realistic over 30 years. + +To survive this, the crawler includes an **HTML fallback parser**: + +- On each request, if the response isn't valid JSON (parse fails, or + `Content-Type` isn't JSON), fall back to treating the response as + nginx's **default HTML autoindex output** instead of failing the + request outright. +- Parse the HTML using the browser's native `DOMParser` (built-in, no + dependency) — extract entries from the `` listing, + using the link `href` for name/type (trailing `/` = directory) and + the surrounding text for `mtime`/size where present. +- This is strictly a **fallback path**, not the primary path — JSON + remains preferred when available, since it's more reliable to parse + and already carries structured `mtime`. The HTML fallback exists + purely so the tool degrades to "still works, just via a different + parse path" rather than "breaks entirely" if `autoindex_format json` + is ever lost from the config. +- This directly follows the same silent-skip philosophy as R3: prefer + degraded function over hard failure, wherever degrading is possible + without violating the zero-dependency principle. + +### L3. Total-failure visibility +Silent-skip (R3) is correct for individual transient request failures, +but should not extend to masking a *total* breakage (e.g. CORS +misconfigured after a migration, autoindex disabled entirely, wrong +origin). The crawler tracks a simple "N of M directories loaded" +count; if that ratio is very low (e.g. near-zero) after a crawl +completes, a minimal, dependency-free visible indicator (a status line +in the UI, no alerting infrastructure) should communicate that +something is broken, so the project doesn't fail silently for years +before a human notices. + +### L4. Zero dependencies, deliberately +No npm packages, no build step, no framework — stated explicitly as a +guiding principle, not just an incidental outcome of earlier +decisions. Any dependency introduces a 30-year liability: registries +can vanish, packages can go unmaintained, and even a "small" library +can break under a future browser change with nobody left to patch it. +Future contributors should treat this as a hard constraint, not a +preference to be relaxed for convenience. + +### L5. Prefer long-stable JS/browser APIs over new syntax +Favor well-established, broadly-supported features (`fetch`, +`Promise`, `async`/`await`, basic IndexedDB, `DOMParser`) over newer or +experimental JS/browser APIs. The newer something is today, the more +likely it is to be deprecated, changed, or need a polyfill by the time +this project is 15-20 years old. Nothing currently behind a flag or +"experimental" label should be used, even if convenient now. + +### L6. Keep this plan attached to the code +For a deploy-and-forget project, the largest real risk isn't +technical — it's a future maintainer with zero context. This document +should ship alongside the implementation (same repository, or +inlined as a comment block) rather than live separately, so the +reasoning behind each decision (why JSON over HTML, why IndexedDB, +why silent-skip, etc.) survives together with the code itself. + +### L7. nginx version/config drift +`autoindex_format json` requires a reasonably modern nginx (long +available, but not guaranteed present on every install). Document a +minimum nginx version alongside the deployment instructions, and treat +"response isn't valid JSON" as an expected, handled case (see L2) +rather than an exceptional one — since over 30 years, drift in the +server config is a "when," not an "if." + +--- + +## Risks & Edge Cases + +### R1. CORS +If the webpage is served from a different origin than the nginx +directory listing, browser `fetch()` calls will be blocked without +proper CORS headers. Requires an `add_header Access-Control-Allow-Origin +...;` (or equivalent) on the relevant nginx `location` block, unless +the page and the file server share an origin. Needs to be decided/set +up alongside the nginx config in §1. + +### R2. Trailing slashes on directory requests +nginx's autoindex only serves a listing cleanly when the request URL +ends in `/`. Requesting a directory path without the trailing slash +typically triggers a redirect (e.g. 301) instead of returning the +listing directly, adding an extra round-trip. The crawler must +consistently append `/` when building wave-2 request URLs from the +`name` field returned in wave-1's JSON. + +### R3. Error handling for failed requests — **decision: silent skip** +If a wave-2 request fails (timeout, 404, host briefly unreachable), +it is silently skipped: no retry, no visible error marker. The +directory in question falls back to whatever is already in the +IndexedDB cache (stale-but-present data), or is simply omitted from +that page's render if nothing is cached yet. Accepted trade-off for +simplicity — a failed fetch does not block or degrade the rest of the +page. + +### R4. Race conditions from rapid navigation +Changing page size or flipping pages quickly can cause in-flight +requests from a previous page/size to resolve *after* newer ones, +overwriting current state with stale data. Mitigated with a +generation/token counter: each navigation action increments a +"current generation" value, and any response that arrives tagged with +an older generation than the current one is discarded rather than +rendered. + +### R5. `mtime` tie-breaking +autoindex JSON timestamps are second-precision, so directories touched +within the same second (e.g. a batch of subdirectories created +together by a script) can tie on `mtime`. The sort in §3 uses `mtime` +descending as the primary key with **directory name ascending** as a +stable secondary key, so ordering — and therefore pagination — stays +consistent across runs instead of jittering on ties. + +### R6. IndexedDB availability — **decision: uncached fallback mode** +IndexedDB may be unavailable or restricted (private/incognito modes in +some browsers) or subject to storage eviction under pressure. The +crawler treats any IndexedDB access failure (open error, blocked +transaction, etc.) as a signal to fall back to an **uncached mode**: +every wave-2 request is fetched live for the duration of that session, +with no persistence attempted. This keeps the sitemap fully functional +— just without the performance benefit of cache hits on repeat visits +— rather than erroring out or blocking the page. Detection happens +once at startup (attempt to open the DB; on failure, set an in-memory +`cacheAvailable = false` flag that the rest of the logic checks before +any cache read/write). + +--- + +## Open items / future considerations + +_All resolved — no open items remain._ + +Ruled out: WebDAV / `PROPFIND` (`ngx_http_dav_ext_module`) as a +single-request full-tree alternative — requires a non-stock nginx +build/module, which conflicts with the "ordinary nginx only" and +simplicity constraints. Wave-based crawling with caching (§2, §5) +remains the approach. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..369d154 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,2 @@ +# Git Overrides +* Do not push commited changes in this project diff --git a/cmjs/export-report.txt b/cmjs/export-report.txt deleted file mode 100644 index 2763c51..0000000 --- a/cmjs/export-report.txt +++ /dev/null @@ -1,99 +0,0 @@ -Source SQL dump: /home/jakub/Documents/expa/web/wp/wordpress/db/migration_dump.sql -Source uploads: /home/jakub/Documents/expa/web/wp/wordpress/html/wp-content/uploads -Exported posts: 509 -Skipped records: 1025 -Copied media files: 322 -Unresolved upload URLs: -http://astronomickaexpedice.cz/wp-content/uploads/2025/03/export-3-export-3-scaled.jpg -http://astronomickaexpedice.cz/wp-content/uploads/2025/03/export-4-export-4-scaled.jpg -http://astronomickaexpedice.cz/wp-content/uploads/2025/06/export-2-export-2.jpg -http://astronomickaexpedice.cz/wp-content/uploads/2025/06/final-1.1-final-1.1-scaled.jpg -http://astronomickaexpedice.cz/wp-content/uploads/2025/06/final-export-final-export.jpg -http://astronomickaexpedice.cz/wp-content/uploads/2025/06/final-nova-uprava-final-nova-uprava.jpg -http://astronomickaexpedice.cz/wp-content/uploads/2025/06/final-pc-final-pc.jpg -http://astronomickaexpedice.cz/wp-content/uploads/2025/06/iris-export-6.jpg -http://astronomickaexpedice.cz/wp-content/uploads/2025/06/jesle-finale-2-jesle-finale-2-1.jpg -http://astronomickaexpedice.cz/wp-content/uploads/2025/06/jeslicky-novy-6-vance-jeslicky-novy-6-vance.jpg -http://astronomickaexpedice.cz/wp-content/uploads/2025/06/koule-plna-hvezd-export-1.jpg -http://astronomickaexpedice.cz/wp-content/uploads/2025/06/m42-orion-starless-scaled.jpg -http://astronomickaexpedice.cz/wp-content/uploads/2025/06/m51-export-3-hdr-sharp-m51-export-3-hdr-sharp-scaled.jpg -http://astronomickaexpedice.cz/wp-content/uploads/2025/06/mensi-mensi.jpg -http://astronomickaexpedice.cz/wp-content/uploads/2025/06/mesic-jizni-okraj-mesic-export-2-1-rotated.jpg -http://astronomickaexpedice.cz/wp-content/uploads/2025/06/orion-novy-pokus-final-4-orion-novy-pokus-final-4-scaled.jpg -http://astronomickaexpedice.cz/wp-content/uploads/2025/06/triangulum-hdr-6-triangulum-hdr-6.tif -http://astronomickaexpedice.cz/wp-content/uploads/2025/08/obloha-nad-expou-v-nedeli-pred-obedem-celooblohovka-expa-1024x767.jpg -http://astronomickaexpedice.cz/wp-content/uploads/2025/08/pacman-4-pacman-4.jpg -http://astronomickaexpedice.cz/wp-content/uploads/2025/08/triangulace-v-triangulu-aneb-jak-jsem-s-pomoci-triangulace-nasel-galaxii-triangulum-triangulace-1024x594.jpeg -https://astronomickaexpedice.cz/wp-content/uploads/2012/06/ngc-457-muzicek1-1024x907.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2012/07/expa2012_dusik-1024x681.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2012/07/expa2012_dusik_vejce-1024x681.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2012/07/img_11062-1024x682.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2012/07/p1240331-1024x768.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2012/07/p1240437-1024x768.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2012/07/pyromanie-300x199.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2012/07/smallimg_2165a-300x112.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2012/07/sun-300x199.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2012/07/v1010cas-300x202.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2012/07/v502oph-300x202.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2012/08/115-300x157.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2012/08/130-300x157.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2012/08/232-300x157.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2012/08/309-300x157.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2012/08/310-300x157.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2012/08/409-300x157.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2012/08/410-300x157.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2012/08/412-300x157.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2012/08/509-300x157.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2012/08/511-300x157.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2012/08/expa-300x199.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2012/08/m13-expa1-300x199.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2019/08/astrometry2.png -https://astronomickaexpedice.cz/wp-content/uploads/2019/08/calib-cometa_00041.gif -https://astronomickaexpedice.cz/wp-content/uploads/2019/08/cwcas_lightcurve.png -https://astronomickaexpedice.cz/wp-content/uploads/2019/08/cwcas_oc.png -https://astronomickaexpedice.cz/wp-content/uploads/2019/08/etd1.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2019/08/exo-chart1.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2019/08/exo2.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2019/08/formular.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2019/08/gif1.gif -https://astronomickaexpedice.cz/wp-content/uploads/2019/08/ha-2-20-zmenseno.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2019/08/lrgb_m8_krivka-1024x1019.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2019/08/lrgb_m8_krivka.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2019/08/m31_single_done_red.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2019/08/mereni-komety.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2019/08/orlimlhovina-mini.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2019/08/referencni.png -https://astronomickaexpedice.cz/wp-content/uploads/2019/08/screen21.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2019/08/sestava-na-spektra.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2019/08/vega-neupraveno.png -https://astronomickaexpedice.cz/wp-content/uploads/2019/08/vega-s-prvky.png -https://astronomickaexpedice.cz/wp-content/uploads/2019/08/vega-upraveno.png -https://astronomickaexpedice.cz/wp-content/uploads/2019/08/vega_opraveno.png -https://astronomickaexpedice.cz/wp-content/uploads/2019/08/wasp_2b_ja.png -https://astronomickaexpedice.cz/wp-content/uploads/2019/08/wasp_2b_peter.png -https://astronomickaexpedice.cz/wp-content/uploads/2019/08/wasp_74b_dienstbier.png -https://astronomickaexpedice.cz/wp-content/uploads/2019/08/wasp_74b_plsek.png -https://astronomickaexpedice.cz/wp-content/uploads/2019/08/wasp_74b_siegert_kohl.png -https://astronomickaexpedice.cz/wp-content/uploads/2022/07/v-nektere-vede-se-muze-skryvat-astrofotografie-v-kazde-astrofotografii-se-muze-skryvat-veda-varzralok-1024x831.png -https://astronomickaexpedice.cz/wp-content/uploads/2022/08/lbn-527-lbn527-1024x854.png -https://astronomickaexpedice.cz/wp-content/uploads/2022/08/okno-do-nebe-aneb-porovnani-kvality-oblohy-windowfinal-1-1024x1024.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2022/08/okno-do-nebe-aneb-porovnani-kvality-oblohy-windowfinal-1024x1024.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2023/08/pozorovani-tranzitu-exoplanety-toi-4010-d-img-5285-225x300.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2024/01/ifn-okolo-polarky-pokus-6-1024x698.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2024/08/bode-modry-3-1320x928.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2024/08/duse-5-1320x742.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2024/08/i-se-starsim-fotakem-lze-vykouzlit-zazraky-krajinka-canon-30d-1024x683.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2024/08/i-se-starsim-fotakem-lze-vykouzlit-zazraky-rybi-oko-canon-30d-1024x683.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2024/08/m27-cinka-m27-1320x969.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2024/08/panorama-export-1320x903.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2024/08/vesmirna-zahradka-hotovo-1024x745.jpeg -https://astronomickaexpedice.cz/wp-content/uploads/2024/08/zakreslovani-slunce-img-4097-768x1024.jpeg -https://astronomickaexpedice.cz/wp-content/uploads/2024/08/zakreslovani-slunce-img-4105-768x1024.jpeg -https://astronomickaexpedice.cz/wp-content/uploads/2025/09/NGC40-1002x1024.jpg -https://astronomickaexpedice.cz/wp-content/uploads/2025/10/final-1024x686.jpg -https://www.astronomickaexpedice.cz/wp-content/uploads/2016/06/img_9395.jpg -https://www.astronomickaexpedice.cz/wp-content/uploads/2016/07/img_4514blog.jpg -https://www.astronomickaexpedice.cz/wp-content/uploads/2019/08/cinka-mini.jpg -https://www.astronomickaexpedice.cz/wp-content/uploads/2019/08/final_ic59_63.jpg -https://www.astronomickaexpedice.cz/wp-content/uploads/2019/08/heartfinal-mini.jpg -https://www.astronomickaexpedice.cz/wp-content/uploads/2019/08/zamrzle1.jpg