Skip to content

Commit 9efecd8

Browse files
Merge pull request #67 from jinwandalaohu66/submission/script_mnfx90ey
2 parents 5298193 + eea22c8 commit 9efecd8

2 files changed

Lines changed: 214 additions & 2 deletions

File tree

script_library/index.json

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"format_version": 1,
3-
"data_version": 47,
4-
"updated": "2026-04-01T10:04:19Z",
3+
"data_version": 48,
4+
"updated": "2026-04-01T10:47:27.654Z",
55
"announcement": null,
66
"categories": [
77
{
@@ -1145,6 +1145,29 @@
11451145
"updated": null,
11461146
"status": "active",
11471147
"lines": 23
1148+
},
1149+
{
1150+
"id": "script_mnfx90ey",
1151+
"name": "纪念日",
1152+
"name_en": "纪念日",
1153+
"desc": "可更改自己所需的纪念日或者倒计时,脚本有注释",
1154+
"desc_en": "可更改自己所需的纪念日或者倒计时,脚本有注释",
1155+
"category": "widgets",
1156+
"file": "scripts/widgets/script_mnfx90ey.py",
1157+
"thumbnail": null,
1158+
"version": 1,
1159+
"file_type": "py",
1160+
"author": "Silence",
1161+
"author_en": "Silence",
1162+
"tags": [
1163+
"community"
1164+
],
1165+
"requires": [],
1166+
"min_app_version": "1.5.0",
1167+
"added": "2026-04-01",
1168+
"updated": null,
1169+
"status": "active",
1170+
"lines": 189
11481171
}
11491172
]
11501173
}
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
from widget import Widget, family, MEDIUM
2+
from datetime import datetime, date
3+
4+
5+
BACKGROUND_COLOR = ("#F8F9FA", "#1C1C1E")
6+
TITLE_COLOR = ("#2C3E50", "#FFFFFF")
7+
DIVIDER_COLOR = ("#DEE2E6", "#3A3A3C")
8+
NAME_COLOR = ("#212529", "#FFFFFF")
9+
FUTURE_COLOR = ("#2ECC71", "#6EE7B7")
10+
TODAY_COLOR = ("#F1C40F", "#FFD966")
11+
PAST_COLOR = ("#E74C3C", "#FF6B6B")
12+
AGE_COLOR = ("#E67E22", "#F39C12")
13+
14+
ICON_COLORS = {
15+
"birthday.cake.fill": ("#FF6B6B", "#FF9F4A"),
16+
"person.fill": ("#4A90E2", "#6AB0FF"),
17+
"heart.fill": ("#E8436E", "#FF6B8B"),
18+
"graduationcap.fill": ("#9B6DFF", "#B78CFF"),
19+
"star.fill": ("#FFC107", "#FFD966"),
20+
"gift.fill": ("#38B2AC", "#6EE7B7"),
21+
"default": ("#8E8E93", "#AEAEB2")
22+
}
23+
24+
# 纪念日列表(直接在下面修改)
25+
# 每个条目包含:name(名称), date(YYYY-MM-DD), icon(SF Symbol), type(类型)
26+
# 类型说明:
27+
# - "yearly" : 每年重复(如生日、纪念日)
28+
# - "age" : 累计天数(如“来到这个世界”)
29+
# - "once" : 一次性固定日期(如某个活动截止日)
30+
ANNIVERSARIES = [
31+
{
32+
"name": "生日",
33+
"date": "2000-01-01",
34+
"icon": "birthday.cake.fill",
35+
"type": "yearly"
36+
},
37+
{
38+
"name": "来到这个世界",
39+
"date": "2000-01-01",
40+
"icon": "person.fill",
41+
"type": "age"
42+
},
43+
{
44+
"name": "恋爱纪念日",
45+
"date": "2022-05-20",
46+
"icon": "heart.fill",
47+
"type": "yearly"
48+
},
49+
{
50+
"name": "毕业日",
51+
"date": "2024-07-01",
52+
"icon": "graduationcap.fill",
53+
"type": "yearly"
54+
}
55+
]
56+
57+
ICON_SIZE = 20
58+
TITLE_FONT_SIZE = 16
59+
NAME_FONT_SIZE = 14
60+
DAYS_FONT_SIZE = 12
61+
SPACING = 10
62+
PADDING = 12
63+
64+
65+
def days_since_birth(birth_date):
66+
today = datetime.now().date()
67+
try:
68+
birth = datetime.strptime(birth_date, "%Y-%m-%d").date()
69+
except:
70+
return None
71+
return (today - birth).days
72+
73+
def get_next_yearly(month, day):
74+
today = datetime.now().date()
75+
try:
76+
target_this_year = date(today.year, month, day)
77+
except ValueError:
78+
return None
79+
if target_this_year >= today:
80+
return target_this_year
81+
else:
82+
try:
83+
return date(today.year + 1, month, day)
84+
except ValueError:
85+
return None
86+
87+
def days_diff(item):
88+
if item['type'] == 'age':
89+
days = days_since_birth(item['date'])
90+
if days is None:
91+
return None, None
92+
return days, f" {days} 天"
93+
elif item['type'] == 'yearly':
94+
try:
95+
parts = item['date'].split('-')
96+
if len(parts) != 3:
97+
return None, None
98+
month, day = int(parts[1]), int(parts[2])
99+
next_date = get_next_yearly(month, day)
100+
if next_date is None:
101+
return None, None
102+
delta = (next_date - datetime.now().date()).days
103+
if delta == 0:
104+
text = "就是今天!"
105+
elif delta > 0:
106+
text = f"还有{delta} 天"
107+
else:
108+
text = f"已过 {-delta} 天"
109+
return delta, text
110+
except:
111+
return None, None
112+
else:
113+
try:
114+
target = datetime.strptime(item['date'], "%Y-%m-%d").date()
115+
delta = (target - datetime.now().date()).days
116+
if delta == 0:
117+
text = "就是今天!"
118+
elif delta > 0:
119+
text = f"还有 {delta} 天"
120+
else:
121+
text = f"已过 {-delta} 天"
122+
return delta, text
123+
except:
124+
return None, None
125+
126+
def get_icon_color(icon_name):
127+
return ICON_COLORS.get(icon_name, ICON_COLORS["default"])
128+
129+
def get_status_color(delta, item_type):
130+
if item_type == 'age':
131+
return AGE_COLOR
132+
if delta == 0:
133+
return TODAY_COLOR
134+
elif delta > 0:
135+
return FUTURE_COLOR
136+
else:
137+
return PAST_COLOR
138+
139+
def render_widget():
140+
items = []
141+
for a in ANNIVERSARIES:
142+
delta, text = days_diff(a)
143+
if delta is not None:
144+
items.append({
145+
'name': a['name'],
146+
'delta': delta,
147+
'text': text,
148+
'icon': a.get('icon', 'calendar'),
149+
'type': a['type']
150+
})
151+
152+
items.sort(key=lambda x: (x['type'] == 'age', abs(x['delta'])))
153+
display_items = items[:4]
154+
155+
w = Widget(background=BACKGROUND_COLOR)
156+
157+
with w.vstack(spacing=8, padding=PADDING):
158+
with w.hstack(spacing=4):
159+
w.icon("calendar", size=ICON_SIZE-2, color=TITLE_COLOR, weight="medium")
160+
w.text("纪念日", size=TITLE_FONT_SIZE, weight="semibold", color=TITLE_COLOR)
161+
162+
w.divider(color=DIVIDER_COLOR)
163+
164+
if not display_items:
165+
with w.hstack():
166+
w.icon("info.circle", size=ICON_SIZE-2, color=("#6C757D", "#8E8E93"))
167+
w.text("暂无纪念日,请在脚本中添加", size=12, color=("#6C757D", "#8E8E93"), align="center")
168+
else:
169+
for item in display_items:
170+
with w.hstack(spacing=SPACING, align="center"):
171+
icon_light, icon_dark = get_icon_color(item['icon'])
172+
icon_color = (icon_light, icon_dark)
173+
w.icon(item['icon'], size=ICON_SIZE, color=icon_color, weight="regular")
174+
175+
w.text(item['name'], size=NAME_FONT_SIZE, weight="medium", color=NAME_COLOR, max_lines=1)
176+
177+
w.spacer()
178+
179+
status_color = get_status_color(item['delta'], item['type'])
180+
w.text(item['text'], size=DAYS_FONT_SIZE, color=status_color, weight="medium", max_lines=1)
181+
182+
w.render(url="pythonide://")
183+
184+
if __name__ == '__main__':
185+
try:
186+
family
187+
except NameError:
188+
family = MEDIUM
189+
render_widget()

0 commit comments

Comments
 (0)