77 lines
2.3 KiB
Python
77 lines
2.3 KiB
Python
#!/usr/bin/env python3
|
|
"""检查 Markdown 中引用的本地图片是否真实存在。"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
from pathlib import Path
|
|
import re
|
|
import sys
|
|
from typing import Iterable, List, Optional
|
|
from urllib.parse import urlparse
|
|
|
|
|
|
IMAGE_RE = re.compile(r"!\[[^\]]*\]\(([^)]+)\)")
|
|
|
|
|
|
def die(message: str, code: int = 1) -> None:
|
|
print(f"错误:{message}", file=sys.stderr)
|
|
raise SystemExit(code)
|
|
|
|
|
|
def normalize_target(raw: str) -> str:
|
|
value = raw.strip()
|
|
if value.startswith("<") and value.endswith(">"):
|
|
return value[1:-1].strip()
|
|
if " " in value:
|
|
value = value.split()[0]
|
|
return value.strip("'\"")
|
|
|
|
|
|
def is_remote_or_anchor(target: str) -> bool:
|
|
parsed = urlparse(target)
|
|
return bool(parsed.scheme in {"http", "https", "data", "mailto"} or target.startswith("#"))
|
|
|
|
|
|
def find_missing(markdown_path: Path) -> List[str]:
|
|
text = markdown_path.read_text(encoding="utf-8")
|
|
base_dir = markdown_path.parent
|
|
missing: List[str] = []
|
|
for match in IMAGE_RE.finditer(text):
|
|
target = normalize_target(match.group(1))
|
|
if not target or is_remote_or_anchor(target):
|
|
continue
|
|
image_path = Path(target)
|
|
if not image_path.is_absolute():
|
|
image_path = base_dir / image_path
|
|
if not image_path.exists():
|
|
missing.append(target)
|
|
return missing
|
|
|
|
|
|
def build_parser() -> argparse.ArgumentParser:
|
|
parser = argparse.ArgumentParser(description="检查 Markdown 本地图片路径是否存在。")
|
|
parser.add_argument("markdown", help="要检查的 article.md 或其他 Markdown 文件。")
|
|
return parser
|
|
|
|
|
|
def main(argv: Optional[Iterable[str]] = None) -> int:
|
|
parser = build_parser()
|
|
args = parser.parse_args(list(argv) if argv is not None else None)
|
|
markdown_path = Path(args.markdown).expanduser().resolve()
|
|
if not markdown_path.exists():
|
|
die(f"Markdown 文件不存在:{markdown_path}")
|
|
missing = find_missing(markdown_path)
|
|
result = {
|
|
"markdown": str(markdown_path),
|
|
"missing_count": len(missing),
|
|
"missing": missing,
|
|
}
|
|
print(json.dumps(result, ensure_ascii=False, indent=2))
|
|
return 1 if missing else 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|