Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# (app/core/update_check.py) compares this against the latest GitHub release
# tag to decide whether to prompt the user to update. Keep it in step with the
# release tag and packaging/msix/AppxManifest.xml on every release.
APP_VERSION = "1.5.0"
APP_VERSION = "1.6.0"

ICON_PATH = Path(__file__).parent / "resources" / "icons" / "app_icon.png"

Expand Down
142 changes: 141 additions & 1 deletion packaging/make_screenshots.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,130 @@
sys.path.insert(0, str(REPO_ROOT))


# ---------------------------------------------------------------------------
# Font coverage check — catch missing glyphs before rendering, not after.
#
# When the CI runner lacks fonts for a locale's primary script (Bengali,
# Telugu, …), Qt renders every native-script character as a tofu rectangle
# (□). The resulting screenshots are useless, and the run looks green.
#
# _LOCALE_WRITING_SYSTEMS maps each supported locale to its Qt WritingSystem.
# _check_font_coverage() queries QFontDatabase.families(writing_system) after
# the QApplication exists, and fails the job immediately if no fonts are
# available — so the error names the cause rather than producing bad images.
# ---------------------------------------------------------------------------

_LOCALE_WRITING_SYSTEMS: dict[str, str] = {
"am": None, # Ethiopic — no matching Qt enum; skipped
"ar": "Arabic",
"bn": "Bengali",
"cs": "Latin",
"de": "Latin",
"el": "Greek",
"en": "Latin",
"es": "Latin",
"fa": "Arabic",
"fr": "Latin",
"gu": "Gujarati",
"ha": "Latin",
"he": "Hebrew",
"hi": "Devanagari",
"hr": "Latin",
"hu": "Latin",
"id": "Latin",
"ig": "Latin",
"it": "Latin",
"ja": "Japanese",
"jv": "Latin",
"kn": "Kannada",
"ko": "Korean",
"ml": "Malayalam",
"mr": "Devanagari",
"ms": "Latin",
"my": "Myanmar",
"ne": "Devanagari",
"nl": "Latin",
"or": "Oriya",
"pa": "Gurmukhi",
"pl": "Latin",
"pt": "Latin",
"ro": "Latin",
"ru": "Cyrillic",
"si": "Sinhala",
"so": "Latin",
"sv": "Latin",
"sw": "Latin",
"ta": "Tamil",
"te": "Telugu",
"th": "Thai",
"tr": "Latin",
"uk": "Cyrillic",
"ur": "Arabic",
"uz": "Latin",
"vi": "Vietnamese",
"yo": "Latin",
"zh": "SimplifiedChinese",
"zu": "Latin",
}


def _check_font_coverage(locale: str) -> list[str]:
"""Verify the system has fonts for the locale's primary script.

Returns a list of problem descriptions (empty = all clear). Must be
called after QApplication exists.
"""
from PySide6.QtGui import QFontDatabase

ws_name = _LOCALE_WRITING_SYSTEMS.get(locale)
if ws_name is None:
return []

ws = getattr(QFontDatabase.WritingSystem, ws_name, None)
if ws is None:
return []

families = QFontDatabase.families(ws)
if not families:
return [
f"No fonts found for {ws_name} script (locale '{locale}'). "
f"Screenshots will contain tofu characters (□). "
f"Install a font covering this script on the runner."
]
return []


def audit_for_tofu(root: Path) -> list[str]:
"""Post-render check: flag screenshots with suspiciously low complexity.

A belt-and-braces pass after the font check. Opens each PNG and checks
that the content area has enough visual variation to contain real text.
Tofu characters compress into very uniform images, so an abnormally small
file relative to its pixel count is a warning sign.
"""
from PIL import Image

problems = []
for png in sorted(root.rglob("*.png")):
img = Image.open(png)
pixel_count = img.width * img.height
file_bytes = png.stat().st_size
if pixel_count == 0:
problems.append(f"{png.name}: empty image")
continue
bits_per_pixel = (file_bytes * 8) / pixel_count
# Real screenshots with anti-aliased text and UI chrome compress to
# roughly 1–6 bits/pixel in PNG. Pure tofu with uniform backgrounds
# compresses below 0.1. A threshold of 0.15 catches obvious cases
# without false-positiving on sparse-but-real pages.
if bits_per_pixel < 0.15:
problems.append(
f"{png.name}: unusually low complexity "
f"({bits_per_pixel:.2f} bits/px) — may contain tofu text"
)
return problems


