feat: Playnite library sync plugin + exporter
A two-part Punktfunk plugin that syncs the Playnite library into the host
game library as the `playnite` provider:
- exporter/ — a minimal C# Playnite GenericPlugin ("Punktfunk Sync") that
writes punktfunk-library.json on every library change. Reading Playnite's
live-locked LiteDB from outside isn't robust, so this adapter runs inside
Playnite. Builds net462 via reference assemblies; packaged as a .pext.
- src/ — the TS plugin (on @punktfunk/host, rom-manager shape): watches the
export, embeds covers as data URLs, reconciles via
PUT /library/provider/playnite, with a console-hosted web UI + standalone
fallback + CLI. Launch = playnite://playnite/start/<id>, run by the host
in the interactive session so Playnite performs the real launch.
Verified locally: backend tsc + 23 tests + biome clean, SPA build, C#
exporter build + .pext pack.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
# 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 `../src/export-schema.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 )
|
||||
```
|
||||
Reference in New Issue
Block a user