From e1bc41f5014565d1f3a2f26deccce1932fbd24fd Mon Sep 17 00:00:00 2001 From: Eltrac Date: Tue, 21 Oct 2025 11:12:16 +0800 Subject: chore(CI/CD): rewrite pre-build Python scripts with Go Former-commit-id: fbd878474f1af38605090307571c03b8409a077c --- scripts/analyze_links.py | 170 ----------------------------------------------- 1 file changed, 170 deletions(-) delete mode 100644 scripts/analyze_links.py (limited to 'scripts/analyze_links.py') diff --git a/scripts/analyze_links.py b/scripts/analyze_links.py deleted file mode 100644 index 8364100e..00000000 --- a/scripts/analyze_links.py +++ /dev/null @@ -1,170 +0,0 @@ -import os -import re -import json -from urllib.parse import urlparse -from collections import Counter - -content_dir = "content" -internal_link_pattern = re.compile(r"\[[^\]]*\]\((/[^)]+)\)") -markdown_link_re = re.compile(r"\[.*?\]\((http.*?)\)") - -url_map = {} # file path -> canonical url -alias_map = {} # alias url -> canonical url -link_graph = {} # canonical url -> list of canonical urls -title_map = {} # canonical url -> title -external_links = Counter() - -def parse_frontmatter(filepath): - with open(filepath, encoding="utf-8") as f: - lines = f.readlines() - - if not lines or lines[0].strip() != "---": - return {}, 0 - - frontmatter = {} - aliases, related_cards, mentioned_books = [], [], [] - slug, draft, title = None, False, None - i = 1 - while i < len(lines): - line = lines[i].strip() - if line == "---": - break - if ":" in line: - key, value = line.split(":", 1) - key = key.strip() - value = value.strip().strip('"').strip("'") - - if key == "aliases": - aliases = [] - i += 1 - while i < len(lines) and lines[i].startswith(" - "): - aliases.append(lines[i].strip()[3:].strip()) - i += 1 - continue - elif key == "slug": - slug = value - elif key == "draft": - draft = value.lower() == "true" - elif key == "title": - title = value - elif key == "related_cards": - related_cards = [] - i += 1 - while i < len(lines) and lines[i].strip().startswith("- "): - related_cards.append(lines[i].strip()[2:].strip()) - i += 1 - continue - elif key == "mentioned_books": - mentioned_books = [] - i += 1 - while i < len(lines) and lines[i].strip().startswith("- "): - mentioned_books.append(lines[i].strip()[2:].strip()) - i += 1 - continue - i += 1 - - return { - "slug": slug, - "aliases": aliases, - "draft": draft, - "title": title, - "related_cards": related_cards, - "mentioned_books": mentioned_books - }, i + 1 - -def get_canonical_url(filepath, frontmatter): - rel_path = os.path.relpath(filepath, content_dir) - dirname, filename = os.path.split(rel_path) - name = os.path.splitext(filename)[0].lower() - slug = frontmatter.get("slug") or name - parts = dirname.split(os.sep) - return f"/{'/'.join(parts)}/{slug}/" if parts != [""] else f"/{slug}/" - -def resolve_url(url): - return alias_map.get(url, url) - -def resolve_url_from_dir(link, subdir): - target_dir = os.path.join(content_dir, subdir) - for path, canonical in url_map.items(): - if path.startswith(target_dir): - name = os.path.splitext(os.path.basename(path))[0] - if name == link: - return canonical - return None - -def get_icon(url): - if url.startswith("/cards/"): return "📄" - if url.startswith("/posts/"): return "📜" - if url.startswith("/library/"): return "📖" - if url.startswith("/fictions/"): return "🧙‍♀️" - if url.startswith("/en/"): return "🇬🇧" - return "📁" - -def collect_urls(): - for root, _, files in os.walk(content_dir): - for file in files: - if not file.endswith(".md") or file == "_index.md": - continue - path = os.path.join(root, file) - frontmatter, _ = parse_frontmatter(path) - if frontmatter.get("draft"): - continue - - canonical_url = get_canonical_url(path, frontmatter) - url_map[path] = canonical_url - link_graph[canonical_url] = [] - title = frontmatter.get("title") or canonical_url.strip("/").split("/")[-1] - title_map[canonical_url] = f"{get_icon(canonical_url)} {title}" - - for alias in frontmatter.get("aliases", []): - alias_map[alias] = canonical_url - -def build_link_graph_and_external_links(): - for path, canonical_url in url_map.items(): - with open(path, encoding="utf-8") as f: - content = f.read() - - # 内部链接 - for match in internal_link_pattern.finditer(content): - link = match.group(1) - normalized = resolve_url(link) - if normalized and normalized in link_graph: - link_graph[canonical_url].append(normalized) - - # 外部链接 - for match in markdown_link_re.findall(content): - domain = urlparse(match).netloc - if domain and domain not in {"image.guhub.cn", "www.geedea.pro"}: - external_links[domain] += 1 - - # 相关卡片和图书 - frontmatter, _ = parse_frontmatter(path) - for card in frontmatter.get("related_cards", []): - target = resolve_url_from_dir(card, "cards") - if target and target in link_graph: - link_graph[canonical_url].append(target) - for book in frontmatter.get("mentioned_books", []): - target = resolve_url_from_dir(book, "library") - if target and target in link_graph: - link_graph[canonical_url].append(target) - -def main(): - collect_urls() - build_link_graph_and_external_links() - - # 写入内部链接图 - os.makedirs("public", exist_ok=True) - nodes = [{"id": url, "label": title_map[url], "url": url} for url in link_graph] - edges = [{"from": src, "to": tgt} for src, targets in link_graph.items() for tgt in targets] - with open("public/link-graph.json", "w", encoding="utf-8") as f: - json.dump({"nodes": nodes, "edges": edges}, f, indent=2, ensure_ascii=False) - print("✅ Link graph generated: public/link-graph.json") - - # 写入外部链接统计 - os.makedirs("data", exist_ok=True) - with open("data/externallinks.json", "w", encoding="utf-8") as f: - json.dump(external_links.most_common(), f, indent=2, ensure_ascii=False) - print("✅ External link data written to data/externallinks.json") - -if __name__ == "__main__": - main() -- cgit v1.2.3