Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
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
73 changes: 66 additions & 7 deletions badge/apps/badge/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

WIFI_PASSWORD = None
WIFI_SSID = None
CLOUDINARY_CLOUD_NAME = "demo"

wlan = None
connected = False
Expand All @@ -39,14 +40,19 @@ def message(text):


def get_connection_details(user):
global WIFI_PASSWORD, WIFI_SSID
global WIFI_PASSWORD, WIFI_SSID, CLOUDINARY_CLOUD_NAME

if WIFI_SSID is not None and user.handle is not None:
return True

try:
sys.path.insert(0, "/")
from secrets import WIFI_PASSWORD, WIFI_SSID, GITHUB_USERNAME
try:
from secrets import CLOUDINARY_CLOUD_NAME as cloud_name
CLOUDINARY_CLOUD_NAME = cloud_name
except ImportError:
pass # Use default "demo"
sys.path.pop(0)
except ImportError:
WIFI_PASSWORD = None
Expand Down Expand Up @@ -171,6 +177,20 @@ def get_user_data(user, force_update=False):
user.handle = r["login"]
user.followers = r["followers"]
user.repos = r["public_repos"]

# Check if name contains Chinese characters and fetch rendered image
if user.name and has_chinese_characters(user.name):
message(f"Rendering Chinese name: {user.name}")
chinese_url = generate_chinese_text_url(user.name)
if chinese_url:
try:
yield from async_fetch_to_disk(chinese_url, "/chinese_name.png", force_update)
user.chinese_name_img = Image.load("/chinese_name.png")
message("Chinese name image loaded")
except Exception as e:
message(f"Failed to load Chinese name: {e}")
user.chinese_name_img = None

del r
gc.collect()

Expand Down Expand Up @@ -201,6 +221,34 @@ def fake_number():
return random.randint(10000, 99999)


def has_chinese_characters(text):
"""Check if text contains Chinese characters"""
if not text:
return False
return any('\u4e00' <= char <= '\u9fff' for char in text)


def generate_chinese_text_url(text, width=150, height=20, font_size=14):
"""Generate Cloudinary URL for rendering Chinese text as image"""
try:
from urllib.parse import quote
text_encoded = quote(text)

# Using Cloudinary's text overlay feature with a CJK-compatible font
# Note: This uses Arial Unicode MS which supports Chinese
# Cloud name is loaded from secrets.py (defaults to "demo")

url = f"https://res.cloudinary.com/{CLOUDINARY_CLOUD_NAME}/image/upload/"
url += f"w_{width},h_{height},c_fit,b_rgb:000000/"
url += f"l_text:Arial%20Unicode%20MS_{font_size}:{text_encoded},co_rgb:ebf5ff/"
url += "blank.png"

return url
except Exception as e:
print(f"Error generating Cloudinary URL: {e}")
return None


def placeholder_if_none(text):
if text:
return text
Expand Down Expand Up @@ -234,6 +282,7 @@ def update(self, force_update=False):
self.contribution_data = None
self.repos = None
self.avatar = None
self.chinese_name_img = None
self._task = None
self._force_update = force_update

Expand Down Expand Up @@ -278,6 +327,10 @@ def draw(self, connected):
handle = "fetching user data..."
if not self._task:
self._task = get_user_data(self, self._force_update)
elif self.name and has_chinese_characters(self.name) and not self.chinese_name_img:
handle = "rendering chinese..."
if not self._task:
self._task = get_user_data(self, self._force_update)
Comment on lines +331 to +332
Copy link

Copilot AI Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This condition calls get_user_data() again which will re-fetch user data unnecessarily. The Chinese image should already be fetched within get_user_data() (lines 182-192). This condition appears to be unreachable in normal flow since chinese_name_img is set during the initial get_user_data() call when self.name is populated.

Suggested change
if not self._task:
self._task = get_user_data(self, self._force_update)

Copilot uses AI. Check for mistakes.
elif not self.contribs:
handle = "fetching contribs..."
if not self._task:
Expand All @@ -302,12 +355,18 @@ def draw(self, connected):
screen.brush = white
screen.text(handle, 80 - (w / 2), 2)

# draw name
screen.font = small_font
screen.brush = phosphor
name = placeholder_if_none(self.name)
w, _ = screen.measure_text(name)
screen.text(name, 80 - (w / 2), 16)
# draw name (use image if Chinese characters, otherwise use text)
if self.chinese_name_img:
# Display Chinese name as image, centered
img_w = self.chinese_name_img.width
screen.blit(self.chinese_name_img, 80 - (img_w / 2), 16)
Copy link

Copilot AI Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Integer division should be used for pixel positioning. Using float division may cause rendering issues. Change to 80 - (img_w // 2) for consistent behavior with the text centering logic on line 369.

Suggested change
screen.blit(self.chinese_name_img, 80 - (img_w / 2), 16)
screen.blit(self.chinese_name_img, 80 - (img_w // 2), 16)

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The Y-coordinate 16 is hardcoded here and on line 369. Consider extracting this as a constant like NAME_Y_POSITION = 16 to improve maintainability and ensure consistency.

Copilot uses AI. Check for mistakes.
else:
# Display name as text for non-Chinese names
screen.font = small_font
screen.brush = phosphor
name = placeholder_if_none(self.name)
w, _ = screen.measure_text(name)
screen.text(name, 80 - (w / 2), 16)

# draw statistics
self.draw_stat("followers", self.followers, 88, 33)
Expand Down
7 changes: 6 additions & 1 deletion badge/secrets.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,9 @@
WIFI_PASSWORD = "h4ck4w4y"

# Update with your GitHub username
GITHUB_USERNAME = ""
GITHUB_USERNAME = ""

# Optional: Update with your Cloudinary cloud name for Chinese character support
# Sign up at https://cloudinary.com (free tier available)
# Leave as "demo" to use the public demo account
CLOUDINARY_CLOUD_NAME = "demo"
Loading