From 9495bb3cf5e434856814294185628f67672c06b7 Mon Sep 17 00:00:00 2001 From: HaBaDEDE <168924925+HaBaDEDE@users.noreply.github.com> Date: Sat, 15 Aug 2026 00:31:56 +0800 Subject: [PATCH] Add project website and automated releases --- .github/workflows/windows.yml | 70 +++++++++++++++++ README.md | 2 + docs/.nojekyll | 1 + docs/index.html | 140 +++++++++++++++++++++++++++++++++ docs/media/peek-ghost-demo.mp4 | Bin 0 -> 57842 bytes docs/robots.txt | 4 + docs/site.css | 131 ++++++++++++++++++++++++++++++ docs/site.js | 24 ++++++ docs/sitemap.xml | 8 ++ scripts/build-release.ps1 | 2 + scripts/ci-smoke.ps1 | 29 +++++++ scripts/record-demo.py | 135 +++++++++++++++++++++++++++++++ 12 files changed, 546 insertions(+) create mode 100644 .github/workflows/windows.yml create mode 100644 docs/.nojekyll create mode 100644 docs/index.html create mode 100644 docs/media/peek-ghost-demo.mp4 create mode 100644 docs/robots.txt create mode 100644 docs/site.css create mode 100644 docs/site.js create mode 100644 docs/sitemap.xml create mode 100644 scripts/ci-smoke.ps1 create mode 100644 scripts/record-demo.py diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml new file mode 100644 index 0000000..c42281f --- /dev/null +++ b/.github/workflows/windows.yml @@ -0,0 +1,70 @@ +name: Windows build + +on: + push: + branches: [main] + tags: ["v*"] + pull_request: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + +jobs: + build: + runs-on: windows-2022 + steps: + - name: Check out source + uses: actions/checkout@v4 + + - name: Configure x64 Release + run: cmake -S . -B build/release -G "Visual Studio 17 2022" -A x64 + + - name: Build + run: cmake --build build/release --config Release --parallel + + - name: Run self-test + shell: pwsh + run: powershell.exe -NoProfile -ExecutionPolicy Bypass -File ./scripts/ci-smoke.ps1 -Exe ./build/release/bin/Release/Peek.exe + + - name: Prepare artifact + shell: pwsh + run: | + New-Item -ItemType Directory -Force -Path artifact | Out-Null + Copy-Item build/release/bin/Release/Peek.exe artifact/Peek.exe + $hash = (Get-FileHash artifact/Peek.exe -Algorithm SHA256).Hash + "$hash Peek.exe" | Set-Content artifact/SHA256SUMS.txt -Encoding ascii + + - name: Upload build artifact + uses: actions/upload-artifact@v4 + with: + name: Peek-windows-x64 + path: artifact/* + if-no-files-found: error + + publish: + if: startsWith(github.ref, 'refs/tags/v') + needs: build + runs-on: windows-2022 + permissions: + contents: write + steps: + - name: Download verified build + uses: actions/download-artifact@v4 + with: + name: Peek-windows-x64 + path: artifact + + - name: Create or update GitHub Release + shell: pwsh + env: + GH_TOKEN: ${{ github.token }} + run: | + gh release view "${{ github.ref_name }}" 2>$null + if ($LASTEXITCODE -eq 0) { + gh release upload "${{ github.ref_name }}" artifact/Peek.exe artifact/SHA256SUMS.txt --clobber + } else { + gh release create "${{ github.ref_name }}" artifact/Peek.exe artifact/SHA256SUMS.txt --generate-notes --title "${{ github.ref_name }}" + } + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } diff --git a/README.md b/README.md index 8bef5f9..7b818df 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,8 @@ [![License: MIT](https://img.shields.io/github/license/HaBaDEDE/Peek?style=flat-square)](LICENSE) ![Windows 10/11](https://img.shields.io/badge/Windows-10%20%7C%2011-0078D4?style=flat-square&logo=windows) +**[官方网站 / Official website](https://habadede.github.io/Peek/)** + [简体中文](#readme-zh) · [English](#readme-en) **[下载最新版本](https://github.com/HaBaDEDE/Peek/releases/latest/download/Peek.exe) · [Download latest release](https://github.com/HaBaDEDE/Peek/releases/latest/download/Peek.exe)** diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/docs/.nojekyll @@ -0,0 +1 @@ + diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..d461412 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,140 @@ + + + + + + + + + + + + + Peek — Tiny native Windows utility + + + + + +
+ + + Peek + + +
+ +
+
+
+

NATIVE WINDOWS UTILITY

+

Three answers. One tiny Windows tool.

+

Find what flashed past, who locked a file, and which Windows UI is under the pointer.

+ +

Windows 10/11 · x64 · Portable · No account · No telemetry

+
+
+ Peek Ghost showing recent process events +
+
+ +
+
+ +

The answer is one hotkey away.

+
+ +
+ +
+
+ +

Only what you need, when you need it.

+
+ +
+
+ 01 +

Ghost

+

What just flashed past?

+

Keeps the latest short-lived process and top-level window events in memory, including lifetime, path, command line, and parent process when Windows makes them available.

+ Ctrl + Shift + G +
+ Ghost feature +
+ +
+
+ 02 +

Unlock

+

Who is using this file?

+

Drop a file or choose one. Peek uses Windows Restart Manager to identify likely owners and lets you reveal the executable or end the process after confirmation.

+
+ Unlock feature +
+ +
+
+ 03 +

Focus

+

What Windows UI is under the pointer?

+

Highlight a window or control and read its HWND, process, class, title, rectangle, and available UI Automation properties.

+ Ctrl + Shift + F +
+ Focus feature +
+
+ +
+
+ +

Native, offline, and understandable.

+
+ +
+ +
+ Peek icon +
+

Keep the answer one action away.

+

Download the portable Windows x64 release.

+
+ Download +
+
+ + + + + diff --git a/docs/media/peek-ghost-demo.mp4 b/docs/media/peek-ghost-demo.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..e402a5ccec698767736f76977057d31711cc5d07 GIT binary patch literal 57842 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 { + const button = document.querySelector("#language"); + const translatable = document.querySelectorAll("[data-en][data-zh]"); + const stored = localStorage.getItem("peek-site-language"); + const preferred = navigator.language.toLowerCase().startsWith("zh") ? "zh" : "en"; + + function setLanguage(language) { + const next = language === "zh" ? "zh" : "en"; + document.documentElement.lang = next === "zh" ? "zh-CN" : "en"; + document.title = next === "zh" ? "Peek — 极小的原生 Windows 工具" : "Peek — Tiny native Windows utility"; + translatable.forEach((element) => { + element.textContent = element.dataset[next]; + }); + button.textContent = next === "zh" ? "EN" : "中文"; + button.dataset.language = next; + localStorage.setItem("peek-site-language", next); + } + + button.addEventListener("click", () => { + setLanguage(button.dataset.language === "zh" ? "en" : "zh"); + }); + + setLanguage(stored || preferred); +})(); diff --git a/docs/sitemap.xml b/docs/sitemap.xml new file mode 100644 index 0000000..f926f77 --- /dev/null +++ b/docs/sitemap.xml @@ -0,0 +1,8 @@ + + + + https://habadede.github.io/Peek/ + monthly + 1.0 + + diff --git a/scripts/build-release.ps1 b/scripts/build-release.ps1 index c900881..2bdb6e1 100644 --- a/scripts/build-release.ps1 +++ b/scripts/build-release.ps1 @@ -18,7 +18,9 @@ if (-not $cmake) { throw "CMake 3.24+ was not found in PATH or Visual Studio." } $cmakePath = if ($cmake.Source) { $cmake.Source } else { $cmake.FullName } & $cmakePath -S $root -B $build -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=Release +if ($LASTEXITCODE -ne 0) { throw "CMake configure failed with code $LASTEXITCODE." } & $cmakePath --build $build --config Release --parallel +if ($LASTEXITCODE -ne 0) { throw "Release build failed with code $LASTEXITCODE." } $exe = Join-Path $build "bin/Release/Peek.exe" if (-not (Test-Path $exe)) { diff --git a/scripts/ci-smoke.ps1 b/scripts/ci-smoke.ps1 new file mode 100644 index 0000000..1082046 --- /dev/null +++ b/scripts/ci-smoke.ps1 @@ -0,0 +1,29 @@ +[CmdletBinding()] +param([Parameter(Mandatory=$true)][string]$Exe) + +$ErrorActionPreference = "Stop" +$exePath = (Resolve-Path $Exe).Path +$report = Join-Path $env:TEMP "Peek-ci-selftest-$PID.txt" +$peek = $null + +try { + $selfTest = Start-Process $exePath -ArgumentList '--self-test',('"' + $report + '"') -PassThru -Wait + if ($selfTest.ExitCode -ne 0) { throw "Peek self-test failed with code $($selfTest.ExitCode)." } + if (-not (Test-Path $report)) { throw "Peek did not write its self-test report." } + + $contents = Get-Content $report + $contents + if ($contents -match '^FAIL') { throw "Peek self-test report contains a failure." } + + $peek = Start-Process $exePath -PassThru + Start-Sleep -Milliseconds 1000 + if ($peek.HasExited) { throw "Peek exited during startup with code $($peek.ExitCode)." } + Write-Host "Startup smoke test passed (PID $($peek.Id))." +} +finally { + if ($peek -and -not $peek.HasExited) { + Stop-Process -Id $peek.Id -Force -ErrorAction SilentlyContinue + $peek.WaitForExit(5000) | Out-Null + } + Remove-Item -LiteralPath $report -Force -ErrorAction SilentlyContinue +} diff --git a/scripts/record-demo.py b/scripts/record-demo.py new file mode 100644 index 0000000..0de643f --- /dev/null +++ b/scripts/record-demo.py @@ -0,0 +1,135 @@ +"""Record the real Peek window into a privacy-safe 1280x720 product demo.""" + +from argparse import ArgumentParser +from ctypes import Structure, byref, sizeof, windll +from ctypes.wintypes import DWORD, HWND, LONG, RECT +from pathlib import Path +import sys +from time import monotonic, sleep + +from PIL import Image, ImageDraw, ImageFilter, ImageFont, ImageGrab + + +ROOT = Path(__file__).resolve().parents[1] +sys.path.insert(0, str(ROOT / "build" / "video-tools")) +import imageio_ffmpeg # noqa: E402 + + +DWMWA_EXTENDED_FRAME_BOUNDS = 9 + + +class DwmRect(Structure): + _fields_ = [("left", LONG), ("top", LONG), ("right", LONG), ("bottom", LONG)] + + +def capture_window(hwnd: HWND) -> Image.Image: + visible = DwmRect() + result = windll.dwmapi.DwmGetWindowAttribute( + hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, byref(visible), DWORD(sizeof(visible))) + if result != 0: + fallback = RECT() + if not windll.user32.GetWindowRect(hwnd, byref(fallback)): + raise RuntimeError("Unable to read Peek window bounds") + visible = DwmRect(fallback.left, fallback.top, fallback.right, fallback.bottom) + return ImageGrab.grab( + bbox=(visible.left, visible.top, visible.right, visible.bottom), + all_screens=True, + ).convert("RGB") + + +def make_frame(window: Image.Image, elapsed: float, icon: Image.Image, + empty_window: Image.Image) -> Image.Image: + canvas = Image.new("RGB", (1280, 720), (11, 23, 40)) + draw = ImageDraw.Draw(canvas) + regular = ImageFont.truetype("C:/Windows/Fonts/segoeui.ttf", 24) + semibold = ImageFont.truetype("C:/Windows/Fonts/seguisb.ttf", 48) + small = ImageFont.truetype("C:/Windows/Fonts/segoeui.ttf", 18) + shortcut = ImageFont.truetype("C:/Windows/Fonts/seguisb.ttf", 26) + + canvas.paste(icon, (58, 51), icon) + draw.text((145, 58), "Peek", font=semibold, fill=(245, 248, 252)) + draw.text((59, 151), "Ghost", font=small, fill=(92, 153, 255)) + + if elapsed < 4.3: + title, detail = "A window flashes.", "It is gone before you can read it." + step = "01" + elif elapsed < 8.0: + title, detail = "Press one hotkey.", "Open the latest Ghost event immediately." + step = "02" + elif elapsed < 13.0: + title, detail = "Peek identifies it.", "Process, lifetime, path, and parent." + step = "03" + else: + title, detail = "One action. One answer.", "Native Win32 · Offline · Portable" + step = "04" + + draw.text((59, 222), step, font=small, fill=(111, 145, 190)) + draw.multiline_text((59, 267), title, font=semibold, fill=(245, 248, 252), spacing=8) + draw.multiline_text((59, 344), detail, font=regular, fill=(161, 178, 202), spacing=8) + if 4.3 <= elapsed < 13.0: + draw.rounded_rectangle((59, 447, 416, 513), radius=9, + fill=(24, 43, 69), outline=(61, 91, 130)) + draw.text((237, 480), "Ctrl + Shift + G", font=shortcut, + fill=(245, 248, 252), anchor="mm") + + display_window = empty_window if elapsed < 4.3 else window + target_height = 664 + target_width = round(display_window.width * target_height / display_window.height) + rendered = display_window.resize((target_width, target_height), Image.Resampling.LANCZOS) + shadow = Image.new("RGBA", canvas.size, (0, 0, 0, 0)) + shadow_draw = ImageDraw.Draw(shadow) + x, y = 1280 - target_width - 38, 28 + shadow_draw.rounded_rectangle((x + 8, y + 12, x + target_width + 8, y + target_height + 12), + radius=18, fill=(0, 0, 0, 115)) + shadow = shadow.filter(ImageFilter.GaussianBlur(17)) + canvas = Image.alpha_composite(canvas.convert("RGBA"), shadow).convert("RGB") + canvas.paste(rendered, (x, y)) + return canvas + + +def main() -> None: + parser = ArgumentParser() + parser.add_argument("output", type=Path) + parser.add_argument("--title", default="Peek") + parser.add_argument("--duration", type=float, default=17.0) + parser.add_argument("--fps", type=int, default=10) + args = parser.parse_args() + + hwnd = windll.user32.FindWindowW(None, args.title) + deadline = monotonic() + 30 + while not hwnd and monotonic() < deadline: + sleep(.1) + hwnd = windll.user32.FindWindowW(None, args.title) + if not hwnd: + raise SystemExit("Peek window not found") + + icon = Image.open(ROOT / "docs/images/peek-icon.png").convert("RGBA") + icon.thumbnail((70, 70), Image.Resampling.LANCZOS) + empty_window = Image.open(ROOT / "docs/images/peek-demo-ghost-hd.png").convert("RGB") + args.output.parent.mkdir(parents=True, exist_ok=True) + writer = imageio_ffmpeg.write_frames( + str(args.output), (1280, 720), fps=args.fps, codec="libx264", + pix_fmt_in="rgb24", pix_fmt_out="yuv420p", quality=5, + output_params=["-movflags", "+faststart", "-preset", "slow"]) + writer.send(None) + started = monotonic() + frame_interval = 1 / args.fps + next_frame = started + try: + while True: + now = monotonic() + elapsed = now - started + if elapsed >= args.duration: + break + if now < next_frame: + sleep(next_frame - now) + window = capture_window(hwnd) + writer.send(make_frame(window, elapsed, icon, empty_window).tobytes()) + next_frame += frame_interval + finally: + writer.close() + print(f"Recorded {args.output} ({args.duration:.1f}s, {args.fps} fps)") + + +if __name__ == "__main__": + main()