Skip to content

Instantly share code, notes, and snippets.

@reagle
Created April 2, 2026 20:11
Show Gist options
  • Select an option

  • Save reagle/aa1b68c86c73aee14f59bfafe9d6274c to your computer and use it in GitHub Desktop.

Select an option

Save reagle/aa1b68c86c73aee14f59bfafe9d6274c to your computer and use it in GitHub Desktop.
Search markdown files and update deprecated Wikimedia image sizes.
#!/usr/bin/env -S uv run
# /// script
# requires-python = ">=3.13"
# dependencies = []
# ///
"""Search markdown files and update deprecated Wikimedia image sizes."""
import argparse
import re
import sys
from pathlib import Path
STANDARD_WIDTHS = [330, 500, 960, 1280, 1920, 3840]
WIKI_THUMB_RE = re.compile(
r"(https://upload\.wikimedia\.org/wikipedia/commons/thumb/(?:[^/]+/){3})(\d+)(px-[^\s)\]\"]+)"
)
def process_file(file_path: Path, dry_run: bool) -> None:
"""Read file, calculate width updates, print changes, and optionally write."""
content = file_path.read_text(encoding="utf-8")
changes: list[tuple[int, int, str]] = []
def snap_width(match: re.Match) -> str:
base_url = match.group(1)
current_width = int(match.group(2))
suffix = match.group(3)
nearest = min(STANDARD_WIDTHS, key=lambda x: abs(x - current_width))
new_url = f"{base_url}{nearest}{suffix}"
if current_width != nearest:
changes.append((current_width, nearest, new_url))
return new_url
updated_content = WIKI_THUMB_RE.sub(snap_width, content)
if changes:
print(f"Updated {len(changes)} links in {file_path}")
for old_w, new_w, new_url in changes:
print(f" {old_w}px to {new_w}px : {new_url}")
if not dry_run:
file_path.write_text(updated_content, encoding="utf-8")
def process_args(argv: list[str] | None = None) -> argparse.Namespace:
"""Parse command-line arguments."""
parser = argparse.ArgumentParser(
description="Fix Wikimedia thumbnail widths in markdown files."
)
parser.add_argument("directories", nargs="+", type=Path, help="Directories to scan")
parser.add_argument(
"--dry-run", action="store_true", help="Print changes without saving"
)
return parser.parse_args(argv)
def main() -> None:
"""Entry point."""
args = process_args()
for directory in args.directories:
target_dir = directory.expanduser()
if not target_dir.is_dir():
print(f"Warning: {target_dir} is not a valid directory.", file=sys.stderr)
continue
for file_path in target_dir.rglob("*.md"):
process_file(file_path, args.dry_run)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment