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
#!/usr/bin/env python3
"""Replace the PattNG download-links card in the Aether tab with the in-app
update flow (3 new screenshots), per his order: links removed entirely."""
import base64, io, pathlib
from PIL import Image
SITE = pathlib.Path.home() / "workspace/foxyvpn-tutorial-site"
FILES = pathlib.Path.home() / "workspace/user/files"
p = SITE / "plain.html"
html = p.read_text(encoding="utf-8")
assert "PattNG_fdroid_2.3.13-P69" in html, "download card not found"
assert "Check for update" not in html.split('id="panel-aether"')[1], "update steps already present"
new_files = [
("1000045719_8_z0g8.jpg", "صفحه اصلی PattNG و علامت سهخط بالای صفحه"),
("1000045721_9_ff3e.jpg", "منوی PattNG و گزینه Check for update"),
("1000045723_10_0cto.jpg", "پیام پیدا شدن نسخه جدید و دکمه Update now"),
]
imgs = []
for fname, alt in new_files:
im = Image.open(FILES / fname).convert("RGB")
if im.width > 800:
im = im.resize((800, round(im.height * 800 / im.width)), Image.LANCZOS)
buf = io.BytesIO()
im.save(buf, "JPEG", quality=85, optimize=True)
imgs.append((f"data:image/jpeg;base64,{base64.b64encode(buf.getvalue()).decode()}", alt))
print(fname, "->", len(buf.getvalue()))
def shot(i):
src, alt = imgs[i]
return f' <div class="shot"><img src="{src}" alt="{alt}"></div>'
def step(num, title, body):
return f""" <div class="step">
<div class="step-header">
<div class="step-number">{num}</div>
<div class="step-title">{title}</div>
</div>
<div class="step-content">
{body}
</div>
</div>
"""
css_group = """
.group-title {
display: flex; align-items: center; gap: 12px;
font-size: 1.08rem; font-weight: 700; color: #fff;
margin: 36px 2px 18px;
}
.group-title::after {
content: ""; flex: 1; height: 1px; background: var(--border);
}
.group-title:first-of-type { margin-top: 6px; }
"""
u1 = step("۱", "باز کردن منوی برنامه", f""" <p>ابتدا وارد برنامهی <span class="highlight">PattNG</span> شوید و روی علامت <strong>سهخط</strong> بالای صفحه بزنید:</p>
{shot(0)}""")
u2 = step("۲", "زدن Check for update", f""" <p>بعد روی گزینهی <span class="highlight">Check for update</span> بزنید:</p>
{shot(1)}""")
u3 = step("۳", "زدن Update now", f""" <p>بعد روی <span class="highlight">Update now</span> بزنید؛ برنامه بهصورت خودکار آخرین نسخهی مناسب دستگاهتان را دانلود میکند:</p>
{shot(2)}
<div class="note warning-note">
<strong>نکته:</strong> نسخهای که توی عکس میبینید ممکن است با نسخهای که برای شما میآید فرق کند، چون با گذر زمان برنامه آپدیتهای بیشتری میدهد. اگر گزینهی Update now برایتان نیامد، یعنی برنامهتان همین حالا هم بهروز است.
</div>""")
update_block = f""" <div class="group-title">اول: آپدیت کردن PattNG به آخرین نسخه</div>
{u1}
{u2}
{u3}
<div class="group-title">بعد: وصل شدن به کانفیگ Aether</div>
"""
# locate the download card: from its step start to the start of the
# "انتخاب کانفیگ Aether" step
dl_marker = '<div class="step-number">⬇</div>'
dl_idx = html.find(dl_marker)
assert dl_idx > 0
card_start = html.rfind(' <div class="step">', 0, dl_idx)
next_marker = '<div class="step-title">انتخاب کانفیگ Aether</div>'
next_idx = html.find(next_marker)
assert next_idx > dl_idx
next_start = html.rfind(' <div class="step">', 0, next_idx)
html = html[:card_start] + update_block + html[next_start:]
# add group-title CSS
assert "</style>" in html
html = html.replace("</style>", css_group + " </style>", 1)
p.write_text(html, encoding="utf-8")
print("done | size:", len(html.encode()))