Skip to content

Commit 6c48159

Browse files
refactor: use gradients without default images
1 parent 2444ff4 commit 6c48159

15 files changed

Lines changed: 53 additions & 52 deletions

File tree

‎README.md‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,5 @@ tools/、deploy/ # 跨项目构建、打包、发布工具
3535

3636
- Rust GUI:`launcher-rust.bat`;隔离演示配置加 `--demo`。
3737
- Python GUI:`launcher.bat`,或 `uv run python -m gui.launcher`。
38-
- Python 后端:`uv run --directory python-backend python -m src.headless serve --stdio`。
3938

4039
构建与测试见 [TESTING.md](TESTING.md),Rust 说明见 [rust-gui/README.md](rust-gui/README.md)。

‎docs/rust-feasibility/headless-cli.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ stdin/stdout 使用 UTF-8 JSON Lines,每行一个请求或响应,立即 flus
9797

9898
协议层校验信封、方法白名单、参数对象及必填/允许的字段,不复制业务取值校验。
9999

100-
壁纸来源优先级为自定义、脚本声明、助手默认;缺失自定义文件返回 gradient,不覆盖用户选择。
100+
壁纸来源优先级为自定义、脚本声明,无图片时使用渐变;缺失自定义文件返回 gradient,不覆盖用户选择。
101101
图片解码/EXIF 方向/缩放由前端完成,缓存写盘仍经 service。缓存最多 4 MiB,路径由服务生成;
102102
token 包含规范化源路径、大小及修改时间。视频首帧缓存沿用原 Qt 的哈希与命名。
103103
保存与反读独立,前端保留失败草稿,不因刷新失败再次保存。自动背景和显式编辑分别命名,

‎python-backend/src/utils/utils_wallpaper.py‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ def save_video_preview(source_path: str, cache_path: str, data: bytes) -> bool:
102102

103103

104104
def wallpaper_view(script_name: str) -> dict:
105-
"""按自定义、脚本声明、助手默认的顺序解析;缺失自定义文件走渐变。"""
105+
"""按自定义、脚本声明的顺序解析;无可用图片时使用渐变。"""
106106
script = get_script(script_name)
107107
if script is None:
108108
raise InvalidWallpaper("脚本已不存在,请刷新列表")
@@ -123,9 +123,7 @@ def wallpaper_view(script_name: str) -> dict:
123123
candidate = os.path.join(root, relative)
124124
if os.path.isfile(candidate):
125125
source = candidate
126-
if not source:
127-
source = resolve_script_path("assets/ds.jpg")
128-
source = os.path.abspath(source)
126+
source = os.path.abspath(source) if source else ""
129127
mode = (
130128
"video" if os.path.splitext(source)[1].lower() in VIDEO_EXTENSIONS else "image"
131129
)

‎python-backend/tests/config/test_set_config.py‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,10 @@ def test_unknown_process_returns_none(self):
495495
def test_known_process_dispatches(self):
496496
factory = MagicMock()
497497
factory.return_value.get_game_exe_path.return_value = "D:/Game/game.exe"
498-
with patch.dict(set_config._CONFIGS, {"ok-ww": factory}, clear=True):
498+
with (
499+
patch.dict(set_config._CONFIGS, {"ok-ww": factory}, clear=True),
500+
patch.object(set_config, "get_script_game_path", return_value=""),
501+
):
499502
self.assertEqual(set_config.get_game_exe_path("ok-ww"), "D:/Game/game.exe")
500503
factory.assert_called_once_with()
501504
factory.return_value.get_game_exe_path.assert_called_once_with()

‎python-backend/tests/tools/test_release_package.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def setUp(self):
3333
"config/weekly.example.yml": "weekly_start: {}\n",
3434
"config/daily_task_list.yml": "日常: []\n",
3535
"config/script_resources.yml": "version: 1\nscripts: {}\n",
36-
"assets/ds.jpg": "image",
36+
"assets/ds.ico": "icon",
3737
"src/gui/qml/main.qml": "Window {}",
3838
}
3939
for name, content in self.resources.items():
@@ -165,7 +165,7 @@ def test_embedded_icons_stay_in_source_and_out_of_both_packages(self):
165165
manifest = release.load_manifest(package, verify=True)
166166
self.assertNotIn("assets/icons/home.png", manifest["files"])
167167
self.assertFalse((package / "assets/icons").exists())
168-
self.assertTrue((package / "assets/ds.jpg").is_file())
168+
self.assertTrue((package / "assets/ds.ico").is_file())
169169
output = self.package / f"{frontend}.zip"
170170
release.archive_package(self.root, package, output)
171171
with zipfile.ZipFile(output) as archive:

