e8acf922de
Overview (exporter health, Playnite version, counts, sync, live SSE activity, and a first-run panel that names the exact ingest path the .pext writes to), Library (covers + per-game include toggles + why-not-synced), Settings (filters, art delivery, sync cadence, paths). Data layer is AtomHttpApi atoms derived from the shared contract; the whole thing runs with zero host against an in-browser mock transport with four scenarios, and Storybook renders the real pages on the same fixtures. CI now asserts the production bundle carries no fixture strings. Also: CI rebuilt for the workspace layout (one root install, per-package typecheck, publish from plugin/ on a v* tag) with the exporter job and `publish: needs [build, exporter]` unchanged; README rewritten around the three workspaces, with the ingest inbox explained as the load-bearing mechanism it is.
70 lines
2.5 KiB
Markdown
70 lines
2.5 KiB
Markdown
# Punktfunk Sync — Playnite exporter
|
|
|
|
The Playnite side of [`@punktfunk/plugin-playnite`](../README.md): a minimal
|
|
[GenericPlugin](https://api.playnite.link/docs/tutorials/extensions/genericPlugins.html) that writes
|
|
your library to `punktfunk-library.json` whenever it changes. The Punktfunk plugin on the host reads
|
|
that file and reconciles it into the streaming library.
|
|
|
|
It exists because Playnite keeps its library database (LiteDB) open and locked while running, so the
|
|
only robust way to read the library — with correct install state, art paths and metadata — is from
|
|
*inside* Playnite. This plugin does exactly that and nothing else: no network, no settings, no UI.
|
|
|
|
## What it writes
|
|
|
|
On startup, on every `OnLibraryUpdated`, and (debounced) on any per-game add/update/remove, it writes:
|
|
|
|
```
|
|
%APPDATA%\Playnite\ExtensionsData\<plugin-guid>\punktfunk-library.json
|
|
```
|
|
|
|
Shape (kept in lockstep with `../contract/src/export.ts`):
|
|
|
|
```jsonc
|
|
{
|
|
"schema": 1,
|
|
"generatedAt": "2026-07-18T21:00:00Z",
|
|
"playnite": { "version": "10.x", "mode": "Desktop" },
|
|
"games": [
|
|
{
|
|
"id": "e3b0c442-98fc-1c14-9afb-4c8996fb9242", // Playnite Guid = reconcile external_id
|
|
"name": "Hollow Knight",
|
|
"installed": true,
|
|
"hidden": false,
|
|
"source": "Steam",
|
|
"platforms": ["PC (Windows)"],
|
|
"cover": "C:\\Users\\me\\AppData\\Roaming\\Playnite\\library\\files\\ab\\cover.jpg",
|
|
"background": null,
|
|
"icon": null
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
Art paths are **absolute** (resolved via `IPlayniteAPI.Database.GetFullFilePath`). Filtering
|
|
(installed-only, hidden, per-source) happens on the Punktfunk side, so the export is the full library.
|
|
|
|
You can also trigger a write by hand: Playnite **main menu → Punktfunk Sync → Export library to
|
|
Punktfunk now**.
|
|
|
|
## Install (for users)
|
|
|
|
Double-click `punktfunk-sync.pext` — Playnite installs it like any add-on — and restart Playnite.
|
|
Grab the `.pext` from the repo's [CI artifacts](https://git.unom.io/unom/punktfunk-plugin-playnite/actions).
|
|
|
|
## Build
|
|
|
|
Targets .NET Framework 4.6.2 (Playnite's runtime). Thanks to
|
|
`Microsoft.NETFramework.ReferenceAssemblies` it builds with the plain .NET SDK on any OS — no Windows
|
|
or MSBuild needed:
|
|
|
|
```sh
|
|
dotnet build PunktfunkSync.csproj -c Release
|
|
# output: bin/Release/PunktfunkSync.dll + extension.yaml (PlayniteSDK.dll is provided by Playnite)
|
|
```
|
|
|
|
Package the `.pext` (a zip of the two files):
|
|
|
|
```sh
|
|
( cd bin/Release && zip -j ../../punktfunk-sync.pext extension.yaml PunktfunkSync.dll )
|
|
```
|