# Bitcoin Pixel OBS

Native OBS source module for transparent Bitcoin Pixel banners. The source registers as **Bitcoin Pixel Banner** and keeps OBS callbacks as thin adapters around an OBS-independent C++ domain library.

## Supported baseline

- Official `obsproject/obs-plugintemplate` structure audited at `3e7d7ac3b5342cd7d9b88890b9c70b472d1520fc`
- OBS/libobs `32.2.2`
- C++17, CMake 3.28+
- GPL-2.0-or-later compatible; the final distribution must include the corresponding GPL license and notices for linked OBS code.
- `buildspec.json` pins the official-template OBS dependency and macOS package identity used by release automation.

## Local automated tests (no OBS required)

```sh
cmake --preset domain-tests
cmake --build --preset domain-tests
ctest --preset domain-tests
```

This preset includes the domain/state tests and the Qt Network adapter event-loop
suite. The adapter suite exercises conditional requests, redirects, bounded PNG
promotion, malformed/oversize rejection, timeout handling, and shutdown races
without requiring OBS or a live Bitcoin Pixel service.

## Native build environments

Native presets bootstrap only the checksum-pinned official OBS 32.2.2 source and
the matching 2026-07-15 OBS/Qt dependency bundles. No project secrets are used.
The current delivery target is Windows x64 for installation into OBS 32.2.2.

Windows x64 (Visual Studio 2022 with the Windows 10.0.22621 SDK):

```powershell
cmake --preset windows-x64
cmake --build --preset windows-x64
cmake --install build/windows-x64 --config RelWithDebInfo --prefix release/windows-x64
```

Mac mini local cross-build (pinned Linux container, clang-cl/lld-link, and xwin
MSVC/Windows SDK redistribution):

```sh
tools/windows-cross/build.sh
```

The script caches checksum-pinned xwin downloads under `.deps/xwin-cache` and
the generated sysroot under `.deps/xwin`, so an interrupted SDK acquisition
resumes without rebuilding or committing generated Microsoft files. A successful
run creates `release/windows-x64/bitcoinpixel-obs-windows-x64-obs-32.2.2.zip`.

## Windows installation and smoke test

OBS 32.2.2 on Windows discovers third-party plugin bundles from the system-wide
`%PROGRAMDATA%\\obs-studio\\plugins` directory. Installing there can require an
administrator account, depending on the machine's permissions:

1. Close OBS 32.2.2.
2. Extract the ZIP.
3. Copy the extracted `bitcoinpixel-obs` directory to
   `%PROGRAMDATA%\\obs-studio\\plugins\\`. Approve the Windows administrator
   prompt if one appears. The installed DLL must be at
   `%PROGRAMDATA%\\obs-studio\\plugins\\bitcoinpixel-obs\\bin\\64bit\\bitcoinpixel-obs.dll`.
   Keep the complete package together: its matching Qt Schannel TLS provider is
   under `data\\qt-plugins\\tls` and is required for HTTPS discovery.
4. Start OBS and inspect **Help → Log Files → View Current Log** for the
   `bitcoinpixel-obs` module load result and the `[bitcoin-pixel] TLS` line. It
   must report `support=yes` and `active-backend=schannel`.
5. In **Sources**, choose **Add → Bitcoin Pixel Banner**, enter a banner ID,
   current URL, or immutable revision URL from `https://bitcoinpixel.lol`,
   and confirm the source can be moved,
   resized, and cropped with normal OBS transforms.
6. In current mode, choose **Load & Preview**, then explicitly **Accept** or
   **Reject** in the preview dialog. Confirm **Reject** and **Retry** preserve
   the last accepted pixels.
7. Leave OBS unfocused while a later revision is discovered. Confirm Windows
   requests taskbar attention and shows an update notification without taking
   focus, then confirm source properties retain **UPDATE WAITING** until a decision.

If OBS still does not discover the module, use the installation-local fallback:
copy `bitcoinpixel-obs.dll` to
`C:\\Program Files\\obs-studio\\obs-plugins\\64bit\\` (or the matching custom OBS
installation directory), then restart OBS and inspect the fresh log. Do not keep
both copies installed after discovery is confirmed.

To upgrade cleanly, close OBS, replace the complete
`%PROGRAMDATA%\\obs-studio\\plugins\\bitcoinpixel-obs` directory, and restart OBS.
To roll back, close OBS and replace that directory with the previous package.
To uninstall, close OBS and remove that directory. Source approval snapshots are
kept separately under the OBS module configuration directory so uninstalling the
binary does not silently destroy streamer-approved pixels; remove the module's
`sources` state directory only when intentionally resetting local approvals.

OBS logs are stored under `%APPDATA%\\obs-studio\\logs`. The plugin has no
localhost process, service, credentials, or private cache. The build/download
cache (`.deps/`) and build outputs exist only on development machines and are not
installed with the user package.

The first configure downloads the audited dependencies into `.deps/`, verifies
their SHA-256 hashes from `buildspec.json`, and builds the matching libobs
development surface. The `release/` tree is the packaging input; neither build
command installs into OBS or mutates the user's system. A clean runner therefore
needs CMake 3.28+, Git, and the platform compiler only—OBS and Qt are bootstrapped.

The Windows package carries only the Qt 6.11.1 Schannel backend from the same
checksum-pinned OBS Qt dependency bundle used to link the module. It uses the
Windows TLS provider and does not bundle OpenSSL or replace OBS's Qt DLLs. The
module adds its private `data/qt-plugins` root before the first network request
and logs Qt's available/active TLS backend for runtime diagnosis.

Persistence is domain-owned and native discovery transport consumes the `metadata_http_policy` boundary for canonical URL, conditional request, timeout/body, redirect, status, and strict decode rules. Source properties apply a valid entered banner ID immediately and expose **Load & Preview**; the bounded operator-only preview dialog owns explicit Accept/Reject without changing program output before acceptance. Validated candidate metadata may establish the source's intrinsic OBS dimensions before approval so the scene transform starts at the banner's real size, while Accept remains the only path that changes the approved program texture. Current/live sources also expose Retry, which clears backoff without clearing approved output. Qt Network remains asynchronous and approved GPU upload is isolated from OBS callbacks. Static QR output is encoded locally with the OBS dependency bundle's MIT-licensed qrcodegencpp library and composed as a high-contrast sidecar into the approved texture; no remote QR service is used. No Browser Source or localhost service is used.
