diff --git a/fixtures/3/accompanyingCanvas.json b/fixtures/3/accompanyingCanvas.json new file mode 100644 index 0000000..641259e --- /dev/null +++ b/fixtures/3/accompanyingCanvas.json @@ -0,0 +1,81 @@ +{ + "@context": "http://iiif.io/api/presentation/3/context.json", + "id": "https://iiif.io/api/cookbook/recipe/0014-accompanyingcanvas/manifest.json", + "type": "Manifest", + "label": { + "en": [ + "Partial audio recording of Gustav Mahler's _Symphony No. 3_" + ] + }, + "items": [ + { + "id": "https://iiif.io/api/cookbook/recipe/0014-accompanyingcanvas/canvas/p1", + "type": "Canvas", + "label": { + "en": [ + "Gustav Mahler, Symphony No. 3, CD 1" + ] + }, + "duration": 1985.024, + "accompanyingCanvas": { + "id": "https://iiif.io/api/cookbook/recipe/0014-accompanyingcanvas/canvas/accompanying", + "type": "Canvas", + "label": { + "en": [ + "First page of score for Gustav Mahler, Symphony No. 3" + ] + }, + "height": 998, + "width": 772, + "items": [ + { + "id": "https://iiif.io/api/cookbook/recipe/0014-accompanyingcanvas/canvas/accompanying/annotation/page", + "type": "AnnotationPage", + "items": [ + { + "id": "https://iiif.io/api/cookbook/recipe/0014-accompanyingcanvas/canvas/accompanying/annotation/image", + "type": "Annotation", + "motivation": "painting", + "body": { + "id": "https://iiif.io/api/image/3.0/example/reference/4b45bba3ea612ee46f5371ce84dbcd89-mahler-0/full/,998/0/default.jpg", + "type": "Image", + "format": "image/jpeg", + "height": 998, + "width": 772, + "service": [ + { + "id": "https://iiif.io/api/image/3.0/example/reference/4b45bba3ea612ee46f5371ce84dbcd89-mahler-0", + "type": "ImageService3", + "profile": "level1" + } + ] + }, + "target": "https://iiif.io/api/cookbook/recipe/0014-accompanyingcanvas/canvas/accompanying" + } + ] + } + ] + }, + "items": [ + { + "id": "https://iiif.io/api/cookbook/recipe/0014-accompanyingcanvas/canvas/page/p1", + "type": "AnnotationPage", + "items": [ + { + "id": "https://iiif.io/api/cookbook/recipe/0014-accompanyingcanvas/canvas/page/annotation/segment1-audio", + "type": "Annotation", + "motivation": "painting", + "body": { + "id": "https://fixtures.iiif.io/audio/indiana/mahler-symphony-3/CD1/medium/128Kbps.mp4", + "type": "Sound", + "duration": 1985.024, + "format": "video/mp4" + }, + "target": "https://iiif.io/api/cookbook/recipe/0014-accompanyingcanvas/canvas/page/p1" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/fixtures/3/placeholderCanvas.json b/fixtures/3/placeholderCanvas.json new file mode 100644 index 0000000..6cf6568 --- /dev/null +++ b/fixtures/3/placeholderCanvas.json @@ -0,0 +1,68 @@ +{ + "@context": "http://iiif.io/api/presentation/3/context.json", + "id": "https://iiif.io/api/cookbook/recipe/0013-placeholderCanvas/manifest.json", + "type": "Manifest", + "label": { + "en": [ + "Video recording of Donizetti's _The Elixer of Love_" + ] + }, + "items": [ + { + "id": "https://iiif.io/api/cookbook/recipe/0013-placeholderCanvas/canvas/donizetti", + "type": "Canvas", + "duration": 7278.466, + "width": 640, + "height": 360, + "placeholderCanvas": { + "id": "https://iiif.io/api/cookbook/recipe/0013-placeholderCanvas/canvas/donizetti/placeholder", + "type": "Canvas", + "width": 640, + "height": 360, + "items": [ + { + "id": "https://iiif.io/api/cookbook/recipe/0013-placeholderCanvas/canvas/donizetti/placeholder/1", + "type": "AnnotationPage", + "items": [ + { + "id": "https://iiif.io/api/cookbook/recipe/0013-placeholderCanvas/canvas/donizetti/placeholder/1-image", + "type": "Annotation", + "motivation": "painting", + "body": { + "id": "https://fixtures.iiif.io/video/indiana/donizetti-elixir/act1-thumbnail.png", + "type": "Image", + "format": "image/png", + "width": 640, + "height": 360 + }, + "target": "https://iiif.io/api/cookbook/recipe/0013-placeholderCanvas/canvas/donizetti/placeholder" + } + ] + } + ] + }, + "items": [ + { + "id": "https://iiif.io/api/cookbook/recipe/0013-placeholderCanvas/donizetti/1", + "type": "AnnotationPage", + "items": [ + { + "id": "https://iiif.io/api/cookbook/recipe/0013-placeholderCanvas/donizetti/1-video", + "type": "Annotation", + "motivation": "painting", + "body": { + "id": "https://fixtures.iiif.io/video/indiana/donizetti-elixir/vae0637_accessH264_low.mp4", + "type": "Video", + "duration": 7278.466, + "width": 640, + "height": 360, + "format": "video/mp4" + }, + "target": "https://iiif.io/api/cookbook/recipe/0013-placeholderCanvas/canvas/donizetti" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/schema/iiif_3_0.json b/schema/iiif_3_0.json index 17bf5ca..1a8dfc4 100644 --- a/schema/iiif_3_0.json +++ b/schema/iiif_3_0.json @@ -424,6 +424,8 @@ "seeAlso": { "$ref": "#/classes/seeAlso" }, "services": { "$ref": "#/classes/service" }, "service": { "$ref": "#/classes/service" }, + "placeholderCanvas": { "$ref": "#/classes/placeholderCanvas" }, + "accompanyingCanvas": { "$ref": "#/classes/accompanyingCanvas" }, "thumbnail": { "type": "array", "items": { "$ref": "#/classes/resource" } @@ -489,6 +491,8 @@ "service": { "$ref": "#/classes/service" }, "services": { "$ref": "#/classes/service" }, "viewingDirection": { "$ref": "#/classes/viewingDirection" }, + "placeholderCanvas": { "$ref": "#/classes/placeholderCanvas" }, + "accompanyingCanvas": { "$ref": "#/classes/accompanyingCanvas" }, "rights": { "$ref": "#/classes/rights" }, "start": {}, "navDate": { "$ref": "#/classes/navDate" }, @@ -605,6 +609,8 @@ "provider": { "$ref": "#/classes/provider" }, "seeAlso": { "$ref": "#/classes/seeAlso" }, "service": { "$ref": "#/classes/service" }, + "placeholderCanvas": { "$ref": "#/classes/placeholderCanvas" }, + "accompanyingCanvas": { "$ref": "#/classes/accompanyingCanvas" }, "thumbnail": { "type": "array", "items": { "$ref": "#/classes/resource" } @@ -638,6 +644,124 @@ } ] }, + "placeholderCanvas": { + "allOf": [ + { "$ref": "#/types/class" }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "pattern": "^Canvas$", + "default": "Canvas" + }, + "height": { "$ref": "#/types/dimension" }, + "width": { "$ref": "#/types/dimension" }, + "duration": { "$ref": "#/types/duration" }, + "metadata": { "$ref": "#/classes/metadata" }, + "summary": { "$ref": "#/types/lngString" }, + "requiredStatement": { "$ref": "#/types/keyValueString" }, + "rendering": { "$ref": "#/types/external" }, + "rights": { "$ref": "#/classes/rights" }, + "navDate": { "$ref": "#/classes/navDate" }, + "navPlace": { "$ref": "#/classes/navPlace" }, + "provider": { "$ref": "#/classes/provider" }, + "seeAlso": { "$ref": "#/classes/seeAlso" }, + "service": { "$ref": "#/classes/service" }, + "thumbnail": { + "type": "array", + "items": { "$ref": "#/classes/resource" } + }, + "homepage": { "$ref": "#/classes/homepage" }, + "behavior": { "$ref": "#/classes/behavior" }, + "partOf": { "$ref": "#/classes/partOf" }, + "items": { + "type": "array", + "items": { + "$ref": "#/classes/annotationPage" + } + }, + "annotations": { + "type": "array", + "items": { + "$ref": "#/classes/annotationPage" + } + } + }, + "required": ["items"], + "anyOf":[ + { "required": ["width"] }, + { "required": ["height"] }, + { "required": ["duration"] } + ], + "dependencies": { + "width": ["height"], + "height": ["width"] + }, + "not": { "required": [ "placeholderCanvas", "accompanyingCanvas" ] } + } + ] + }, + "accompanyingCanvas": { + "allOf": [ + { "$ref": "#/types/class" }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "pattern": "^Canvas$", + "default": "Canvas" + }, + "height": { "$ref": "#/types/dimension" }, + "width": { "$ref": "#/types/dimension" }, + "duration": { "$ref": "#/types/duration" }, + "metadata": { "$ref": "#/classes/metadata" }, + "summary": { "$ref": "#/types/lngString" }, + "requiredStatement": { "$ref": "#/types/keyValueString" }, + "rendering": { "$ref": "#/types/external" }, + "rights": { "$ref": "#/classes/rights" }, + "navDate": { "$ref": "#/classes/navDate" }, + "navPlace": { "$ref": "#/classes/navPlace" }, + "provider": { "$ref": "#/classes/provider" }, + "seeAlso": { "$ref": "#/classes/seeAlso" }, + "service": { "$ref": "#/classes/service" }, + "thumbnail": { + "type": "array", + "items": { "$ref": "#/classes/resource" } + }, + "homepage": { "$ref": "#/classes/homepage" }, + "behavior": { "$ref": "#/classes/behavior" }, + "partOf": { "$ref": "#/classes/partOf" }, + "items": { + "type": "array", + "items": { + "$ref": "#/classes/annotationPage" + } + }, + "annotations": { + "type": "array", + "items": { + "$ref": "#/classes/annotationPage" + } + } + }, + "required": ["items"], + "anyOf":[ + { "required": ["width"] }, + { "required": ["height"] }, + { "required": ["duration"] } + ], + "dependencies": { + "width": ["height"], + "height": ["width"] + }, + "not": { "required": [ "placeholderCanvas", "accompanyingCanvas" ] } + } + ] + }, + + "annotationCollection": { "allOf": [ { "$ref": "#/types/class" }, @@ -848,6 +972,8 @@ "rendering": { "$ref": "#/types/external" }, "supplementary": { "$ref": "#/classes/annotationCollection" }, "service": { "$ref": "#/classes/service" }, + "placeholderCanvas": { "$ref": "#/classes/placeholderCanvas" }, + "accompanyingCanvas": { "$ref": "#/classes/accompanyingCanvas" }, "annotations": { "type": "array", "items": { diff --git a/tests/test_validator.py b/tests/test_validator.py index c3bba34..44feb14 100644 --- a/tests/test_validator.py +++ b/tests/test_validator.py @@ -146,7 +146,9 @@ def test07_check_manifest3(self): 'fixtures/3/publicdomain.json', 'fixtures/3/navPlace.json', 'fixtures/3/anno_source.json', - 'fixtures/3/range_range.json' + 'fixtures/3/range_range.json', + 'fixtures/3/accompanyingCanvas.json', + 'fixtures/3/placeholderCanvas.json' ]: with open(good, 'r') as fh: print ('Testing: {}'.format(good))