jellyfin-tools/jellyfin-year-review/docs/review.schema.json
jellyfin-year-review/docs/review.schema.jsonRaw
1{
2 "$schema": "https://json-schema.org/draft/2020-12/schema",
3 "$id": "urn:reel-review:review:1",
4 "title": "Owner-visible Reel Review v1",
5 "type": "object",
6 "properties": {
7 "schemaVersion": {
8 "const": 1
9 },
10 "rules": {
11 "type": "object",
12 "properties": {
13 "minimumSeconds": {
14 "type": "number",
15 "minimum": 0
16 },
17 "completionPercent": {
18 "type": "number",
19 "exclusiveMinimum": 0,
20 "maximum": 100
21 },
22 "marathonGapSeconds": {
23 "type": "number",
24 "minimum": 0,
25 "maximum": 86400
26 }
27 },
28 "required": [
29 "minimumSeconds",
30 "completionPercent",
31 "marathonGapSeconds"
32 ],
33 "additionalProperties": false
34 },
35 "user": {
36 "type": "object",
37 "properties": {
38 "id": {
39 "type": "string",
40 "pattern": "^[a-f0-9]{32}$"
41 },
42 "name": {
43 "type": "string"
44 }
45 },
46 "required": [
47 "id",
48 "name"
49 ],
50 "additionalProperties": false
51 },
52 "year": {
53 "type": "integer",
54 "minimum": 1970,
55 "maximum": 9998
56 },
57 "timezone": {
58 "type": "string"
59 },
60 "generatedAt": {
61 "type": "string",
62 "format": "date-time"
63 },
64 "source": {
65 "type": "string"
66 },
67 "coverage": {
68 "type": "string"
69 },
70 "availability": {
71 "type": "object",
72 "required": [
73 "exactWatchTime",
74 "completion",
75 "marathon",
76 "personality",
77 "ranking"
78 ],
79 "additionalProperties": {
80 "type": "object",
81 "properties": {
82 "available": {
83 "type": "boolean"
84 },
85 "reason": {
86 "type": "string"
87 }
88 },
89 "required": [
90 "available"
91 ],
92 "additionalProperties": false
93 }
94 },
95 "seconds": {
96 "type": "number",
97 "minimum": 0
98 },
99 "movieSeconds": {
100 "type": "number",
101 "minimum": 0
102 },
103 "tvSeconds": {
104 "type": "number",
105 "minimum": 0
106 },
107 "records": {
108 "type": "integer",
109 "minimum": 0
110 },
111 "uniqueTitles": {
112 "type": "integer",
113 "minimum": 0
114 },
115 "activeDays": {
116 "type": "integer",
117 "minimum": 0
118 },
119 "movies": {
120 "type": "array",
121 "items": {
122 "type": "object",
123 "properties": {
124 "id": {
125 "type": "string"
126 },
127 "title": {
128 "type": "string"
129 },
130 "poster": {
131 "type": "string",
132 "pattern": "^/art/[a-f0-9]{64}\\.jpg$"
133 },
134 "seconds": {
135 "type": "number",
136 "minimum": 0
137 },
138 "records": {
139 "type": "integer",
140 "minimum": 0
141 },
142 "completionPercent": {
143 "type": "number",
144 "minimum": 0,
145 "maximum": 100
146 }
147 },
148 "required": [
149 "id",
150 "title",
151 "seconds",
152 "records"
153 ],
154 "additionalProperties": false
155 }
156 },
157 "shows": {
158 "type": "array",
159 "items": {
160 "type": "object",
161 "properties": {
162 "id": {
163 "type": "string"
164 },
165 "title": {
166 "type": "string"
167 },
168 "poster": {
169 "type": "string",
170 "pattern": "^/art/[a-f0-9]{64}\\.jpg$"
171 },
172 "seconds": {
173 "type": "number",
174 "minimum": 0
175 },
176 "records": {
177 "type": "integer",
178 "minimum": 0
179 },
180 "completionPercent": {
181 "type": "number",
182 "minimum": 0,
183 "maximum": 100
184 }
185 },
186 "required": [
187 "id",
188 "title",
189 "seconds",
190 "records"
191 ],
192 "additionalProperties": false
193 }
194 },
195 "abandoned": {
196 "type": "array",
197 "items": {
198 "type": "object",
199 "properties": {
200 "id": {
201 "type": "string"
202 },
203 "title": {
204 "type": "string"
205 },
206 "poster": {
207 "type": "string",
208 "pattern": "^/art/[a-f0-9]{64}\\.jpg$"
209 },
210 "seconds": {
211 "type": "number",
212 "minimum": 0
213 },
214 "records": {
215 "type": "integer",
216 "minimum": 0
217 },
218 "completionPercent": {
219 "type": "number",
220 "minimum": 0,
221 "maximum": 100
222 }
223 },
224 "required": [
225 "id",
226 "title",
227 "seconds",
228 "records"
229 ],
230 "additionalProperties": false
231 }
232 },
233 "genres": {
234 "type": "array",
235 "items": {
236 "type": "object",
237 "properties": {
238 "name": {
239 "type": "string"
240 },
241 "seconds": {
242 "type": "number",
243 "minimum": 0
244 },
245 "records": {
246 "type": "integer",
247 "minimum": 0
248 }
249 },
250 "required": [
251 "name",
252 "seconds",
253 "records"
254 ],
255 "additionalProperties": false
256 }
257 },
258 "devices": {
259 "type": "array",
260 "items": {
261 "type": "object",
262 "properties": {
263 "name": {
264 "type": "string"
265 },
266 "seconds": {
267 "type": "number",
268 "minimum": 0
269 },
270 "records": {
271 "type": "integer",
272 "minimum": 0
273 }
274 },
275 "required": [
276 "name",
277 "seconds",
278 "records"
279 ],
280 "additionalProperties": false
281 }
282 },
283 "clients": {
284 "type": "array",
285 "items": {
286 "type": "object",
287 "properties": {
288 "name": {
289 "type": "string"
290 },
291 "seconds": {
292 "type": "number",
293 "minimum": 0
294 },
295 "records": {
296 "type": "integer",
297 "minimum": 0
298 }
299 },
300 "required": [
301 "name",
302 "seconds",
303 "records"
304 ],
305 "additionalProperties": false
306 }
307 },
308 "distributionMetric": {
309 "enum": [
310 "watched minutes",
311 "activity record ends (counts)"
312 ]
313 },
314 "marathon": {
315 "anyOf": [
316 {
317 "type": "object",
318 "properties": {
319 "start": {
320 "type": "string",
321 "format": "date-time"
322 },
323 "end": {
324 "type": "string",
325 "format": "date-time"
326 },
327 "watchedSeconds": {
328 "type": "number",
329 "minimum": 0
330 },
331 "elapsedSeconds": {
332 "type": "number",
333 "minimum": 0
334 },
335 "records": {
336 "type": "integer",
337 "minimum": 0
338 }
339 },
340 "required": [
341 "start",
342 "end",
343 "watchedSeconds",
344 "elapsedSeconds",
345 "records"
346 ],
347 "additionalProperties": false
348 },
349 {
350 "type": "null"
351 }
352 ]
353 },
354 "personality": {
355 "anyOf": [
356 {
357 "type": "object",
358 "properties": {
359 "name": {
360 "enum": [
361 "Night Owl",
362 "Early Bird",
363 "Weekend Warrior",
364 "Marathoner",
365 "Binge Watcher",
366 "Movie Buff",
367 "Series Devotee",
368 "Comfort Rewatcher",
369 "Genre Explorer",
370 "Prime-Time Regular",
371 "Daily Viewer",
372 "Seasonal Viewer",
373 "Short-Session Viewer",
374 "Balanced Viewer"
375 ]
376 },
377 "explanation": {
378 "type": "string"
379 }
380 },
381 "required": [
382 "name",
383 "explanation"
384 ],
385 "additionalProperties": false
386 },
387 {
388 "type": "null"
389 }
390 ]
391 },
392 "ranking": {
393 "anyOf": [
394 {
395 "type": "object",
396 "properties": {
397 "rank": {
398 "type": "integer",
399 "minimum": 1
400 },
401 "cohort": {
402 "type": "integer",
403 "minimum": 1
404 },
405 "percentile": {
406 "type": "number",
407 "minimum": 0,
408 "maximum": 100
409 },
410 "averageSeconds": {
411 "type": "number",
412 "minimum": 0
413 }
414 },
415 "required": [
416 "rank",
417 "cohort",
418 "percentile",
419 "averageSeconds"
420 ],
421 "additionalProperties": false
422 },
423 {
424 "type": "null"
425 }
426 ]
427 },
428 "warnings": {
429 "type": "array",
430 "items": {
431 "type": "string"
432 }
433 },
434 "hourly": {
435 "type": "array",
436 "items": {
437 "type": "number",
438 "minimum": 0
439 },
440 "minItems": 24,
441 "maxItems": 24
442 },
443 "weekdays": {
444 "type": "array",
445 "items": {
446 "type": "number",
447 "minimum": 0
448 },
449 "minItems": 7,
450 "maxItems": 7
451 },
452 "monthly": {
453 "type": "array",
454 "items": {
455 "type": "number",
456 "minimum": 0
457 },
458 "minItems": 12,
459 "maxItems": 12
460 }
461 },
462 "required": [
463 "schemaVersion",
464 "rules",
465 "user",
466 "year",
467 "timezone",
468 "generatedAt",
469 "source",
470 "coverage",
471 "availability",
472 "seconds",
473 "movieSeconds",
474 "tvSeconds",
475 "records",
476 "uniqueTitles",
477 "activeDays",
478 "movies",
479 "shows",
480 "abandoned",
481 "genres",
482 "devices",
483 "clients",
484 "distributionMetric",
485 "marathon",
486 "personality",
487 "ranking",
488 "warnings",
489 "hourly",
490 "weekdays",
491 "monthly"
492 ],
493 "additionalProperties": false
494}