diff --git a/.github/workflows/screenshots.yml b/.github/workflows/screenshots.yml index 6b5a74f..8aeadc3 100644 --- a/.github/workflows/screenshots.yml +++ b/.github/workflows/screenshots.yml @@ -21,6 +21,10 @@ on: run-id: description: 'windows-build run to take the binaries from (default: the build of this commit)' required: false + language: + description: 'lang/ basename to run the GUI in, e.g. Francais.' + required: false + default: English permissions: contents: read @@ -119,14 +123,17 @@ jobs: shell: pwsh env: MODE: ${{ inputs.mode }} + LANGUAGE: ${{ inputs.language }} run: | python -m pip install --quiet pywin32 pillow pywinauto $script = 'screenshot-walk.py' $site = @('--site-host', 'www.example.com') + $lang = @() + if ($env:LANGUAGE) { $lang = @('--language', $env:LANGUAGE) } # The probe only answers whether the machine renders at all, and takes no site. - if ($env:MODE -eq 'probe') { $script = 'screenshot-probe.py'; $site = @() } + if ($env:MODE -eq 'probe') { $script = 'screenshot-probe.py'; $site = @(); $lang = @() } Write-Host "running $script" - python "tools\$script" --exe app\WinHTTrack.exe --out shots @site + python "tools\$script" --exe app\WinHTTrack.exe --out shots @site @lang - name: Upload the screens if: always() diff --git a/tools/screenshot-walk.py b/tools/screenshot-walk.py index b2d83e9..46173f1 100644 --- a/tools/screenshot-walk.py +++ b/tools/screenshot-walk.py @@ -327,12 +327,22 @@ def options(main, pid, ids, shots, connections=8, rate=2_000_000): sheet, tabs, captions = open_options(main, pid, ids) count = win32gui.SendMessage(tabs, TCM_GETITEMCOUNT, 0, 0) print(f" options sheet {sheet:#x}: {count} tabs") - at = {} + # Keyed by a control each page owns: tab labels come from the .rc and stay + # English, but a display string would be the wrong key regardless. + wanted = {"IDC_maxrate": rate, "IDC_connexion": connections} + owns = {} for i in range(count): win32gui.SendMessage(sheet, PSM_SETCURSEL, i, 0) time.sleep(0.6) page = slug(captions.get_tab_text(i)) - at[page] = i + for control in wanted: + # Both are combo boxes, and resource.h gives IDC_pausebytes, an edit box on + # another page, the same 1051 as IDC_connexion. Match the class as well. + if find(sheet, control_id=ids[control], class_name="ComboBox") is not None: + if control in owns: + raise RuntimeError(f"{control} is on pages {owns[control]} and {i}, " + "so its id does not name one page") + owns[control] = i shots.take(sheet, f"{4 + i:02d}_options_{page}") gated(sheet, ids, count) # Eight parallel transfers, so the animation shows a mirror working rather than one @@ -340,11 +350,10 @@ def options(main, pid, ids, shots, connections=8, rate=2_000_000): # rate cap goes up with it: eight transfers sharing the engine's 100 KB/s default # would still crawl. Each on its own page, since a control on a page that is not on # top is not visible to find(). - for page, control, value in (("limits", "IDC_maxrate", rate), - ("flow_control", "IDC_connexion", connections)): - if page not in at: - raise RuntimeError(f"no {page} tab to set the mirror up on") - win32gui.SendMessage(sheet, PSM_SETCURSEL, at[page], 0) + for control, value in wanted.items(): + if control not in owns: + raise RuntimeError(f"no options page owns {control} to set the mirror up on") + win32gui.SendMessage(sheet, PSM_SETCURSEL, owns[control], 0) time.sleep(0.6) set_text(find(sheet, control_id=ids[control]), str(value)) close_options(sheet, pid, IDOK) @@ -352,15 +361,18 @@ def options(main, pid, ids, shots, connections=8, rate=2_000_000): reopen_options(main, pid, ids) -def run(pid, ids, shots, url, base_path): +def run(pid, ids, shots, url, base_path, language): # Only a first run offers the language, so a VM replay skips this shot rather than # failing on it. try: lang = wait(lambda: window_titled(pid, "About WinHTTrack"), "the language dialog", 25) shots.take(lang, "00_language_preference") combo = ComboBoxWrapper(find(lang, control_id=ids["IDC_lang"])) - print(f" languages: {combo.selected_text()!r} of {len(combo.item_texts())}") - combo.select("English") + names = combo.item_texts() + print(f" languages: {combo.selected_text()!r} of {len(names)}, picking {language!r}") + if language not in names: + raise RuntimeError(f"no {language!r} in the language list: {sorted(names)}") + combo.select(language) click(find(lang, control_id=IDOK, class_name="Button")) except Timeout: print(" no language dialog: not a first run") @@ -429,6 +441,8 @@ def main(): ap.add_argument("--site-port", type=int, default=8099, help="port to serve it on (0 picks a free one)") ap.add_argument("--base-path", default=r"C:\shots-mirror") + ap.add_argument("--language", default="English", + help="lang/ basename as the combo lists it, so Francais rather than French") args = ap.parse_args() ids = resource_ids(args.resource_h) @@ -442,7 +456,7 @@ def main(): exe = os.path.abspath(args.exe) proc = subprocess.Popen([exe], cwd=os.path.dirname(exe)) try: - run(proc.pid, ids, shots, site_url, args.base_path) + run(proc.pid, ids, shots, site_url, args.base_path, args.language) except Exception as e: print(f"FAILED: {e}") diagnose(proc.pid, args.out) diff --git a/tools/screenshots.md b/tools/screenshots.md index 3f51fc4..e01e103 100644 --- a/tools/screenshots.md +++ b/tools/screenshots.md @@ -22,9 +22,10 @@ a real site. ## Replay Run the **screenshots** workflow (Actions → Run workflow) and download the -`screenshots` artifact. It takes the binaries from the last green `windows-build` on -the branch you dispatch it from, falling back to master, so a new option page is shot -from the build that added it. `run-id` overrides that; `mode: probe` runs +`screenshots` artifact. It takes the binaries from the green `windows-build` of the +commit you dispatch it from, so a new option page is shot from the build that added it. +A branch with no build of its own stops rather than shooting master's binaries, so pass +`run-id` for a change that builds nothing. `mode: probe` runs `screenshot-probe.py` instead, which only answers whether the machine renders and captures at all — reach for it when the runner image changes or when moving to a VM. @@ -41,6 +42,12 @@ and in the mirror folder name. For publication, pass `--site-host` as the workfl port stays visible, since `http.sys` holds 80 on the runner and 80 is excluded from binding there. +`--language` runs the GUI in another catalog, as the workflow input of the same name +does. It takes the lang/ basename the first-run combo lists, which for several +languages is not the translated name, so `Francais` rather than `French`. English is +the default and the only catalog with no high bytes, so it is the one language that +exercises none of the conversion `LANG_LOAD` does. + ## Adding an option page Nothing to edit: the tabs are enumerated from the sheet and named after their caption,