# Store-required canvas sizes, in logical pixels, with the scale factor each is
# rendered at. Apple and Microsoft both police these dimensions, so they are
# produced exactly rather than resized afterwards.
Expand Down Expand Up @@ -1019,6 +1143,14 @@ def main() -> int:

app = QApplication.instance() or QApplication([])
print(f"Qt platform plugin: {app.platformName()}")

font_problems = _check_font_coverage(args.locale)
if font_problems:
for p in font_problems:
print(f"FONT ERROR: {p}")
sys.stdout.flush()
os._exit(3)

if args.unseeded:
from app.core.db import init_db

Expand Down Expand Up @@ -1126,6 +1258,13 @@ def main() -> int:

shutil.rmtree(scratch, ignore_errors=True)
print(f"{written} screenshot(s) written to {out_root}")

tofu_problems = audit_for_tofu(out_root)
if tofu_problems:
print(f"\n{len(tofu_problems)} screenshot(s) may have encoding issues:")
for p in tofu_problems:
print(f" WARNING: {p}")

sys.stdout.flush()

# Leave immediately rather than unwinding Qt.
Expand All @@ -1137,7 +1276,8 @@ def main() -> int:
# disk, but with a non-zero exit code that would fail the CI job for no
# real reason. Every file is written and flushed by this point, so there is
# nothing left to clean up.
os._exit(0 if written else 1)
exit_code = 0 if written and not tofu_problems else 1
os._exit(exit_code)


def audit_for_secrets(root: Path) -> list[str]:
Expand Down
2 changes: 1 addition & 1 deletion packaging/msix/AppxManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<Identity
Name="SFields.Easy-PostDesktop"
Publisher="CN=A7D4B6C0-27D4-4F66-82EB-82F5DD466788"
Version="1.5.0.0"
Version="1.6.0.0"
ProcessorArchitecture="x64" />

<Properties>
Expand Down
6 changes: 3 additions & 3 deletions site/ar/download.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
<div class="hero">
<div class="wrap">
<p class="eyebrow">تنزيل</p>
<h1>الإصدار 1.3.1</h1>
<h1>الإصدار 1.6.0</h1>
<p class="lede">لأنظمة Windows و macOS. التثبيت مجاني — ومفتاح الترخيص يفتح الاستخدام الإنتاجي. أما نسختا Microsoft Store و Mac App Store فتفتحانه داخل التطبيق نفسه.</p>
</div>
</div>
Expand All @@ -65,15 +65,15 @@ <h1>الإصدار 1.3.1</h1>
<h3>Windows 10 و11</h3>
<p class="seats">64 بت · 86 ميغابايت</p>
<p class="per-seat">فُك الضغط في أي مكان، ثم شغّل EasyPostDesktop.exe</p>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.3.1/EasyPostDesktop-Windows-x64.zip">تنزيل لنظام Windows</a>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.6.0/EasyPostDesktop-Windows-x64.zip">تنزيل لنظام Windows</a>
</div>

<div class="tier">
<p class="tag">macOS</p>
<h3>macOS على معالجات Apple silicon</h3>
<p class="seats">Apple silicon · 82 ميغابايت</p>
<p class="per-seat">موثّقة من Apple · تُفتح بلا أي تحذيرات</p>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.3.1/EasyPostDesktop-macOS-arm64.dmg">تنزيل لنظام macOS</a>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.6.0/EasyPostDesktop-macOS-arm64.dmg">تنزيل لنظام macOS</a>
</div>

<div class="tier">
Expand Down
6 changes: 3 additions & 3 deletions site/bn/download.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
<div class="hero">
<div class="wrap">
<p class="eyebrow">ডাউনলোড</p>
<h1>সংস্করণ ১.৩.১</h1>
<h1>সংস্করণ ১.৬.০</h1>
<p class="lede">Windows ও macOS। বিনামূল্যে ইনস্টল করুন — একটি লাইসেন্স কী প্রোডাকশন ব্যবহার আনলক করে। Microsoft Store এবং Mac App Store সংস্করণগুলি এর পরিবর্তে অ্যাপের মধ্যেই এটি আনলক করে।</p>
</div>
</div>
Expand All @@ -65,15 +65,15 @@ <h1>সংস্করণ ১.৩.১</h1>
<h3>Windows 10 ও 11</h3>
<p class="seats">৬৪-বিট · ৮৬ MB</p>
<p class="per-seat">যেকোনো জায়গায় আনজিপ করুন, তারপর EasyPostDesktop.exe চালান</p>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.3.1/EasyPostDesktop-Windows-x64.zip">Windows-এর জন্য ডাউনলোড করুন</a>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.6.0/EasyPostDesktop-Windows-x64.zip">Windows-এর জন্য ডাউনলোড করুন</a>
</div>

