信捷PLCSkill
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

73 lines
2.4 KiB

  1. import argparse
  2. import csv
  3. import pathlib
  4. import re
  5. import sys
  6. from download_xinje_file import request, quote_url
  7. import urllib.request
  8. INVALID_FILENAME_CHARS = r'<>:"/\|?*'
  9. def clean_filename(value: str) -> str:
  10. value = "".join("_" if ch in INVALID_FILENAME_CHARS else ch for ch in value)
  11. value = re.sub(r"\s+", " ", value).strip(" .")
  12. return value or "xinje-download"
  13. def build_filename(row: dict[str, str]) -> str:
  14. base = row.get("download_name") or row.get("title") or row["id"]
  15. base = clean_filename(base)
  16. version = clean_filename(row.get("version") or "")
  17. update_date = clean_filename(row.get("update_date") or "")
  18. suffix_parts = []
  19. if version:
  20. suffix_parts.append(f"v{version}")
  21. if update_date:
  22. suffix_parts.append(update_date)
  23. suffix = f" ({', '.join(suffix_parts)})" if suffix_parts else ""
  24. extension = (row.get("file_type") or "pdf").lower().lstrip(".")
  25. return f"{base}{suffix}.{extension}"
  26. def load_rows(catalog: pathlib.Path) -> dict[str, dict[str, str]]:
  27. with catalog.open("r", encoding="utf-8-sig", newline="") as handle:
  28. return {row["id"]: row for row in csv.DictReader(handle)}
  29. def download(row: dict[str, str], output_dir: pathlib.Path, skip_existing: bool) -> pathlib.Path:
  30. output = output_dir / build_filename(row)
  31. if output.exists() and skip_existing:
  32. print(f"skip existing {row['id']}: {output}")
  33. return output
  34. url = quote_url(row["url"])
  35. output.parent.mkdir(parents=True, exist_ok=True)
  36. with urllib.request.urlopen(request(url), timeout=120) as response:
  37. output.write_bytes(response.read())
  38. print(f"downloaded {row['id']}: {output} ({output.stat().st_size} bytes)")
  39. return output
  40. def main() -> None:
  41. parser = argparse.ArgumentParser(description="Download Xinje catalog files by ID.")
  42. parser.add_argument("--catalog", required=True, type=pathlib.Path)
  43. parser.add_argument("--output-dir", required=True, type=pathlib.Path)
  44. parser.add_argument("--ids", required=True, nargs="+")
  45. parser.add_argument("--overwrite", action="store_true")
  46. args = parser.parse_args()
  47. rows = load_rows(args.catalog)
  48. missing = [item for item in args.ids if item not in rows]
  49. if missing:
  50. raise SystemExit(f"catalog IDs not found: {', '.join(missing)}")
  51. for item in args.ids:
  52. download(rows[item], args.output_dir, skip_existing=not args.overwrite)
  53. if __name__ == "__main__":
  54. sys.exit(main())