From f31c7a28b74ab7e4477d1d6d206de6fc93bbf273 Mon Sep 17 00:00:00 2001 From: Kanahiro Date: Sun, 25 Jan 2026 22:19:38 +0900 Subject: [PATCH 1/5] fix: mbtiles metadata --- tileget/__main__.py | 60 ++++++++++++++++++++++++++++----------------- tileget/arg.py | 7 ++++++ 2 files changed, 44 insertions(+), 23 deletions(-) diff --git a/tileget/__main__.py b/tileget/__main__.py index 6ce1a2f..5e1174a 100644 --- a/tileget/__main__.py +++ b/tileget/__main__.py @@ -45,6 +45,20 @@ async def acquire(self) -> bool: return True +def normalize_format(ext: str, default: str | None = None) -> str: + """拡張子をMBTiles仕様のformat値に正規化""" + ext = ext.lower().lstrip(".") + if not ext: + if default is None: + raise ValueError("format must be specified when url has no extension") + return normalize_format(default) + if ext in ("jpeg", "jpg"): + return "jpg" + if ext in ("mvt", "pbf"): + return "pbf" + return ext + + def is_retryable_error(e: Exception) -> bool: if isinstance(e, httpx.TimeoutException): return True @@ -184,7 +198,7 @@ def create_mbtiles(output_file: str): c.execute( """ CREATE TABLE metadata ( - name TEXT, + name TEXT PRIMARY KEY, value TEXT ) """ @@ -232,32 +246,32 @@ def handle_sigint(): conn = None if params.mode == "mbtiles": - if not os.path.exists(params.output_path): + is_new = not os.path.exists(params.output_path) + if is_new: create_mbtiles(params.output_path) conn = sqlite3.connect(params.output_path, check_same_thread=False) - c = conn.cursor() - c.execute( - "INSERT INTO metadata (name, value) VALUES (?, ?)", - ("name", os.path.basename(params.output_path)), - ) - c.execute( - "INSERT INTO metadata (name, value) VALUES (?, ?)", - ( - "format", - os.path.splitext(params.tileurl.split("?")[0])[-1].replace(".", ""), - ), - ) - c.execute( - "INSERT INTO metadata (name, value) VALUES (?, ?)", - ("minzoom", params.minzoom), - ) - c.execute( - "INSERT INTO metadata (name, value) VALUES (?, ?)", - ("maxzoom", params.maxzoom), - ) - conn.commit() + if is_new: + ext = os.path.splitext(params.tileurl.split("?")[0])[-1] + c = conn.cursor() + c.execute( + "INSERT INTO metadata (name, value) VALUES (?, ?)", + ("name", os.path.basename(params.output_path)), + ) + c.execute( + "INSERT INTO metadata (name, value) VALUES (?, ?)", + ("format", normalize_format(ext, params.format)), + ) + c.execute( + "INSERT INTO metadata (name, value) VALUES (?, ?)", + ("minzoom", params.minzoom), + ) + c.execute( + "INSERT INTO metadata (name, value) VALUES (?, ?)", + ("maxzoom", params.maxzoom), + ) + conn.commit() tilescheme = ( tiletanic.tileschemes.WebMercatorBL() diff --git a/tileget/arg.py b/tileget/arg.py index 02212a2..8e37b74 100644 --- a/tileget/arg.py +++ b/tileget/arg.py @@ -21,6 +21,7 @@ class RunParams: tms: bool retries: int retry_delay: float + format: str | None def parse_arg() -> RunParams: @@ -73,6 +74,11 @@ def positive_int(value: str) -> int: type=float, help="base delay in seconds for exponential backoff, default to 1.0", ) + parser.add_argument( + "--format", + type=str, + help="tile format for mbtiles metadata (e.g. png, jpg, pbf). used when url has no extension", + ) args = parser.parse_args() if args.output_dir is None and args.output_file is None: @@ -131,6 +137,7 @@ def positive_int(value: str) -> int: tms=args.tms, retries=args.retries, retry_delay=args.retry_delay, + format=args.format, ) return params From 55371f6d2e2b5f69516d3575e9b0c7916e05dac2 Mon Sep 17 00:00:00 2001 From: Kanahiro Date: Sun, 25 Jan 2026 22:26:31 +0900 Subject: [PATCH 2/5] fix: mvt mbtiles gzip --- tileget/__main__.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tileget/__main__.py b/tileget/__main__.py index 5e1174a..aa07836 100644 --- a/tileget/__main__.py +++ b/tileget/__main__.py @@ -1,4 +1,5 @@ import asyncio +import gzip import os import random import signal @@ -179,6 +180,11 @@ async def download_mbtiles( if data is None: return + # MVT(pbf)はgzip圧縮して保存する必要がある + ext = os.path.splitext(tileurl.split("?")[0])[-1].lower().lstrip(".") + if ext in ("mvt", "pbf") and data[:2] != b"\x1f\x8b": + data = gzip.compress(data) + if overwrite: c.execute( "DELETE FROM tiles WHERE zoom_level = ? AND tile_column = ? AND tile_row = ?", From c74efce2c6cc43c924b8da0c6003618c596bed2b Mon Sep 17 00:00:00 2001 From: Kanahiro Date: Sun, 25 Jan 2026 22:26:49 +0900 Subject: [PATCH 3/5] 1.0.1 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index e61f2a5..b6dea07 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "tileget" -version = "1.0.0" +version = "1.0.1" description = "Tile download utility - easily download xyz-tile data" readme = "README.md" requires-python = ">= 3.14" From 10e09e11b2b636c183aac46234ab30d4e809ecbc Mon Sep 17 00:00:00 2001 From: Kanahiro Date: Sun, 25 Jan 2026 22:27:40 +0900 Subject: [PATCH 4/5] format --- tileget/arg.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tileget/arg.py b/tileget/arg.py index 8e37b74..d0f645d 100644 --- a/tileget/arg.py +++ b/tileget/arg.py @@ -40,6 +40,7 @@ def parse_arg() -> RunParams: ) parser.add_argument("--minzoom", default=0, type=int, help="default to 0") parser.add_argument("--maxzoom", default=16, type=int, help="default to 16") + def positive_int(value: str) -> int: ivalue = int(value) if ivalue <= 0: From 0d2b614efafb251e196985ecb517ed62f265f268 Mon Sep 17 00:00:00 2001 From: Kanahiro Date: Sun, 25 Jan 2026 22:28:41 +0900 Subject: [PATCH 5/5] fix --- uv.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uv.lock b/uv.lock index 633a92b..57b0657 100644 --- a/uv.lock +++ b/uv.lock @@ -212,7 +212,7 @@ wheels = [ [[package]] name = "tileget" -version = "1.0.0" +version = "1.0.1" source = { editable = "." } dependencies = [ { name = "httpx" },