[general]
name=Basemap Tile Downloader
qgisMinimumVersion=3.40.8
qgisMaximumVersion=4.99
description=Download a WMS, WMTS, XYZ, or ArcGIS REST basemap over an extent and mosaic it into a GeoTIFF.
about=Auto-detects whether the chosen layer is a WMS, WMTS, XYZ, or ArcGIS REST MapServer tile source. Tiles the request over a chosen extent (WMS GetMap at a chosen resolution/CRS, or WMTS / Web-Mercator {z}/{x}/{y} at a chosen zoom), downloads with adaptive throttling and a resumable SQLite work queue, georeferences each tile, and builds a compressed, tiled GeoTIFF mosaic (with overviews) using GDAL. Optionally reprojects to a chosen output CRS and crops to the exact extent. Requires the GDAL Python bindings. For personal and educational use only — respect each provider's Terms of Service and usage limits.
version=1.10.6
author=Coert Vonk
email=ing.c.j.s.vonk@gmail.com
license=GPL-3.0-or-later
tracker=https://github.com/cvonk/qgis-basemap-tile-downloader/issues
repository=https://github.com/cvonk/qgis-basemap-tile-downloader
homepage=https://github.com/cvonk/qgis-basemap-tile-downloader
icon=icon.svg
experimental=False
deprecated=False
category=Raster
tags=wms,wmts,xyz,tiles,download,raster,mosaic,gdal,basemap,orthophoto,aoi,web mercator
changelog=1.10.6 - Dialog tooltips wrap to a readable column: Qt does not
    word-wrap plain-text tooltips, so the hover help added in 1.10.5 rendered as
    single very wide lines. They are now wrapped to 40 columns, with
    continuation lines indented so the "On:"/"Off:" clauses stand out.
    1.10.5 - Code-review fixes, plus hover help on every dialog control.
    ArcGIS now shows the live tile-count estimate and the large-download /
    Terms-of-Service confirmation (counted per flight year when harmonising),
    and resuming a harmonised ArcGIS job no longer re-asks the overwrite/ToS
    prompts (the job fingerprint no longer depends on service metadata resolved
    at run time). Per-job caches are keyed by output name plus a short path
    hash, so same-named outputs in different folders can't wipe each other's
    queue (existing caches migrate automatically). Cached tiles are now
    DEFLATE-compressed (roughly an order of magnitude smaller cache). Logged
    request URLs mask API-key/token values, so a shared download.log can't leak
    a credential. WMTS tile-matrix indexes up to 30 are selectable.
    1.10.4 - ArcGIS tiles now use the shared cache (like XYZ/WMTS/WMS):
    keyed by content (endpoint/CRS/format/tile-size/resolution) plus a per-tile
    layer/col/row identity, so overlapping AOIs and re-runs that only change the
    harmonise match knob or the output file reuse tiles instead of re-downloading.
    Each flight year is cached under its own layer folder.
    1.10.3 - Harmonise gains a "Match brightness/contrast" strength
    (Processing group, ArcGIS; default 0 = today's colour-only behaviour): on top
    of the seam colour match, it can pull the flight years' overall brightness and
    contrast together, blending toward a global match. Also renamed an ambiguous
    variable to clear a Flake8 E741 warning on the plugin repository.
    1.10.2 - Qt6 / QGIS 4 fix: several QGIS enums were used unscoped
    (Qgis.Info, QgsTask.CanCancel, QgsMapLayerProxyModel.RasterLayer, etc.),
    which PyQt6 rejects and the QGIS Plugin Repository flags. They are now fully
    scoped (Qgis.MessageLevel.Info, QgsTask.Flag.CanCancel, ...), which also
    works on QGIS 3's PyQt5.
    1.10.1 - Flight-year harmonise now recognises more ArcGIS layer
    namings (e.g. Land Tirol's "Image_2022" / "Image_2019_2021", which the old
    exact-"Image" match and word-boundary year regex missed). Services with a
    deep dated archive harmonise only the newest few years, so a current basemap
    isn't composited with decades-old imagery.
    1.10.0 - New ArcGIS REST MapServer source type: point the plugin at an
    ArcGIS Map Server layer and it downloads faithfully via the service's export
    endpoint (tiled over the extent at a chosen resolution/CRS). New "Harmonise
    flight years" option (a Processing group in the dialog) for ArcGIS orthophoto
    services that mosaic several survey years: it downloads each year separately
    and colour-matches the older years to the newest along their shared boundary,
    removing the year-boundary seam without muting the colours.
    1.9.4 - Quieter Message Log: the extent-coordinate dump and the
    fetch-settings line (concurrency / back-off cap / give-up) are now written to
    download.log only, not shown in the QGIS Message Log panel. The "building the
    GeoTIFF mosaic..." notice now stays in the canvas message bar for the whole
    build instead of auto-dismissing part-way through.
    1.9.3 - The live message-bar counter now shows estimated time
    remaining (e.g. "~5m 36s left") instead of the per-tile pace, using the pace
    of tiles fetched this run so a resume or shared-cache reuse doesn't skew it.
    The shared-cache signature is now logged to the Message Log at the start of
    the fetch phase, so overlapping jobs can be confirmed to share a cache.
    1.9.2 - Fixed the live "s/tile" counter, which read too low: it
    divided the elapsed time by every resolved tile, including tiles restored
    from a resumed queue or the shared cache (which cost no time this run), so it
    showed roughly half the real pace on a fresh run and near zero on a resume.
    It now measures only the tiles fetched after the counter appears.
    1.9.1 - The WMS retry cache-buster added in 1.9.0 is now an opt-in
    Advanced option, "Bypass cached server errors on retry" (off by default). It
    forgoes any server-side cache on retries and only helps when a WMS behind a
    cache/CDN keeps replaying a cached ServiceException for byte-identical
    retries, so it is now a deliberate toggle rather than always-on. Only WMS is
    affected; XYZ/WMTS and local rasters ignore it.
    1.9.0 - New option "Build mosaic even if some tiles are missing" (off
    by default): an interrupted or partly-failed run can stitch a mosaic from
    whatever downloaded, leaving the missing tiles as transparent gaps, and a
    later re-run with the option off still fills them and rebuilds it complete.
    Fixed: WMS retries could not get past a server error cached by a CDN/proxy
    (a ServiceException is returned as HTTP 200, so a byte-identical retry
    replayed the cached failure); each retry now adds a throwaway cache-buster
    to the GetMap request so the server actually re-renders.
    1.8.1 - Fixed server rate-limiting handling, which never engaged: a
    429/403/500/503 reply was misread as a plain network error, so the adaptive
    throttle never backed off, Retry-After was ignored, and rate-limited tiles
    burned their retry budget at full speed and failed. Those replies are now
    correctly treated as back-pressure. Also fixed: WMTS KVP requests kept an API
    key carried in the capabilities URL; a GeoTIFF job no longer wipes its cache
    when an unrelated WMS resolution changes; starting a second run while one is
    active now warns instead of falsely reporting a download started; an invalid
    mosaic is reported as an error instead of "all tiles are empty"; and
    "Reproject sampling: None" keeps the WMTS CRS resolved from the capabilities.
    1.8.0 - The mosaic is now built only when every tile is downloaded.
    A cancelled run, a server that stops the run early, or one with failed tiles
    no longer produces a partial mosaic with gaps; progress is checkpointed and
    re-running continues where it left off, building the mosaic once the last tile
    lands. Completion messages report how many tiles are left to go.
    1.7.1 - A live per-tile counter now shows in the message bar while
    downloading (tiles done / total, percent and seconds-per-tile), updating in
    place; it replaces the 10 percent progress line in the log. Throttle log lines
    note when the minimum-delay floor is in effect, so they no longer look like
    the pace dropped below your minimum. Security housekeeping: all bandit
    findings cleared with scoped nosec markers (hardened-XML imports, dev-only git
    call, best-effort error handlers) and CI now runs the full bandit scan.
    1.7.0 - Shared tile cache: overlapping areas now reuse each other's
    tiles (XYZ, WMTS and WMS) from a shared folder, skipping the repeat request
    and the provider-quota hit; WMS tiles are anchored to the CRS origin so they
    line up across areas (output size unchanged; a resumed pre-1.7.0 WMS job keeps
    its tiles and is not re-downloaded). The Message Log shows a growing progress
    bar (0...10...20...100). Fixes: a download could be garbage-collected and
    silently do nothing before it started; the completion/cancel message now
    appears immediately instead of on the next run; resuming a pre-1.7.0 WMS job
    no longer errors.
    1.6.0 - Removed the "polite mode" macro-cell features (Stop after N
    tiles, Rest after each macro-cell, and the 8x8 fetch ordering). Tiles fetch
    in natural order; the adaptive throttle, minimum delay, give-up threshold and
    resumable cache still handle rate-limited and daily-quota servers (run, stop,
    resume the next day).
    1.5.4 - Warn when the extent comes from a layer with more than one
    feature: its bounding box spans all of them, so a stray/unwanted feature can
    silently enlarge the download area (e.g. a vertex near 0,0 in EPSG:3857
    dropping the South to 0).
    1.5.3 - Resuming a job no longer prompts to confirm the large download
    or to overwrite the output file (those prompts still appear for a new or
    changed export).
    1.5.2 - Per-tile success is logged to download.log only (DEBUG), not
    to the QGIS Message Log panel, so a large run no longer floods and truncates
    the panel. The periodic Checkpoint line stays the panel's progress indicator.
    1.5.1 - Declare QGIS 4 support via qgisMaximumVersion=4.99 and drop the
    deprecated supportsQt6 flag (QGIS 4 eligibility is now taken from
    qgisMaximumVersion).
    1.5.0 - QGIS 4 / Qt 6 support: the plugin now runs on QGIS 4.2 as well
    as QGIS 3.40+ from a single codebase (scoped Qt enums).
    Note QGIS 4 uses a separate profile root (see the README install notes).
    1.4.22 - Fully-transparent tiles are kept and mosaicked like any other
    tile. The cache stores relative file paths, so a job folder can be
    moved/restored elsewhere and still resume (existing absolute-path caches
    still work). GeoTIFF exports at its true native resolution. Fixes: resuming
    no longer re-requests known-empty tiles (saves a quota tile); stopping on the
    per-run budget or cancel keeps the in-flight fetches instead of re-fetching;
    the inter-cell rest only fires on forward progress.
    1.4.21 - A local raster (GeoTIFF) is read/exported, not downloaded, and
    the wording now reflects that (the Task Manager entry reads "Basemap raster
    export"; the log and message bar say read/export). Dialog tweaks: the
    tile-count estimate sits with the size controls (under the Zoom level for
    XYZ), and Reproject sampling now comes before Output CRS. Refreshed the
    screenshot and README.
    1.4.20 - Dialog reorganized into collapsible groups (Extent + crop,
    Tile size & resolution, Output). For a GeoTIFF source the Tile size &
    resolution group is collapsed and greyed (it exports at native resolution),
    and the Advanced options and tile-count estimate are greyed out. New
    confirmation prompt before overwriting an existing output file.
    1.4.19 - Auto-migrate a pre-1.4.18 flat cache into the new per-job
    folder on the next run of the same job, so an interrupted download resumes
    without re-downloading.
    1.4.18 - Polite mode for rate-limited servers: tiles are fetched by
    walking an 8x8 grid of macro-cells (so an interrupted run leaves a contiguous
    area), a new "Stop after N tiles this run" budget lets you fill a daily-quota
    server over several days via resume, and an optional rest after each cell
    eases short-term burst limits. Each job now caches in its own subdirectory,
    so a different download no longer wipes an in-progress one.
    1.4.17 - Added a "Reset to defaults" button to the Advanced options.
    Removed the non-functional "Draw on Canvas" button from the extent selector.
    1.4.16 - Removed the .flake8 config from the plugin package (a hidden
    file inside the package is flagged as suspicious). It stays at the repo root
    for local dev and CI only.
    1.4.15 - Ship the .flake8 config inside the plugin package so the QGIS
    Plugin Repository's Flake8 Code Quality check honours it. Added bandit
    (security) and detect-secrets scanning to the CI check-in.
    1.4.14 - Flake8 code-quality cleanups (renamed an ambiguous loop
    variable, fixed inline-comment and comma spacing) plus a .flake8 config
    documenting the plugin's intentional compact style. No behavior change.
    1.4.13 - Hardened parsing of remote WMS/WMTS GetCapabilities and
    ServiceException XML against entity-expansion (billion laughs) and
    external-entity (XXE) attacks, via a dependency-free safe parser. No change
    for valid responses (WMS 1.1.1 DOCTYPEs still parse).
    1.4.12 - Added a LICENSE file inside the plugin package, required by
    the QGIS Plugin Repository.
    1.4.11 - Fixed metadata.txt so it parses on the QGIS Plugin Repository
    (removed literal percent signs the repository's parser rejected).
    1.4.10 - First public release on the QGIS Plugin Repository.
    1.4.9 - A message-bar notice appears when the fetch phase ends and the
    mosaic build begins ("All tiles fetched — building the GeoTIFF mosaic…"), so
    the completed progress bar isn't mistaken for a stall. Declared the plugin license
    (GPL-3.0-or-later) in metadata.
    1.4.8 - Renamed the cache folder btd_cache/ to __btdcache__/
    (Python __pycache__ style). Clearer mosaic-build error messages. The WMTS
    zoom control shows a tile-matrix index instead of a misleading m/px figure.
    README refreshed (Advanced back-off/give-up options, circuit breaker, log
    panel, sync.ps1).
    1.4.7 - The task progress bar no longer sits frozen at the last
    fetch percentage while the mosaic is built, including after a
    cancel. It jumps to the end when the fetch phase ends and clears once done.
    1.4.6 - A resumed run no longer grinds for hours when a provider
    refuses a block of tiles (every request failing with the throttle pinned at
    its cap). A run-level circuit breaker stops after ~10 min of no successes,
    builds a partial mosaic, and leaves the rest pending for a later re-run. New
    Advanced options: back-off cap, and give-up threshold (0 = never).
    1.4.5 - Starting a download now raises QGIS's Log Messages panel (the
    Basemap Tile Downloader tab) so the live run log is visible without hunting.
    1.4.4 - Moved the menu entry from Web to Raster (category is now
    Raster). Added a note that the plugin is for personal/educational use only and
    to respect provider Terms of Service, plus a Q&A on NaN extents from
    "Calculate from Layer" (a layer CRS mismatch — reproject that layer).
    1.4.3 - New "Minimum delay between requests" advanced option (default
    0). The mosaic is now always built from whatever downloaded, including after a
    cancel, so gaps show which tiles are missing. Persistently-broken tiles give
    up faster (back-pressure budget 8, backoff cap 30s).
    1.4.2 - WMS ServiceExceptions (transient server draw failures) are now
    retried with back-off on the back-pressure budget instead of failing fast, so
    intermittent provider glitches recover far more often. Repeated error messages
    in the log are collapsed (full once, then "repeat xN", with an end-of-run
    tally).
    1.4.1 - The dialog title bar now shows the plugin version (and, from a
    git checkout, the short commit hash).
    1.4.0 - Local raster (GeoTIFF/GDAL) layers can now be used as the
    source: read over the extent and reprojected/cropped like the tile sources
    (single-band rasters keep their nodata instead of gaining an alpha band).
    A resumed run re-fetches 'done' tiles whose cached file went missing. Clearer
    end-of-run log ("Queue drained: N of M …", a warning when tiles failed).
    1.3.2 - download.log is truncated at the start of each run (no longer
    grows unbounded). Server rate-limiting is now logged explicitly (reason,
    HTTP status, Retry-After, new pacing, and back-pressure retry count).
    1.3.1 - Dialog remembers and restores the last-used extent. Extent
    widget shown as separate, clearly-labelled fields (readable with a comma
    decimal separator) in a collapsible group. Throttle/timeout responses retried
    on a separate budget and a server Retry-After is honoured, so rate-limiting no
    longer fails good tiles. Suppressed QGIS's redundant task-ended notification.
    Cache folder renamed to btd_cache/.
    1.3.0 - Raised the minimum QGIS to 3.40.8. Fixed request timeouts
    (now honoured and retried instead of being mistaken for empty tiles) and
    Retry-After date parsing. WMTS shows the large-download/ToS confirmation;
    XYZ zoom is clamped to the layer's range. Moved "Crop output to the exact
    extent" up under the extent selector. Renamed the per-job working folder to
    basemap_tile_downloader/ (an interrupted aoi_download/ run won't auto-resume).
    1.2.1 - Renamed the plugin package folder to basemap_tile_downloader
    (the installed plugin id changed to match).
    1.2.0 - Renamed to Basemap Tile Downloader. Download area is now a
    rectangular extent selector (was an AOI polygon layer). Configurable parallel
    downloads and max attempts in a collapsible Advanced section; re-runs retry
    previously-failed tiles.
    1.1.1 - Terms-of-Service reminder on large downloads; XYZ resolution
    label reported at the AOI latitude.
    1.1.0 - WMTS source backend; optional clip-to-AOI-polygon (cutline);
    release-zip automation; ruff lint and more unit tests.
    1.0.0 - Combined WMS + XYZ download to clipped GeoTIFF: auto-detected source,
    resumable queue, adaptive per-source throttling, parallel fetching, GDAL
    mosaic with selectable resampling/optional reprojection, tile-count estimate,
    and completion feedback. See CHANGELOG.md for details.
