-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild.py
More file actions
128 lines (109 loc) · 5.01 KB
/
build.py
File metadata and controls
128 lines (109 loc) · 5.01 KB
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import sys
from bs4 import BeautifulSoup
import os
import base64
import mimetypes
import re
EXTENSIONS_TO_INLINE = [
'.js', '.css', '.png', '.jpg', '.jpeg', '.gif', '.svg',
'.mp3', '.wav', '.mp4', '.woff', '.woff2', '.json', '.manifest'
]
def file_to_data_uri(path, mime_override=None):
if not os.path.isfile(path):
return False
mime, _ = mimetypes.guess_type(path)
if mime_override:
mime = mime_override
with open(path, "rb") as f:
file_data = f.read()
encoded_data = base64.b64encode(file_data).decode("utf-8")
return f"data:{mime};base64,{encoded_data}"
def inline_html(input_file, output_file=None):
base_dir = os.path.dirname(os.path.abspath(input_file))
if not output_file:
name, ext = os.path.splitext(input_file)
output_file = f"webotp.html"
with open(input_file, "r", encoding="utf-8") as f:
soup = BeautifulSoup(f, "html.parser")
# Scripts
for script in soup.find_all("script", src=True):
src_path = os.path.join(base_dir, script["src"])
if os.path.exists(src_path):
with open(src_path, "r", encoding="utf-8") as s:
code = s.read()
def replace_js_match(match):
path = match.group(2)
if path.startswith("data:") or "://" in path:
return match.group(0)
if not any(path.lower().endswith(ext) for ext in EXTENSIONS_TO_INLINE):
return match.group(0)
abs_path = os.path.join(base_dir, path)
if os.path.exists(abs_path):
mime, _ = mimetypes.guess_type(abs_path)
if path.lower().endswith('.js'):
mime = "text/javascript"
return f'{match.group(1)}{file_to_data_uri(abs_path, mime_override=mime)}{match.group(1)}'
return match.group(0)
code = re.sub(r'(["\'])(.+?)\1', replace_js_match, code)
script.clear()
script.string = code
del script["src"]
for script in soup.find_all("script", src=False):
if script.string:
def replace_inline_js(match):
path = match.group(2)
if path.startswith("data:") or "://" in path:
return match.group(0)
if not any(path.lower().endswith(ext) for ext in EXTENSIONS_TO_INLINE):
return match.group(0)
abs_path = os.path.join(base_dir, path)
if os.path.exists(abs_path):
mime, _ = mimetypes.guess_type(abs_path)
if path.lower().endswith('.js'):
mime = "text/javascript"
return f'{match.group(1)}{file_to_data_uri(abs_path, mime_override=mime)}{match.group(1)}'
return match.group(0)
script.string = re.sub(r'(["\'])(.+?)\1', replace_inline_js, script.string)
# Styles
for link in soup.find_all("link", rel="stylesheet", href=True):
css_path = os.path.join(base_dir, link["href"])
if os.path.exists(css_path):
with open(css_path, "r", encoding="utf-8") as c:
css_code = c.read()
def replace_css_match(match):
url = match.group(1).strip(' \'"')
if url.startswith("data:") or "://" in url:
return f"url({url})"
abs_path = os.path.join(base_dir, url)
if os.path.exists(abs_path):
return f"url({file_to_data_uri(abs_path)})"
return f"url({url})"
css_code = re.sub(r'url\(([^)]+)\)', replace_css_match, css_code)
style_tag = soup.new_tag("style")
style_tag.string = css_code
link.replace_with(style_tag)
# Media
for tag in soup.find_all(["img", "audio", "video", "source", "object", "embed"], src=True):
src_attr = "src" if tag.name != "object" and tag.name != "embed" else "data"
resource_path = os.path.join(base_dir, tag[src_attr])
if os.path.exists(resource_path):
tag[src_attr] = file_to_data_uri(resource_path)
# Other links
for link in soup.find_all("link", href=True):
href_path = os.path.join(base_dir, link["href"])
if os.path.exists(href_path):
mime, _ = mimetypes.guess_type(href_path)
if mime and (mime.startswith("image/") or mime.startswith("font/")):
link["href"] = file_to_data_uri(href_path)
for link in soup.find_all("link", rel="manifest", href=True):
manifest_path = os.path.join(base_dir, link["href"])
if os.path.exists(manifest_path):
link["href"] = file_to_data_uri(manifest_path, mime_override="application/manifest+json")
with open(output_file, "w", encoding="utf-8") as f:
f.write(str(soup))
if __name__ == "__main__":
if len(sys.argv) < 2:
input_file = "index.html"
else:
input_file = sys.argv[1]
inline_html(input_file)