Repository navigation
Expand file tree
/
Copy pathpluginInfo.schema.json
More file actions
438 lines (438 loc) · 22.5 KB
/
Copy pathpluginInfo.schema.json
File metadata and controls
438 lines (438 loc) · 22.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://raw.githubusercontent.com/FalconChristmas/fpp-plugin-Template/master/pluginInfo.schema.json",
"title": "FPP pluginInfo.json",
"description": "Metadata file every FPP plugin ships in its repository root. Prose reference: PLUGININFO_FORMAT.md in this repo. Strictly validated: every field below is the complete recognized set, including 'version'/'requires' (legacy, ignored by FPP at runtime but explicitly allowed here so a plugin that still carries them from an older template doesn't fail validation) and the optional 'privacy' declaration block -- anything else is rejected.",
"type": "object",
"required": [
"repoName",
"name",
"author",
"description",
"homeURL",
"srcURL",
"bugURL",
"versions"
],
"additionalProperties": false,
"properties": {
"repoName": {
"type": "string",
"minLength": 1,
"description": "Unique identifier and on-disk install directory name. Keep it filesystem/shell safe. Must match the name in fpp-data/pluginList.json.",
"pattern": "^[A-Za-z0-9._-]+$"
},
"name": {
"type": "string",
"minLength": 1,
"description": "Human-readable title shown on the plugin card."
},
"author": {
"type": "string",
"minLength": 1,
"description": "Author name / handle."
},
"description": {
"type": "string",
"minLength": 1,
"description": "Short description shown on the plugin card."
},
"homeURL": {
"type": "string",
"format": "uri",
"pattern": "^https?://",
"description": "Project home page; rendered as the home link."
},
"srcURL": {
"type": "string",
"format": "uri",
"pattern": "^https://(www\\.)?github\\.com/",
"description": "Git clone URL (normally ending in .git). FPP clones this to install. Must be a github.com repo -- that's the only source FPP plugins support, and this is the trust anchor for the Official badge. It must be the repo whose pluginInfo.json is listed; a rename or transfer blocks the listing check until srcURL (and the listing URL) are updated."
},
"bugURL": {
"type": "string",
"format": "uri",
"pattern": "^https?://",
"description": "Issue tracker URL; rendered as Report a Bug."
},
"iconURL": {
"type": "string",
"format": "uri",
"description": "Icon URL. FPP prefers a local icon.png (128x128 or 256x256) in the repo root and falls back to this, which must be an https://raw.githubusercontent.com/ URL ending in .png, .jpg, .jpeg, .gif or .webp; anything else is ignored."
},
"allowUpdates": {
"type": "integer",
"enum": [
0,
1
],
"description": "0 hides in-place update buttons (install-once plugins). Omitted = allowed. Can be overridden per version."
},
"releaseNotesStyle": {
"type": "string",
"enum": [
"none",
"gitRelease",
"gitHistory",
"script"
],
"description": "How the Plugin Manager shows this plugin's release notes (FPP 10+). Omitted (or \"none\") = no Release Notes icon/link is offered at all. \"gitRelease\": the latest GitHub Release of the srcURL repo (its markdown body, rendered). \"gitHistory\": the commits between the installed clone and origin/<branch>, i.e. what an update would bring in -- no GitHub Release needed. \"script\": the stdout of the plugin's own scripts/fpp_releasenotes.sh, shown as plain text (for a plugin whose updates aren't git commits, e.g. one driving fpp_update_check.sh/fpp_upgrade.sh). FPP reads this from the INSTALLED plugin's pluginInfo.json on click, so it only takes effect once the plugin is installed."
},
"minMemoryMB": {
"type": "integer",
"minimum": 1,
"description": "Minimum system RAM (MB), plugin-wide (top level only; not read from versions[] entries). Below this, FPP flags the plugin and hides it on the Basic UI level."
},
"minCpuCores": {
"type": "integer",
"minimum": 1,
"description": "Minimum recommended CPU cores, plugin-wide (top level only; not read from versions[] entries). Below this, FPP flags the plugin and hides it on the Basic UI level."
},
"private": {
"type": "boolean",
"description": "true if hosted in a private GitHub repo; installed with the credentials on the Developer settings page."
},
"linkName": {
"type": "string",
"description": "Legacy: creates a symlink on install. Only takes effect when the cloned repo does NOT ship its own pluginInfo.json. New plugins rarely need it."
},
"delist": {
"type": "boolean",
"description": "Set true to request removal from FPP's Plugin Manager list (retire the plugin). Because setting it requires write access to your repo, it also serves as proof of ownership for a de-list request. Existing installs are unaffected."
},
"versions": {
"type": "array",
"minItems": 1,
"description": "Compatibility entries. FPP installs the LAST entry whose FPP-version range and platform match the device, so list them oldest-first.",
"items": {
"$ref": "#/$defs/versionEntry"
}
},
"dependencies": {
"$ref": "#/$defs/dependencies",
"description": "Things installed automatically BEFORE the plugin's own scripts/fpp_install.sh (FPP 10+). Applies to every entry in versions[]. A versions[] entry may also declare its own 'dependencies' (see versionEntry) with items ADDITIONAL to this top-level set for that entry only -- e.g. a package name that differs between the FPP9 and FPP10 image."
},
"documentation": {
"type": "string",
"format": "uri",
"description": "Optional URL to human documentation for this plugin (e.g. a guide/README elsewhere). Purely informational -- not read or rendered by FPP itself."
},
"version": {
"description": "IGNORED. FPP does not read a top-level 'version' -- use versions[] entries for compatibility instead. Allowed here only so a plugin carrying it from an older template doesn't fail validation; don't add it to a new plugin."
},
"requires": {
"type": "array",
"description": "IGNORED. FPP does not read a top-level 'requires' -- declare needs in the 'dependencies' block instead. Allowed here only so a plugin carrying it from an older template doesn't fail validation; don't add it to a new plugin."
},
"privacy": {
"$ref": "#/$defs/privacy",
"description": "Privacy disclosure (the `privacy` section of PLUGININFO_FORMAT.md; rules in PLUGIN_GUIDELINES.md §14). Optional in the schema but required for listing: a plugin without it cannot be listed or updated (lint_plugin.py's privacy-missing blocker). All eight keys are required and may be empty - an empty array is a statement (\"sends nothing\"), a missing key fails validation. Self-declared: the listing check greps the plugin's code against it (lint_plugin.py's privacy-undeclared-* rules) and fails on a contradiction. FPP computes the six install-dialog lights from it; the author never picks a colour. See PLUGIN_GUIDELINES.md §14."
}
},
"$defs": {
"platform": {
"type": "string",
"description": "Must exactly match the value FPP writes to /etc/fpp/platform.",
"enum": [
"Raspberry Pi",
"BeagleBone Black",
"BeagleBone 64",
"Armbian",
"Debian",
"Ubuntu",
"Fedora",
"MacOS",
"UNKNOWN"
]
},
"versionEntry": {
"type": "object",
"required": [
"minFPPVersion",
"maxFPPVersion",
"branch",
"sha"
],
"additionalProperties": false,
"properties": {
"minFPPVersion": {
"type": "string",
"minLength": 1,
"description": "Minimum FPP version this entry supports, e.g. \"9.0\".",
"pattern": "^[0-9]+(\\.[0-9]+)*$"
},
"maxFPPVersion": {
"type": "string",
"description": "Maximum FPP version. \"0\", \"0.0\" or \"\" mean open-ended, but only within the major named by minFPPVersion; on a newer major the entry is treated as untested.",
"pattern": "^([0-9]+(\\.[0-9]+)*)?$"
},
"branch": {
"type": "string",
"minLength": 1,
"description": "Git branch to check out for this entry."
},
"sha": {
"type": "string",
"description": "Commit to pin to. \"\" installs the latest commit on branch."
},
"allowUpdates": {
"type": "integer",
"enum": [
0,
1
],
"description": "Per-version override of the top-level allowUpdates."
},
"platforms": {
"type": "array",
"description": "Restrict this entry to specific hardware. Omit to match all platforms.",
"items": {
"$ref": "#/$defs/platform"
}
},
"dependencies": {
"$ref": "#/$defs/dependencies",
"description": "Dependencies ADDITIONAL to the top-level dependencies block, installed only when THIS entry is the one selected for the running FPP version/platform (FPP 10+)."
}
}
},
"dependencies": {
"type": "object",
"description": "Resolved in order: packages -> python -> scripts -> plugins.",
"properties": {
"packages": {
"type": "array",
"items": {
"type": "string"
},
"description": "System (apt) packages. Reference-counted per requester. Needs a Debian-family platform."
},
"python": {
"type": "array",
"items": {
"type": "string"
},
"description": "Python (PyPI) packages, only for what Debian does not package (prefer `python3-<name>` in `packages`). Installed via `pip install --break-system-packages` into FPP's system Python (not isolated per plugin, not reference-counted). pip ships by default with FPP."
},
"scripts": {
"type": "array",
"items": {
"type": "string"
},
"description": "Script-repository entries in \"Category/file\" form."
},
"plugins": {
"type": "array",
"items": {
"type": "string"
},
"description": "Other FPP plugins by repoName. Each must exist in fpp-data/pluginList.json."
}
}
},
"privacy": {
"type": "object",
"description": "What the plugin sends, collects, senses, opens to the outside and changes on the host. Eight keys, all required. Written for a neighbour, not a developer: \"your phone number and message\", not \"MSISDN and body\". Any other key is rejected here and ignored by FPP.",
"required": [
"summary",
"sends",
"collects",
"sensors",
"remoteAccess",
"systemChanges",
"closedCode",
"other"
],
"additionalProperties": false,
"properties": {
"summary": {
"type": "string",
"minLength": 1,
"description": "One or two plain sentences for the install dialog: what leaves the device, to whom, and why. 1-200 characters; the listing check warns (never blocks) over 200."
},
"sends": {
"type": "array",
"description": "Every destination the plugin's traffic reaches off this device - directly, through FPP's helpers (CurlManager, urlGet, core MQTT, MultiSync), from the operator's browser (CDN, fonts, embeds) or from a visitor's device - and every broadcast (FM, LoRa). Empty means the plugin sends nothing.",
"items": {
"$ref": "#/$defs/privacySend"
}
},
"collects": {
"type": "array",
"description": "Data the plugin keeps about people. Empty means nothing beyond the operator's own settings.",
"items": {
"$ref": "#/$defs/privacyCollect"
}
},
"sensors": {
"type": "array",
"description": "Cameras, microphones and other sensors the plugin reads. Empty means none. A camera stream that leaves the device is also a `sends` entry.",
"items": {
"$ref": "#/$defs/privacySensor"
}
},
"remoteAccess": {
"type": "string",
"enum": [
"none",
"lan",
"internet-authenticated",
"internet-open",
"exposes-fpp",
"tunnel"
],
"description": "The plugin's OWN listener, at its widest reach: `none` (nothing, or only routes on FPP's web server), `lan` (a port on the local network), `internet-authenticated` / `internet-open` (a port meant to be reached from the internet, with / without a login), `exposes-fpp` (puts FPP's own pages on the internet), `tunnel` (bundles a tunnel or overlay network that lets an outside service reach this device)."
},
"systemChanges": {
"type": "array",
"description": "Every change outside the plugin's own directory. Empty means nothing outside its own directory.",
"items": {
"$ref": "#/$defs/privacySystemChange"
}
},
"closedCode": {
"type": "boolean",
"description": "true if anything that runs cannot be read by anyone: not in the repository, not from a public package source (apt, pip, npm, CPAN or similar) whose source is published (a closed binary wheel or vendor SDK from PyPI/npm is closed code), and not an open-source project's own release of code that is public (a project's .deb from its GitHub releases is open code; a vendor's binary is not). Examples: a prebuilt binary with no public source, a downloaded .so, a vendor installer, an obfuscated script. A fetched package is still a `download` system change."
},
"other": {
"type": "string",
"minLength": 1,
"description": "Anything the keys above cannot say - what is left behind after uninstall, a visitor-facing page hosted by a vendor, payments taken. \"none\" if nothing."
}
}
},
"privacySend": {
"type": "object",
"required": [
"to",
"what",
"why",
"alwaysOn"
],
"additionalProperties": false,
"properties": {
"to": {
"type": "string",
"minLength": 1,
"description": "A hostname (\"api.twilio.com\"; a bare domain covers its subdomains); or a phrase for an operator-entered address (\"your MQTT broker\", \"the FPP players you list\"); or a broadcast (\"anyone in FM range\"). Starts with \"http://\" when the connection is unencrypted. GitHub's own hosts (github.com, raw.githubusercontent.com, api.github.com, *.github.io and similar) are not listed here for reading: fetching code, releases, update checks or a package from GitHub is traffic FPP's plugin manager already makes; a downloaded program is a systemChanges entry of kind download. Writing to GitHub is sending: a plugin that creates a gist, an issue or a comment, or uploads a file, lists `api.github.com` (or `uploads.github.com`) like any other host."
},
"what": {
"type": "string",
"minLength": 1,
"description": "What is sent, in words. Say \"CPU serial number\" / \"MAC address\" if a hardware identifier is sent. 1-100 characters (the listing check warns over 100)."
},
"why": {
"type": "string",
"minLength": 1,
"description": "Purpose, in words. 1-100 characters (the listing check warns over 100)."
},
"alwaysOn": {
"type": "boolean",
"description": "true if it sends before the operator turns anything on (at install, at boot, while fppd runs)."
}
}
},
"privacyCollect": {
"type": "object",
"required": [
"what",
"about",
"keptDays",
"canDelete",
"where"
],
"additionalProperties": false,
"properties": {
"what": {
"type": "string",
"minLength": 1,
"description": "What is kept, in words. 1-100 characters (the listing check warns over 100)."
},
"about": {
"type": "string",
"enum": [
"operator",
"household",
"visitors",
"passers-by",
"third-parties",
"performers"
],
"description": "Whom it is about. `operator` is the FPP owner; `household` people at the property; `visitors` people who interact with the show; `passers-by` people captured without interacting (camera, presence); `third-parties` people in content (messages, contacts); `performers`."
},
"keptDays": {
"type": [
"integer",
"null"
],
"minimum": 0,
"description": "How long it is kept, in days. null = kept until deleted by hand."
},
"canDelete": {
"type": "boolean",
"description": "true if a control in the plugin's UI deletes it."
},
"where": {
"type": "string",
"minLength": 1,
"description": "Where the operator would look for it and what to delete: a path under /home/fpp/media/ (\"plugindata/fpp-x/\", \"config/plugin.fpp-x\"), \"plugin log\", or a phrase if it is held off the device (\"the vendor's service\"). Written for the operator; FPP does not act on it."
}
}
},
"privacySensor": {
"type": "object",
"required": [
"type",
"stored"
],
"additionalProperties": false,
"properties": {
"type": {
"type": "string",
"enum": [
"camera",
"microphone",
"face-tracking",
"body-tracking",
"presence",
"rfid",
"gpio-input"
]
},
"stored": {
"type": "boolean",
"description": "true if frames, audio or detections are written to disk."
}
}
},
"privacySystemChange": {
"type": "object",
"required": [
"kind",
"what"
],
"additionalProperties": false,
"properties": {
"kind": {
"type": "string",
"enum": [
"service",
"network",
"core-settings",
"download",
"package-source",
"tunnel",
"reads-core-credentials",
"privilege"
],
"description": "`service` (units, daemons, cron, mounts, shares) · `network` (a LAN port, mDNS, a port-forward instruction) · `core-settings` (writes FPP's own files or settings) · `download` (extra software fetched at install, a self-update, a runtime download) · `package-source` (an apt/pip/npm source added) · `tunnel` (overlay network, remote-access tunnel) · `reads-core-credentials` (reads FPP's own passwords or tokens) · `privilege` (sudoers, groups, kernel modules, keys on other hosts)."
},
"what": {
"type": "string",
"minLength": 1,
"description": "One line: \"enables smbd\", \"adds fpp to the video group\", \"downloads the Piper voice models from huggingface.co\". Name the host of a download or package source so the listing check can match it. 1-150 characters (the listing check warns over 150)."
}
}
}
}
}