scripts/capture_store_pages.ps1
Rama main · réplica de lectura del repositorio original.
# Capture Clips Kitty's people-free pages for the Microsoft Store listing.
#
# powershell -ExecutionPolicy Bypass -File scripts\capture_store_pages.ps1
#
# ONLY visits Models and Settings. Every other page shows the library: clip
# thumbnails on Clip Editor and Creators, and video titles and channel names on
# Dashboard and Queue. None of that belongs in a public listing - the footage
# is someone else's, and neither their face nor their channel name is ours to
# advertise with.
#
# Pass -All to include Dashboard and Queue, for when there is finally footage
# that can be shown.
#
# Uses PrintWindow rather than a screen grab. A screen grab copies whatever
# pixels are at the window's coordinates, so if the app loses focus for even a
# moment the image fills with the desktop behind it - file paths, other
# applications, whatever happens to be open. PrintWindow asks the window to
# draw itself into a bitmap instead, so nothing else can appear in the frame.
# PW_RENDERFULLCONTENT (0x2) is the flag that makes it work for the
# hardware-composited surfaces Chromium uses.
#
# Output: docs/store-screenshots/ (gitignored). Check every image before
# uploading anyway.
param([switch]$All)
Add-Type -AssemblyName System.Drawing
# -ReferencedAssemblies: the inline C# below uses System.Drawing.Bitmap, and
# loading the assembly into PowerShell does not put it on the compiler's path.
Add-Type -ReferencedAssemblies System.Drawing -TypeDefinition @"
using System;
using System.Drawing;
using System.Runtime.InteropServices;
public class Shot {
[DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr h);
[DllImport("user32.dll")] public static extern bool ShowWindow(IntPtr h, int c);
[DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr h, out RECT r);
[DllImport("user32.dll")] public static extern bool SetCursorPos(int x, int y);
[DllImport("user32.dll")] public static extern void mouse_event(uint f, uint x, uint y, uint d, int e);
[DllImport("user32.dll")] public static extern bool PrintWindow(IntPtr h, IntPtr dc, uint flags);
[StructLayout(LayoutKind.Sequential)] public struct RECT { public int L, T, R, B; }
public static Bitmap Grab(IntPtr h) {
RECT r; GetWindowRect(h, out r);
Bitmap bmp = new Bitmap(r.R - r.L, r.B - r.T);
using (Graphics g = Graphics.FromImage(bmp)) {
IntPtr dc = g.GetHdc();
PrintWindow(h, dc, 0x2); // PW_RENDERFULLCONTENT
g.ReleaseHdc(dc);
}
return bmp;
}
}
"@
$DOWN = 0x0002; $UP = 0x0004
# Sidebar offsets from the window's top-left, on a 1440x900 window. The
# sidebar is a fixed width, so these hold as the window grows.
$pages = @(
@{ n = "3-models"; y = 325 },
@{ n = "4-settings"; y = 373 }
)
if ($All) {
$pages = @(
@{ n = "1-dashboard"; y = 133 },
@{ n = "2-queue"; y = 181 }
) + $pages
}
$sidebarX = 110
$proc = Get-Process -Name "Clips Kitty" -ErrorAction SilentlyContinue |
Where-Object { $_.MainWindowHandle -ne 0 -and $_.MainWindowTitle } |
Select-Object -First 1
if (-not $proc) { Write-Output "Clips Kitty is not running."; exit 1 }
$h = $proc.MainWindowHandle
$outDir = Join-Path $PSScriptRoot "..\docs\store-screenshots"
New-Item -ItemType Directory -Force -Path $outDir | Out-Null
Get-ChildItem $outDir -Filter *.png -ErrorAction SilentlyContinue | Remove-Item -Force
[void][Shot]::ShowWindow($h, 9)
[void][Shot]::SetForegroundWindow($h)
Start-Sleep -Milliseconds 900
$r = New-Object Shot+RECT
[void][Shot]::GetWindowRect($h, [ref]$r)
Write-Output "window $($r.R - $r.L)x$($r.B - $r.T)"
if (($r.R - $r.L) -lt 1366) { Write-Output "NOTE: under the Store 1366px minimum - maximise and re-run" }
foreach ($p in $pages) {
# Re-assert focus before every click; a click on an unfocused window is
# consumed activating it and never reaches the button.
[void][Shot]::SetForegroundWindow($h)
Start-Sleep -Milliseconds 250
[void][Shot]::SetCursorPos($r.L + $sidebarX, $r.T + $p.y)
Start-Sleep -Milliseconds 200
[Shot]::mouse_event($DOWN, 0, 0, 0, 0)
[Shot]::mouse_event($UP, 0, 0, 0, 0)
Start-Sleep -Milliseconds 2000 # render, plus any fetch the page makes
$bmp = [Shot]::Grab($h)
$path = Join-Path $outDir "$($p.n).png"
$bmp.Save($path, [System.Drawing.Imaging.ImageFormat]::Png)
$bmp.Dispose()
Write-Output " $($p.n).png"
}
Write-Output ""
Write-Output "Captured to docs\store-screenshots\."
if (-not $All) {
Write-Output "Only Models and Settings: the other pages show titles, channel"
Write-Output "names or thumbnails. Pass -All if that is wanted."
}