Files
punktfunk-plugin-playnite/test/art.test.ts
T
enricobuehler 9988729aab
CI / publish (push) Has been skipped
CI / exporter (push) Successful in 12s
CI / build (push) Successful in 20s
feat(art): default to host-served cover art (scales to large libraries)
Adds art.mode "host" (now the default): emit each cover's local file PATH
and let the host serve the bytes via its art proxy, instead of inlining a
data URL. The reconcile payload carries no image data, so a large Playnite
library no longer exceeds the host's request-body limit. "dataurl" (inline,
small libraries) and "off" remain. Requires a host with the provider-art
proxy (punktfunk main: feat/library-local-art).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-19 00:56:15 +02:00

109 lines
3.5 KiB
TypeScript

import { afterAll, describe, expect, test } from "bun:test";
import * as fs from "node:fs";
import * as os from "node:os";
import * as path from "node:path";
import { buildArtwork, fileToDataUrl } from "../src/art.js";
import { DEFAULT_ART } from "../src/config.js";
import type { ExportedGame } from "../src/export-schema.js";
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pf-playnite-art-"));
const write = (name: string, bytes: Buffer): string => {
const p = path.join(dir, name);
fs.writeFileSync(p, bytes);
return p;
};
afterAll(() => fs.rmSync(dir, { recursive: true, force: true }));
const game = (over: Partial<ExportedGame>): ExportedGame => ({
id: "11111111-1111-1111-1111-111111111111",
name: "Game",
installed: true,
hidden: false,
source: "Steam",
platforms: [],
cover: null,
background: null,
icon: null,
...over,
});
describe("fileToDataUrl", () => {
test("encodes a small png as a data URL", () => {
const p = write("cover.png", Buffer.from([1, 2, 3, 4]));
expect(fileToDataUrl(p, 1000)).toBe(
`data:image/png;base64,${Buffer.from([1, 2, 3, 4]).toString("base64")}`,
);
});
test("drops files over the size cap", () => {
const p = write("big.jpg", Buffer.alloc(2000, 7));
expect(fileToDataUrl(p, 1000)).toBeNull();
});
test("rejects unknown extensions and null", () => {
const p = write("weird.xyz", Buffer.from([1]));
expect(fileToDataUrl(p, 1000)).toBeNull();
expect(fileToDataUrl(null, 1000)).toBeNull();
});
test("mime follows the extension", () => {
const p = write("c.jpeg", Buffer.from([9]));
expect(fileToDataUrl(p, 1000)?.startsWith("data:image/jpeg;base64,")).toBe(
true,
);
});
});
describe("buildArtwork", () => {
test("off mode yields no art", () => {
const cover = write("c1.png", Buffer.from([1]));
expect(
buildArtwork(game({ cover }), { ...DEFAULT_ART, mode: "off" }),
).toBeUndefined();
});
test("host mode (default) emits the raw cover path — no bytes", () => {
const cover = write("c2.png", Buffer.from([1, 2]));
const art = buildArtwork(game({ cover }), DEFAULT_ART);
expect(art?.portrait).toBe(cover);
expect(art?.hero).toBeUndefined();
});
test("host mode includeBackground adds the hero path", () => {
const cover = write("c2b.png", Buffer.from([1]));
const background = write("b2b.jpg", Buffer.from([2]));
const art = buildArtwork(game({ cover, background }), {
...DEFAULT_ART,
includeBackground: true,
});
expect(art?.portrait).toBe(cover);
expect(art?.hero).toBe(background);
});
test("host mode with no cover yields undefined", () => {
expect(buildArtwork(game({ cover: null }), DEFAULT_ART)).toBeUndefined();
});
test("dataurl mode embeds the cover as a portrait data URL", () => {
const cover = write("c3.png", Buffer.from([1, 2]));
const art = buildArtwork(game({ cover }), {
...DEFAULT_ART,
mode: "dataurl",
});
expect(art?.portrait?.startsWith("data:image/png;base64,")).toBe(true);
expect(art?.hero).toBeUndefined();
});
test("dataurl includeBackground adds a hero data URL", () => {
const cover = write("c4.png", Buffer.from([1]));
const background = write("b4.jpg", Buffer.from([2]));
const art = buildArtwork(game({ cover, background }), {
...DEFAULT_ART,
mode: "dataurl",
includeBackground: true,
});
expect(art?.portrait).toBeTruthy();
expect(art?.hero?.startsWith("data:image/jpeg;base64,")).toBe(true);
});
test("dataurl mode with no readable art yields undefined", () => {
expect(
buildArtwork(game({ cover: "/does/not/exist.png" }), {
...DEFAULT_ART,
mode: "dataurl",
}),
).toBeUndefined();
});
});