‎python-backend/tests/tools/test_rust_gui.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ def test_demo_uses_generated_config_and_static_declarations_only(self):
1616
root = Path(temporary)
1717
with patch("tools.run_rust_gui.shutil.copytree") as source_copy:
1818
prepare_demo(root)
19+
self.assertFalse((root / "assets/ds.jpg").exists())
1920
self.assertEqual(source_copy.call_count, 2)
2021
backend, runner = source_copy.call_args_list
2122
self.assertEqual(backend.args[1], root / "python-backend/src")

‎python-backend/tests/utils/test_utils_wallpaper.py‎

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -157,13 +157,16 @@ def setUp(self):
157157
)
158158
(self.root / "config").mkdir()
159159
(self.root / "assets").mkdir()
160-
self.default = self.root / "assets/ds.jpg"
161-
self.default.write_bytes(b"default")
160+
self.image = self.root / "assets/custom.jpg"
161+
self.image.write_bytes(b"custom")
162162

163163
def test_priority_and_missing_custom_do_not_fall_back_to_another_image(self):
164-
self.assertEqual(
165-
wallpaper.wallpaper_view("script")["source"], str(self.default)
166-
)
164+
legacy = self.root / "assets/ds.jpg"
165+
legacy.write_bytes(b"old bundled background")
166+
state = wallpaper.wallpaper_view("script")
167+
self.assertEqual(state["mode"], "gradient")
168+
self.assertEqual(state["source"], "")
169+
self.assertIsNone(state["token"])
167170
native = self.root / "native.png"
168171
native.write_bytes(b"native")
169172
self.relative.return_value = "native.png"
@@ -179,27 +182,28 @@ def test_priority_and_missing_custom_do_not_fall_back_to_another_image(self):
179182

180183
def test_save_reset_preserve_other_script_and_source_files(self):
181184
save_wallpapers({"other": "unchanged.png"})
182-
wallpaper.set_wallpaper("script", str(self.default))
185+
wallpaper.set_wallpaper("script", str(self.image))
183186
self.assertEqual(
184-
load_wallpapers(), {"other": "unchanged.png", "script": str(self.default)}
187+
load_wallpapers(), {"other": "unchanged.png", "script": str(self.image)}
185188
)
186189
wallpaper.set_wallpaper("script", None)
187190
self.assertEqual(load_wallpapers(), {"other": "unchanged.png"})
188-
self.assertEqual(self.default.read_bytes(), b"default")
191+
self.assertEqual(self.image.read_bytes(), b"custom")
189192
before = (self.root / "config/wallpaper.json").read_bytes()
190193
for path in ("", "missing.png", str(self.root), "bad.exe"):
191194
with self.subTest(path=path), self.assertRaises(wallpaper.InvalidWallpaper):
192195
wallpaper.set_wallpaper("script", path)
193196
self.assertEqual((self.root / "config/wallpaper.json").read_bytes(), before)
194197

195198
def test_cache_uses_current_source_identity_and_rejects_stale_data(self):
199+
wallpaper.set_wallpaper("script", str(self.image))
196200
state = wallpaper.wallpaper_view("script")
197201
jpeg = base64.b64encode(b"\xff\xd8test\xff\xd9").decode()
198202
self.assertTrue(wallpaper.save_wallpaper_cache("script", state["token"], jpeg))
199203
cache = Path(wallpaper.wallpaper_view("script")["cache"])
200204
self.assertEqual(cache.parent, self.root / "config/wallpaper_cache")
201205
self.assertEqual(cache.read_bytes(), b"\xff\xd8test\xff\xd9")
202-
self.default.write_bytes(b"changed source")
206+
self.image.write_bytes(b"changed source")
203207
self.assertIsNone(wallpaper.wallpaper_view("script")["cache"])
204208
self.assertFalse(wallpaper.save_wallpaper_cache("script", state["token"], jpeg))
205209
for invalid in ("not base64", base64.b64encode(b"not jpeg").decode()):

‎python-gui/src/gui/controllers/background.py‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@
1919

2020
logger = logging.getLogger(__name__)
2121

22-
# 兜底背景:脚本未配置背景图时使用(相对项目根)
23-
DEFAULT_BG = "assets/ds.jpg"
24-
2522
# 自定义壁纸缓存:用户选图时按最长边压到 WALLPAPER_MAX_SIDE 后存于
2623
# config/wallpaper_cache/<script_name>.jpg,resolve_bg 优先返回缓存,避免大图
2724
# 直接进 GPU 纹理(与 main.qml 的 sourceSize 互补)。视频首帧也复用此尺寸上限。
@@ -79,14 +76,17 @@ def background_version(self) -> int:
7976
return self._bg_version
8077