<div class="tier">
<p class="tag">macOS</p>
<h3>Apple silicon-এ macOS</h3>
<p class="seats">Apple silicon · 82 MB</p>
<p class="per-seat">Apple দ্বারা নোটারাইজড · কোনো সতর্কবার্তা ছাড়াই খোলে</p>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.3.1/EasyPostDesktop-macOS-arm64.dmg">macOS-এর জন্য ডাউনলোড করুন</a>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.6.0/EasyPostDesktop-macOS-arm64.dmg">macOS-এর জন্য ডাউনলোড করুন</a>
</div>

<div class="tier">
Expand Down
6 changes: 3 additions & 3 deletions site/de/download.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
<div class="hero">
<div class="wrap">
<p class="eyebrow">Download</p>
<h1>Version 1.3.1</h1>
<h1>Version 1.6.0</h1>
<p class="lede">Windows und macOS. Kostenlose Installation – ein Lizenzschlüssel schaltet die produktive Nutzung frei. Bei den Versionen aus dem Microsoft Store und dem Mac App Store erfolgt die Freischaltung stattdessen direkt in der App.</p>
</div>
</div>
Expand All @@ -65,15 +65,15 @@ <h1>Version 1.3.1</h1>
<h3>Windows 10 &amp; 11</h3>
<p class="seats">64-Bit · 86 MB</p>
<p class="per-seat">Entpacken Sie die Datei an einem beliebigen Ort und führen Sie dann EasyPostDesktop.exe aus</p>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.3.1/EasyPostDesktop-Windows-x64.zip">Für Windows herunterladen</a>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.6.0/EasyPostDesktop-Windows-x64.zip">Für Windows herunterladen</a>
</div>

<div class="tier">
<p class="tag">macOS</p>
<h3>macOS auf Apple Silicon</h3>
<p class="seats">Apple Silicon · 82 MB</p>
<p class="per-seat">Von Apple notarisiert · öffnet ohne Warnungen</p>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.3.1/EasyPostDesktop-macOS-arm64.dmg">Für macOS herunterladen</a>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.6.0/EasyPostDesktop-macOS-arm64.dmg">Für macOS herunterladen</a>
</div>

<div class="tier">
Expand Down
6 changes: 3 additions & 3 deletions site/download.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
<div class="hero">
<div class="wrap">
<p class="eyebrow">Download</p>
<h1>Version 1.3.1</h1>
<h1>Version 1.6.0</h1>
<p class="lede">Windows and macOS. Free to install — a licence key unlocks production use. The Microsoft Store and Mac App Store versions unlock it in the app instead.</p>
</div>
</div>
Expand All @@ -69,15 +69,15 @@ <h1>Version 1.3.1</h1>
<h3>Windows 10 &amp; 11</h3>
<p class="seats">64-bit · 86 MB</p>
<p class="per-seat">Unzip anywhere, then run EasyPostDesktop.exe</p>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.3.1/EasyPostDesktop-Windows-x64.zip">Download for Windows</a>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.6.0/EasyPostDesktop-Windows-x64.zip">Download for Windows</a>
</div>

<div class="tier">
<p class="tag">macOS</p>
<h3>macOS on Apple silicon</h3>
<p class="seats">Apple silicon · 82 MB</p>
<p class="per-seat">Notarized by Apple · opens without warnings</p>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.3.1/EasyPostDesktop-macOS-arm64.dmg">Download for macOS</a>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.6.0/EasyPostDesktop-macOS-arm64.dmg">Download for macOS</a>
</div>

