Pi66

merodi
A markdown-based static site generator.
git clone https://git.pi66.xyz/merodi

← back to log

fix: resolve local IPs for the HTTP server

author: pi66
date: 2026-07-02 21:43
hash: 5df83c3337bb8e2a1e65c5d08f389e736c80386c

Diffstat:

M

pyproject.toml
1 +

M

src/webviewer.py
45 +++++++++++++++++++++++-------
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
diff --git a/pyproject.toml b/pyproject.toml
index 12e8fa4..412ef03 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -13,6 +13,7 @@ dependencies = [
    "pymdown-extensions",
    "latex2mathml",
    "pygments",
+   "ifaddr",
 ]

 [project.scripts]
diff --git a/src/webviewer.py b/src/webviewer.py
index 8e79663..9d24ad8 100644
--- a/src/webviewer.py
+++ b/src/webviewer.py
@@ -1,17 +1,35 @@
 from os import getcwd, path
 from http.server import HTTPServer, SimpleHTTPRequestHandler
 from threading import Thread
-from watchdog.observers import Observer
-from watchdog.events import FileSystemEventHandler
 import webview
-import time

 from .config import find_project_from_path, load_extras_config, load_tree_config, load_webview_config
 from .errors import fatal, html_fatal
-from .build import compile_md_to_html
 from .watcher import watch_files 
-from .log import die, info, warn
-
+from .log import info, warn
+import ifaddr
+import socket
+
+_ip_cache: list[str] = []
+
+import ifaddr
+
+def resolve_ips(host: str, port: int) -> list[str]:
+    global _ip_cache
+    if host != "0.0.0.0":
+        _ip_cache = [host]
+    elif not _ip_cache:
+        _ip_cache = [
+            ip_str
+            for adapter in ifaddr.get_adapters()
+            for ip in adapter.ips
+            if ip.is_IPv4
+            and (ip_str := str(ip.ip))
+            and not ip_str.startswith("127.")
+            and not ip_str.startswith("169.254.")
+        ] or ["127.0.0.1"]
+
+    return _ip_cache

 def http_server(host, port, routes):
     class Handler(SimpleHTTPRequestHandler):
@@ -61,15 +79,16 @@ def http_server(host, port, routes):
     server = HTTPServer((host, port), Handler)
     return server

-def reload_webview(window, url, webview_config):
+def reload_webview(window, url, host, port):
     try:
-        window.load_url(f"http://{webview_config.host}:{webview_config.port}/{url}")
+        window.load_url(f"http://{host}:{port}/{url}")
     except Exception as e:
         window.load_url(f"data:text/html,{html_fatal(e, f'Failed to reload {url}')}")
         warn(str(e))

 def run(project_path):
     try:
+        global _ip_cache
         project_path = project_path if project_path else getcwd()
         find_project_from_path(project_path)
         webview_config = load_webview_config(project_path)
@@ -91,12 +110,16 @@ def run(project_path):
         server = http_server(host, port, routes)
         server_thread = Thread(target=server.serve_forever, daemon=True)
         server_thread.start()
-        info(f"HTTP SERVER STARTS: http://{host}:{port}")
+        _ip_cache = resolve_ips(host, port)
+        info(f"HTTP SERVER STARTS ON:")
+        for ip in _ip_cache:
+            info(f"  IP: http://{ip}:{port}")
+        print()

-        window = webview.create_window("Merodi", url=f"http://{host}:{port}/")
+        window = webview.create_window("Merodi", url=f"http://{_ip_cache[0]}:{port}/")
         observer = watch_files(
                 tree_config, extras_config,
-                lambda path: reload_webview(window, path, webview_config),
+                lambda path: reload_webview(window, path, _ip_cache[0], port),
                 )
         observer.start()
         webview.start(debug=webview_config.dev_tools in ["true",1])