60 lines
2.0 KiB
Python
60 lines
2.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""一次性脚本:把前端 CDN 资源下载到 public/vendor/,实现完全本地化。"""
|
|
import os, re, sys, urllib.request, urllib.parse
|
|
|
|
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
VENDOR = os.path.join(ROOT, "public", "vendor")
|
|
os.makedirs(VENDOR, exist_ok=True)
|
|
|
|
UA = {"User-Agent": "Mozilla/5.0"}
|
|
|
|
def download(url, dest):
|
|
req = urllib.request.Request(url, headers=UA)
|
|
with urllib.request.urlopen(req, timeout=30) as r:
|
|
data = r.read()
|
|
with open(dest, "wb") as f:
|
|
f.write(data)
|
|
print(f" {os.path.relpath(dest, ROOT)} ({len(data)} B)")
|
|
return data
|
|
|
|
def main():
|
|
print("下载 Bootstrap CSS...")
|
|
download(
|
|
"https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css",
|
|
os.path.join(VENDOR, "bootstrap.min.css"),
|
|
)
|
|
|
|
print("下载 Bootstrap Icons CSS...")
|
|
css = download(
|
|
"https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css",
|
|
os.path.join(VENDOR, "bootstrap-icons.css"),
|
|
).decode("utf-8", "ignore")
|
|
|
|
# 找出字体 url 并本地化
|
|
CSS_URL = "https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css"
|
|
urls = re.findall(r'url\(["\']?([^"\')]+)["\']?\)', css)
|
|
for u in set(urls):
|
|
if u.startswith("data:"):
|
|
continue
|
|
full = urllib.parse.urljoin(CSS_URL, u)
|
|
fname = os.path.basename(full.split("?")[0])
|
|
print(f"下载字体 {fname}...")
|
|
download(full, os.path.join(VENDOR, fname))
|
|
css = css.replace(u, "./" + fname)
|
|
|
|
with open(os.path.join(VENDOR, "bootstrap-icons.css"), "w", encoding="utf-8") as f:
|
|
f.write(css)
|
|
print(" 已重写 bootstrap-icons.css 字体路径")
|
|
|
|
print("下载 SortableJS...")
|
|
download(
|
|
"https://cdn.jsdelivr.net/npm/sortablejs@1.15.0/Sortable.min.js",
|
|
os.path.join(VENDOR, "Sortable.min.js"),
|
|
)
|
|
|
|
print("\n完成。vendor 目录:")
|
|
for f in sorted(os.listdir(VENDOR)):
|
|
print(" ", f)
|
|
|
|
if __name__ == "__main__":
|
|
main() |