8178
def resolve_bg(self, game: dict) -> str | None:
82-
"""返回该脚本应使用的背景路径(自定义壁纸缓存 → 自定义壁纸 → 脚本背景 → DEFAULT_BG)。
79+
"""返回该脚本应使用的背景路径(自定义壁纸缓存 → 自定义壁纸 → 脚本背景)。
8380
8481
文件不存在返回 None(走渐变兜底)。
8582
8683
Args:
8784
game: 当前脚本数据。
8885
"""
89-
resolved = resolve_script_path(self._wallpaper_for(game))
86+
path = self._wallpaper_for(game)
87+
if not path:
88+
return None
89+
resolved = resolve_script_path(path)
9090
if not os.path.isfile(resolved):
9191
return None
9292
return resolved
@@ -98,7 +98,7 @@ def _script_background(self, script_name: str) -> str:
9898
script_name: 脚本标识名。
9999
100100
Returns:
101-
背景图绝对路径;未适配/未声明/文件缺失 → 空字符串(交 DEFAULT_BG 兜底)。
101+
背景图绝对路径;未适配/未声明/文件缺失 → 空字符串(使用渐变背景)。
102102
"""
103103
rel = get_background_rel_path(script_name)
104104
if not rel:
@@ -110,7 +110,7 @@ def _script_background(self, script_name: str) -> str:
110110
return path if os.path.isfile(path) else ""
111111

112112
def _wallpaper_for(self, game: dict) -> str:
113-
"""解析某脚本应使用的背景路径:定位源(自定义壁纸 → 脚本背景图 → DEFAULT_BG),
113+
"""解析某脚本应使用的背景路径:定位源(自定义壁纸 → 脚本背景图),
114114
并判定图像/视频。图像交给 _build_wallpaper_cache 确保缓存,视频直接用源路径。
115115
resolve_bg 负责 resolve + isfile 守卫。
116116
@@ -120,7 +120,7 @@ def _wallpaper_for(self, game: dict) -> str:
120120
script_name = game["script_name"]
121121
wallpapers = self.read_wallpapers()
122122
if script_name not in wallpapers:
123-
return self._script_background(script_name) or DEFAULT_BG
123+
return self._script_background(script_name)
124124
src_path = wallpapers[script_name]
125125
if not os.path.isfile(src_path):
126126
return src_path # 源图缺失:交回 resolve_bg 的 isfile 守卫,走渐变兜底

‎python-gui/tests/exe/test_image_formats_exe.py‎

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,6 @@
2121
"imageformats",
2222
)
2323

24-
# 与 src/gui/controllers/background.py 的 DEFAULT_BG 一致(脚本未声明背景时的兜底图)
25-
DEFAULT_BG = "assets/ds.jpg"
26-
2724
# 扩展名 → 提供该格式解码能力的 Qt 图片插件。
2825
# png / bmp 等由 Qt 内建支持,不需要插件,故不在表内。
2926
_EXT_PLUGIN = {
@@ -40,12 +37,12 @@
4037

4138

4239
def _declared_backgrounds() -> dict[str, str]:
43-
"""收集项目声明用到的背景图:脚本标识 → 相对路径(含兜底图)。
40+
"""收集项目声明用到的背景图:脚本标识 → 相对路径。
4441
4542
Returns:
46-
脚本标识到背景图相对路径的映射;兜底图以键 ``__default__`` 表示。
43+
脚本标识到背景图相对路径的映射。
4744
"""
48-
backgrounds = {"__default__": DEFAULT_BG}
45+
backgrounds = {}
4946
for name in set_config._CONFIGS:
5047
rel = get_background_rel_path(name)
5148
if rel:
@@ -103,7 +100,9 @@ def test_packaged_plugins_decode_declared_backgrounds(self):
103100
QCoreApplication.setLibraryPaths([os.path.dirname(IMAGEFORMATS)])
104101

105102
samples = {
106-
"qjpeg.dll": os.path.join(package_dir(), DEFAULT_BG),
103+
"qjpeg.dll": os.path.join(
104+
PROJECT_ROOT, "python-gui", "tests", "fixtures", "background.jpg"
105+
),
107106
"qwebp.dll": os.path.join(
108107
PROJECT_ROOT, "python-gui", "tests", "fixtures", "background.webp"
109108
),
632 Bytes
Loading

0 commit comments

Comments
 (0)