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
11 changes: 9 additions & 2 deletions .github/workflows/screenshots.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand Down
36 changes: 25 additions & 11 deletions tools/screenshot-walk.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,40 +327,52 @@ 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
# file trickling in. Eight is the engine's ceiling; it clamps anything higher. The
# 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)
print(f" {connections} connections, {rate} B/s")
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")
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down
13 changes: 10 additions & 3 deletions tools/screenshots.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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,
Expand Down
Loading