Files
enricobuehler 6694be9848
CI / exporter (push) Failing after 24s
CI / build (push) Failing after 25s
CI / publish (push) Has been skipped
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>
2026-07-18 23:35:35 +02:00

69 lines
2.2 KiB
C#

using System.Collections.Generic;
using Playnite.SDK.Data;
namespace PunktfunkSync
{
// The on-disk contract with the Punktfunk `playnite` plugin. Keep these property names in lockstep
// with `src/export-schema.ts` (ExportedGame / LibraryExport). Serialized via the Playnite SDK's
// `Serialization.ToJson`, so `[SerializationPropertyName]` pins the JSON keys regardless of the
// serializer's default casing.
public class ExportedGame
{
// Playnite's stable game Guid ("d"-format, lowercase with dashes) — the reconcile external_id.
[SerializationPropertyName("id")]
public string Id { get; set; }
[SerializationPropertyName("name")]
public string Name { get; set; }
[SerializationPropertyName("installed")]
public bool Installed { get; set; }
[SerializationPropertyName("hidden")]
public bool Hidden { get; set; }
// Library source name ("Steam", "GOG", "Epic", emulator name…) or null.
[SerializationPropertyName("source")]
public string Source { get; set; }
[SerializationPropertyName("platforms")]
public List<string> Platforms { get; set; }
// ABSOLUTE paths on the host box (already resolved from Playnite's database-relative form), or
// null. A remote (http) art URL is passed through verbatim.
[SerializationPropertyName("cover")]
public string Cover { get; set; }
[SerializationPropertyName("background")]
public string Background { get; set; }
[SerializationPropertyName("icon")]
public string Icon { get; set; }
}
public class PlayniteInfo
{
[SerializationPropertyName("version")]
public string Version { get; set; }
[SerializationPropertyName("mode")]
public string Mode { get; set; }
}
public class LibraryExport
{
[SerializationPropertyName("schema")]
public int Schema { get; set; }
[SerializationPropertyName("generatedAt")]
public string GeneratedAt { get; set; }
[SerializationPropertyName("playnite")]
public PlayniteInfo Playnite { get; set; }
[SerializationPropertyName("games")]
public List<ExportedGame> Games { get; set; }
}
}