<div class="tier">
Expand Down
6 changes: 3 additions & 3 deletions site/es/download.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
<div class="hero">
<div class="wrap">
<p class="eyebrow">Descargar</p>
<h1>Versión 1.3.1</h1>
<h1>Versión 1.6.0</h1>
<p class="lede">Windows y macOS. Instalación gratuita — una clave de licencia desbloquea el uso en producción. Las versiones de Microsoft Store y Mac App Store lo desbloquean directamente en la aplicación.</p>
</div>
</div>
Expand All @@ -65,15 +65,15 @@ <h1>Versión 1.3.1</h1>
<h3>Windows 10 y 11</h3>
<p class="seats">64 bits · 86 MB</p>
<p class="per-seat">Descomprima en cualquier carpeta y ejecute EasyPostDesktop.exe</p>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.3.1/EasyPostDesktop-Windows-x64.zip">Descargar para Windows</a>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.6.0/EasyPostDesktop-Windows-x64.zip">Descargar para Windows</a>
</div>

<div class="tier">
<p class="tag">macOS</p>
<h3>macOS en Apple silicon</h3>
<p class="seats">Apple silicon · 82 MB</p>
<p class="per-seat">Notarizado por Apple · se abre sin advertencias</p>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.3.1/EasyPostDesktop-macOS-arm64.dmg">Descargar para macOS</a>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.6.0/EasyPostDesktop-macOS-arm64.dmg">Descargar para macOS</a>
</div>

<div class="tier">
Expand Down
6 changes: 3 additions & 3 deletions site/fr/download.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
<div class="hero">
<div class="wrap">
<p class="eyebrow">Télécharger</p>
<h1>Version 1.3.1</h1>
<h1>Version 1.6.0</h1>
<p class="lede">Windows et macOS. Installation gratuite — une clé de licence débloque l'usage en production. Les versions du Microsoft Store et du Mac App Store le débloquent directement dans l'application.</p>
</div>
</div>
Expand All @@ -65,15 +65,15 @@ <h1>Version 1.3.1</h1>
<h3>Windows 10 et 11</h3>
<p class="seats">64 bits · 86 Mo</p>
<p class="per-seat">Décompressez où vous le souhaitez, puis lancez EasyPostDesktop.exe</p>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.3.1/EasyPostDesktop-Windows-x64.zip">Télécharger pour Windows</a>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.6.0/EasyPostDesktop-Windows-x64.zip">Télécharger pour Windows</a>
</div>

<div class="tier">
<p class="tag">macOS</p>
<h3>macOS sur puce Apple</h3>
<p class="seats">Puce Apple · 82 Mo</p>
<p class="per-seat">Notarisé par Apple · s'ouvre sans avertissement</p>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.3.1/EasyPostDesktop-macOS-arm64.dmg">Télécharger pour macOS</a>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.6.0/EasyPostDesktop-macOS-arm64.dmg">Télécharger pour macOS</a>
</div>

<div class="tier">
Expand Down
6 changes: 3 additions & 3 deletions site/hi/download.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
<div class="hero">
<div class="wrap">
<p class="eyebrow">डाउनलोड</p>
<h1>संस्करण 1.3.1</h1>
<h1>संस्करण 1.6.0</h1>
<p class="lede">Windows और macOS। इंस्टॉल करना निःशुल्क है — एक लाइसेंस कुंजी उत्पादन उपयोग को अनलॉक करती है। Microsoft Store और Mac App Store संस्करण इसे इसके बजाय ऐप के भीतर अनलॉक करते हैं।</p>
</div>
</div>
Expand All @@ -65,15 +65,15 @@ <h1>संस्करण 1.3.1</h1>
<h3>Windows 10 और 11</h3>
<p class="seats">64-बिट · 86 MB</p>
<p class="per-seat">कहीं भी अनज़िप करें, फिर EasyPostDesktop.exe चलाएँ</p>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.3.1/EasyPostDesktop-Windows-x64.zip">Windows के लिए डाउनलोड करें</a>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.6.0/EasyPostDesktop-Windows-x64.zip">Windows के लिए डाउनलोड करें</a>
</div>

<div class="tier">
<p class="tag">macOS</p>
<h3>Apple silicon पर macOS</h3>
<p class="seats">Apple silicon · 82 MB</p>
<p class="per-seat">Apple द्वारा सत्यापित (notarized) · बिना किसी चेतावनी के खुलता है</p>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.3.1/EasyPostDesktop-macOS-arm64.dmg">macOS के लिए डाउनलोड करें</a>
<a class="btn" href="https://github.com/sgf36/EasyPost/releases/download/v1.6.0/EasyPostDesktop-macOS-arm64.dmg">macOS के लिए डाउनलोड करें</a>
</div>

<div class="tier">
Expand Down
Loading
Loading