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
83 changes: 69 additions & 14 deletions scripts/generate_share_images.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"""

import json
import logging
import os
import re
import sys
Expand All @@ -18,6 +19,8 @@
from bidi.algorithm import get_display
from PIL import Image, ImageDraw, ImageFont

logger = logging.getLogger(__name__)

# Paths
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DATA_DIR = os.path.join(ROOT, "webapp", "data")
Expand All @@ -36,12 +39,60 @@
GRAY = (82, 82, 82) # #525252
WHITE = (255, 255, 255)

# Font paths
FONT_DEJAVU = "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"
FONT_DEJAVU_BOLD = "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf"
FONT_CJK = "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc"
FONT_CJK_BOLD = "/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc"
SCORE_FONT = "/usr/share/fonts/truetype/noto/NotoSans-Bold.ttf"
# Candidate paths for font resolution, tried in order per platform.
_DEJAVU_PATHS = [
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", # Ubuntu/Debian
"/usr/share/fonts/dejavu-sans-fonts/DejaVuSans.ttf", # Fedora/RHEL
"/usr/share/fonts/TTF/DejaVuSans.ttf", # Arch
]
_DEJAVU_BOLD_PATHS = [
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
"/usr/share/fonts/dejavu-sans-fonts/DejaVuSans-Bold.ttf",
"/usr/share/fonts/TTF/DejaVuSans-Bold.ttf",
]
_NOTO_BOLD_PATHS = [
"/usr/share/fonts/truetype/noto/NotoSans-Bold.ttf",
"/usr/share/fonts/noto/NotoSans-Bold.ttf",
"/usr/share/fonts/TTF/NotoSans-Bold.ttf",
"/usr/share/fonts/noto-sans-fonts/NotoSans-Bold.ttf", # Fedora
]
_CJK_REGULAR_PATHS = [
"/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",
"/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc",
"/usr/share/fonts/OTF/NotoSansCJK-Regular.ttc",
]
_CJK_BOLD_PATHS = [
"/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc",
"/usr/share/fonts/noto-cjk/NotoSansCJK-Bold.ttc",
"/usr/share/fonts/OTF/NotoSansCJK-Bold.ttc",
]


def _resolve_font(candidates, label):
"""Return the first path that exists from *candidates*, or None."""
for path in candidates:
if os.path.isfile(path):
return path
logger.warning("No %s font found at any of %s — will use Pillow default", label, candidates)
return None


# Resolve once at import time and cache the results.
FONT_DEJAVU = _resolve_font(_DEJAVU_PATHS, "DejaVu regular")
FONT_DEJAVU_BOLD = _resolve_font(_DEJAVU_BOLD_PATHS, "DejaVu bold") or _resolve_font(
_DEJAVU_PATHS, "DejaVu regular (bold fallback)"
)
SCORE_FONT = (
_resolve_font(_NOTO_BOLD_PATHS, "Noto Sans bold")
or _resolve_font(_DEJAVU_BOLD_PATHS, "DejaVu bold (score fallback)")
or _resolve_font(_DEJAVU_PATHS, "DejaVu regular (score fallback)")
)
FONT_CJK = _resolve_font(_CJK_REGULAR_PATHS, "CJK regular") or FONT_DEJAVU
FONT_CJK_BOLD = (
_resolve_font(_CJK_BOLD_PATHS, "CJK bold")
or _resolve_font(_CJK_REGULAR_PATHS, "CJK regular (bold fallback)")
or FONT_DEJAVU_BOLD
)

# Languages needing CJK font (DejaVu doesn't cover Hangul glyphs)
CJK_LANGS = {"ko"}
Expand All @@ -55,10 +106,17 @@


def get_font(path, size):
"""Get a cached font instance."""
"""Get a cached font instance, falling back to Pillow default if path is None."""
key = (path, size)
if key not in FONTS:
FONTS[key] = ImageFont.truetype(path, size)
if path is None:
FONTS[key] = ImageFont.load_default(size=size)
else:
try:
FONTS[key] = ImageFont.truetype(path, size)
except OSError:
logger.warning("Failed to load font %s — using Pillow default", path)
FONTS[key] = ImageFont.load_default(size=size)
return FONTS[key]


Expand Down Expand Up @@ -168,7 +226,7 @@ def generate_image(lang_code, result, challenge_text, is_rtl):

# Auto-size: enforce exactly 2 lines — line 1 = white statement, line 2 = green CTA.
# Shrink fonts until each part fits on exactly 1 line.
stmt_size, cta_size = 44, 48
stmt_size = 44
for stmt_s, cta_s in ((44, 48), (38, 42), (32, 36), (26, 30)):
font_main = get_font(font_reg, stmt_s)
font_cta = get_font(font_bold, cta_s)
Expand All @@ -185,7 +243,7 @@ def generate_image(lang_code, result, challenge_text, is_rtl):
cta_lines = wrap_text(cta_display, font_cta, draw, max_w)
if len(cta_lines) != 1:
cta_ok = False
stmt_size, cta_size = stmt_s, cta_s
stmt_size = stmt_s
if stmt_ok and cta_ok:
break

Expand Down Expand Up @@ -238,10 +296,7 @@ def main():
load_header()
configs = load_language_configs()

if len(sys.argv) > 1:
target_langs = sys.argv[1:]
else:
target_langs = sorted(configs.keys())
target_langs = sys.argv[1:] if len(sys.argv) > 1 else sorted(configs.keys())

os.makedirs(OUTPUT_DIR, exist_ok=True)

Expand Down
17 changes: 11 additions & 6 deletions webapp/templates/game.html
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,16 @@
<meta name="keywords" content="wordle, {{ language.config.name_native }}, {{ language.config.name }}">
{% endif %}
{% if share_result %}
{% set share_desc = "Think you can do better? Try today's Wordle in " ~ language.config.name ~ "!" %}
{# og:title: short and punchy (score + language). og:desc: native challenge text. #}
{% if share_result == 'x' %}
{% set share_title = "Wordle " ~ language.config.name_native ~ " — I didn't get it. Can you?" %}
{% set share_title = "Wordle " ~ language.config.name_native ~ " — X/6" %}
{% set share_desc = language.config.text.share_challenge_lose %}
{% elif share_result == '1' %}
{% set share_title = "Wordle " ~ language.config.name_native ~ " — 1/6 🤯 Beat that!" %}
{% set share_desc = "First try! " ~ share_desc %}
{% set share_title = "Wordle " ~ language.config.name_native ~ " — 1/6 🤯" %}
{% set share_desc = language.config.text.share_challenge_win | replace('{n}', '1') %}
{% else %}
{% set share_title = "Wordle " ~ language.config.name_native ~ " — " ~ share_result ~ "/6. Can you beat me?" %}
{% set share_title = "Wordle " ~ language.config.name_native ~ " — " ~ share_result ~ "/6" %}
{% set share_desc = language.config.text.share_challenge_win | replace('{n}', share_result) %}
{% endif %}
{% else %}
{% set share_title = title %}
Expand Down Expand Up @@ -109,11 +111,14 @@
<script>
window.word_list = JSON.parse('{{language.word_list | tojson | safe}}');
window.word_list_supplement = JSON.parse('{{language.word_list_supplement | tojson | safe}}');
console.log('\nFor the language: ' + '"{{language.config.name_native}}/{{language.config.name}}"' + ' there are:\n' + window.word_list.length + ' words in the word list\n' + window.word_list_supplement.length + ' words in the supplemental word list.');
window.characters = JSON.parse('{{language.characters | tojson | safe}}');
window.config = JSON.parse('{{language.config | tojson | safe}}');
console.log("Character Set: " + window.characters);
window.todays_idx = "{{ language.todays_idx }}";
window.todays_word = "{{ language.daily_word }}";
window.timezone_offset = {{ language.timezone_offset | default(0) | tojson }};
console.log("Today's word is: " + window.todays_word.toUpperCase() + "\nDon't cheat!");
</script>
</head>

Expand Down Expand Up @@ -293,7 +298,7 @@ <h2 class="text-md font-semibold text-gray-900 dark:text-gray-100">{{ language.c
<div class="border-t-2 border-gray-300 dark:border-gray-600"></div>

<div class="flex flex-col gap-2 py-2">
<a href="https://github.com/Hugo0/wordle/issues/new/choose"
<a href="https://github.com/Hugo0/wordle/issues"
target="_blank"
rel="noopener noreferrer"
class="flex items-center gap-2 text-sm text-neutral-600 dark:text-neutral-300 hover:text-neutral-900 dark:hover:text-white">
Expand Down
Loading