|
| 1 | +#!/usr/bin/env python3 |
| 2 | +""" |
| 3 | +Generate HTML redirect files from redirects.json. |
| 4 | +
|
| 5 | +Usage: |
| 6 | + python generate_redirects.py |
| 7 | +
|
| 8 | +This script reads redirects.json and generates individual HTML files |
| 9 | +for each redirect path. Each HTML file uses meta refresh (0 delay) |
| 10 | +which is SEO-friendly and treated similarly to 301 redirects by Google. |
| 11 | +
|
| 12 | +To add new redirects, simply edit redirects.json and re-run this script. |
| 13 | +""" |
| 14 | + |
| 15 | +import json |
| 16 | +import os |
| 17 | +from pathlib import Path |
| 18 | + |
| 19 | +# Default fallback URL for any path not in the redirect map |
| 20 | +DEFAULT_REDIRECT = "https://docs.langchain.com/oss/python/langgraph/overview" |
| 21 | + |
| 22 | +HTML_TEMPLATE = """<!doctype html> |
| 23 | +<html lang="en"> |
| 24 | +<head> |
| 25 | + <meta charset="utf-8"> |
| 26 | + <title>Redirecting...</title> |
| 27 | + <link rel="canonical" href="{url}"> |
| 28 | + <meta name="robots" content="noindex"> |
| 29 | + <script>var anchor=window.location.hash.substr(1);location.href="{url}"+(anchor?"#"+anchor:"")</script> |
| 30 | + <meta http-equiv="refresh" content="0; url={url}"> |
| 31 | +</head> |
| 32 | +<body> |
| 33 | +Redirecting... |
| 34 | +</body> |
| 35 | +</html> |
| 36 | +""" |
| 37 | + |
| 38 | +ROOT_HTML_TEMPLATE = """<!doctype html> |
| 39 | +<html lang="en"> |
| 40 | +<head> |
| 41 | + <meta charset="utf-8"> |
| 42 | + <title>Redirecting to LangGraph Documentation</title> |
| 43 | + <link rel="canonical" href="{url}"> |
| 44 | + <meta name="robots" content="noindex"> |
| 45 | + <script>var anchor=window.location.hash.substr(1);location.href="{url}"+(anchor?"#"+anchor:"")</script> |
| 46 | + <meta http-equiv="refresh" content="0; url={url}"> |
| 47 | +</head> |
| 48 | +<body> |
| 49 | +<h1>Documentation has moved</h1> |
| 50 | +<p>The LangGraph documentation has moved to <a href="{url}">docs.langchain.com</a>.</p> |
| 51 | +<p>Redirecting you now...</p> |
| 52 | +</body> |
| 53 | +</html> |
| 54 | +""" |
| 55 | + |
| 56 | +CATCHALL_404_TEMPLATE = """<!doctype html> |
| 57 | +<html lang="en"> |
| 58 | +<head> |
| 59 | + <meta charset="utf-8"> |
| 60 | + <title>Redirecting to LangGraph Documentation</title> |
| 61 | + <link rel="canonical" href="{default_url}"> |
| 62 | + <meta name="robots" content="noindex"> |
| 63 | + <script> |
| 64 | + // Catchall redirect for any unmapped paths |
| 65 | + window.location.replace("{default_url}"); |
| 66 | + </script> |
| 67 | + <meta http-equiv="refresh" content="0; url={default_url}"> |
| 68 | +</head> |
| 69 | +<body> |
| 70 | +<h1>Documentation has moved</h1> |
| 71 | +<p>The LangGraph documentation has moved to <a href="{default_url}">docs.langchain.com</a>.</p> |
| 72 | +<p>Redirecting you now...</p> |
| 73 | +</body> |
| 74 | +</html> |
| 75 | +""" |
| 76 | + |
| 77 | + |
| 78 | +def generate_redirects(): |
| 79 | + script_dir = Path(__file__).parent |
| 80 | + output_dir = script_dir / "_site" |
| 81 | + |
| 82 | + # Load redirects |
| 83 | + with open(script_dir / "redirects.json") as f: |
| 84 | + redirects = json.load(f) |
| 85 | + |
| 86 | + # Clean output directory |
| 87 | + if output_dir.exists(): |
| 88 | + import shutil |
| 89 | + shutil.rmtree(output_dir) |
| 90 | + output_dir.mkdir(parents=True) |
| 91 | + |
| 92 | + # Generate individual HTML files for each redirect |
| 93 | + for old_path, new_url in redirects.items(): |
| 94 | + # Remove leading slash and create directory structure |
| 95 | + path = old_path.lstrip("/") |
| 96 | + |
| 97 | + # Check if path has a file extension (e.g., .txt, .xml) |
| 98 | + # If so, create the file directly instead of a directory with index.html |
| 99 | + path_obj = Path(path) |
| 100 | + has_extension = path_obj.suffix and len(path_obj.suffix) <= 5 |
| 101 | + |
| 102 | + if not path: |
| 103 | + html_path = output_dir / "index.html" |
| 104 | + elif has_extension: |
| 105 | + # For files with extensions, create the file directly |
| 106 | + html_path = output_dir / path |
| 107 | + else: |
| 108 | + # For directory-style URLs, create index.html inside |
| 109 | + html_path = output_dir / path / "index.html" |
| 110 | + |
| 111 | + # Create parent directories |
| 112 | + html_path.parent.mkdir(parents=True, exist_ok=True) |
| 113 | + |
| 114 | + # Write the redirect HTML |
| 115 | + html_path.write_text(HTML_TEMPLATE.format(url=new_url)) |
| 116 | + print(f"Created: {html_path}") |
| 117 | + |
| 118 | + # Create root index.html |
| 119 | + root_index = output_dir / "index.html" |
| 120 | + if not root_index.exists(): |
| 121 | + root_index.write_text(ROOT_HTML_TEMPLATE.format(url=DEFAULT_REDIRECT)) |
| 122 | + print(f"Created: {root_index}") |
| 123 | + |
| 124 | + # Create 404.html for catchall |
| 125 | + catchall_404 = output_dir / "404.html" |
| 126 | + catchall_404.write_text(CATCHALL_404_TEMPLATE.format(default_url=DEFAULT_REDIRECT)) |
| 127 | + print(f"Created: {catchall_404}") |
| 128 | + |
| 129 | + # Copy static files (like llms.txt) that can't be redirected via HTML |
| 130 | + static_files = ["llms.txt"] |
| 131 | + for static_file in static_files: |
| 132 | + src = script_dir / static_file |
| 133 | + if src.exists(): |
| 134 | + dst = output_dir / static_file |
| 135 | + dst.write_text(src.read_text()) |
| 136 | + print(f"Copied: {dst}") |
| 137 | + |
| 138 | + print(f"\nGenerated {len(redirects)} redirect files in {output_dir}") |
| 139 | + |
| 140 | + |
| 141 | +if __name__ == "__main__": |
| 142 | + generate_redirects() |
0 commit comments