Skip to content
Snippets Groups Projects
Verified Commit 5a4437c7 authored by Loïs Poujade's avatar Loïs Poujade
Browse files

Fix captions to handle array or single body

+ add tests
parent 047b2063
Branches
No related tags found
No related merge requests found
{
"@context": "http://iiif.io/api/presentation/3/context.json",
"id": "https://iiif.io/api/cookbook/recipe/0266-full-canvas-annotation/manifest.json",
"type": "Manifest",
"label": { "en": [ "Video Example 3" ] },
"items": [
{
"id": "https://iiif.io/api/cookbook/recipe/0003-mvm-video-annot/canvas",
"type": "Canvas",
"height": 360,
"width": 640,
"duration": 572.034,
"items": [
{
"id": "https://iiif.io/api/cookbook/recipe/0003-mvm-video-annot/canvas/page",
"type": "AnnotationPage",
"items": [
{
"id": "https://iiif.io/api/cookbook/recipe/0003-mvm-video-annot/canvas/page/annotation",
"type": "Annotation",
"motivation": "painting",
"body": {
"id": "https://fixtures.iiif.io/video/indiana/lunchroom_manners/high/lunchroom_manners_1024kb.mp4",
"type": "Video",
"height": 360,
"width": 480,
"duration": 572.034,
"format": "video/mp4"
},
"target": "https://iiif.io/api/cookbook/recipe/0003-mvm-video-annot/canvas"
}
]
}
],
"annotations": [
{
"id": "https://iiif.io/api/cookbook/recipe/0266-full-canvas-annotation/canvas-1/annopage-2",
"type": "AnnotationPage",
"items": [
{
"id": "https://iiif.io/api/cookbook/recipe/0266-full-canvas-annotation/canvas-1/annopage-2/anno-1",
"type": "Annotation",
"motivation": "commenting",
"body": {
"type": "TextualBody",
"language": "de",
"format": "text/plain",
"value": "Göttinger Marktplatz mit Gänseliesel Brunnen"
},
"target": "https://iiif.io/api/cookbook/recipe/0003-mvm-video-annot/canvas/page/annotation"
}
]
}
]
}
]
}
{
"@context": "http://iiif.io/api/presentation/3/context.json",
"id": "https://iiif.io/api/cookbook/recipe/0219-using-caption-file/manifest.json",
"type": "Manifest",
"label": {
"en": [
"Lunchroom Manners"
]
},
"items": [
{
"id": "https://iiif.io/api/cookbook/recipe/0219-using-caption-file/canvas",
"type": "Canvas",
"height": 360,
"width": 480,
"duration": 572.034,
"items": [
{
"id": "https://iiif.io/api/cookbook/recipe/0219-using-caption-file/canvas/page",
"type": "AnnotationPage",
"items": [
{
"id": "https://iiif.io/api/cookbook/recipe/0219-using-caption-file/canvas/page/annotation1",
"type": "Annotation",
"motivation": "painting",
"body": {
"id": "https://fixtures.iiif.io/video/indiana/lunchroom_manners/high/lunchroom_manners_1024kb.mp4",
"type": "Video",
"height": 360,
"width": 480,
"duration": 572.034,
"format": "video/mp4"
},
"target": "https://iiif.io/api/cookbook/recipe/0219-using-caption-file/canvas"
}
]
}
],
"annotations": [
{
"id": "https://iiif.io/api/cookbook/recipe/0219-using-caption-file/canvas/page2",
"type": "AnnotationPage",
"items": [
{
"id": "https://iiif.io/api/cookbook/recipe/0219-using-caption-file/canvas/page2/a1",
"type": "Annotation",
"motivation": "supplementing",
"body": {
"id": "https://fixtures.iiif.io/video/indiana/lunchroom_manners/lunchroom_manners.vtt",
"format": "text/vtt",
"language": "en"
},
"target": "https://iiif.io/api/cookbook/recipe/0219-using-caption-file/canvas"
}
]
}
]
}
]
}
{
"@context": "http://iiif.io/api/presentation/3/context.json",
"id": "https://iiif.io/api/cookbook/recipe/0219-using-caption-file/manifest.json",
"type": "Manifest",
"label": {
"en": [
"Lunchroom Manners"
]
},
"items": [
{
"id": "https://iiif.io/api/cookbook/recipe/0219-using-caption-file/canvas",
"type": "Canvas",
"height": 360,
"width": 480,
"duration": 572.034,
"items": [
{
"id": "https://iiif.io/api/cookbook/recipe/0219-using-caption-file/canvas/page",
"type": "AnnotationPage",
"items": [
{
"id": "https://iiif.io/api/cookbook/recipe/0219-using-caption-file/canvas/page/annotation1",
"type": "Annotation",
"motivation": "painting",
"body": {
"id": "https://fixtures.iiif.io/video/indiana/lunchroom_manners/high/lunchroom_manners_1024kb.mp4",
"type": "Video",
"height": 360,
"width": 480,
"duration": 572.034,
"format": "video/mp4"
},
"target": "https://iiif.io/api/cookbook/recipe/0219-using-caption-file/canvas"
}
]
}
],
"annotations": [
{
"id": "https://iiif.io/api/cookbook/recipe/0219-using-caption-file/canvas/page2",
"type": "AnnotationPage",
"items": [
{
"id": "https://iiif.io/api/cookbook/recipe/0219-using-caption-file/canvas/page2/a1",
"type": "Annotation",
"motivation": "supplementing",
"body": [
{
"id": "https://fixtures.iiif.io/video/indiana/lunchroom_manners/lunchroom_manners.vtt#fr",
"format": "text/vtt",
"language": "fr"
},
{
"id": "https://fixtures.iiif.io/video/indiana/lunchroom_manners/lunchroom_manners.vtt#en",
"format": "text/vtt",
"language": "en"
}
],
"target": "https://iiif.io/api/cookbook/recipe/0219-using-caption-file/canvas"
},
{
"id": "https://iiif.io/api/cookbook/recipe/0219-using-caption-file/canvas/page2/a1",
"type": "Annotation",
"motivation": "supplementing",
"body": {
"id": "https://fixtures.iiif.io/video/indiana/lunchroom_manners/lunchroom_manners.vtt#ru",
"format": "text/vtt",
"language": "ru"
},
"target": "https://iiif.io/api/cookbook/recipe/0219-using-caption-file/canvas"
}
]
}
]
}
]
}
{
"@context": "http://iiif.io/api/presentation/3/context.json",
"id": "https://iiif.io/api/cookbook/recipe/0219-using-caption-file/manifest.json",
"type": "Manifest",
"label": {
"en": [
"Lunchroom Manners"
]
},
"items": [
{
"id": "https://iiif.io/api/cookbook/recipe/0219-using-caption-file/canvas",
"type": "Canvas",
"height": 360,
"width": 480,
"duration": 572.034,
"items": [
{
"id": "https://iiif.io/api/cookbook/recipe/0219-using-caption-file/canvas/page",
"type": "AnnotationPage",
"items": [
{
"id": "https://iiif.io/api/cookbook/recipe/0219-using-caption-file/canvas/page/annotation1",
"type": "Annotation",
"motivation": "painting",
"body": {
"id": "https://fixtures.iiif.io/video/indiana/lunchroom_manners/high/lunchroom_manners_1024kb.mp4",
"type": "Video",
"height": 360,
"width": 480,
"duration": 572.034,
"format": "video/mp4"
},
"target": "https://iiif.io/api/cookbook/recipe/0219-using-caption-file/canvas"
}
]
}
],
"annotations": [
{
"id": "https://iiif.io/api/cookbook/recipe/0219-using-caption-file/canvas/page2",
"type": "AnnotationPage",
"items": [
{
"id": "https://iiif.io/api/cookbook/recipe/0219-using-caption-file/canvas/page2/a1",
"type": "Annotation",
"motivation": "supplementing",
"body": [
{
"id": "https://fixtures.iiif.io/video/indiana/lunchroom_manners/lunchroom_manners.vtt#fr",
"format": "text/vtt",
"language": "fr"
},
{
"id": "https://fixtures.iiif.io/video/indiana/lunchroom_manners/lunchroom_manners.vtt#en",
"format": "text/vtt",
"language": "en"
}
],
"target": "https://iiif.io/api/cookbook/recipe/0219-using-caption-file/canvas"
}
]
}
]
}
]
}
import React from 'react';
import { shallow } from 'enzyme';
import { Utils } from 'manifesto.js';
import AnnotationFactory from '../../../src/lib/AnnotationFactory';
import { VideoViewer } from '../../../src/components/VideoViewer';
import videoSimple from '../../fixtures/version-3/video.json';
import videoCaptions from '../../fixtures/version-3/video_captions.json';
import videoMultiCaptions from '../../fixtures/version-3/video_multiples_captions.json';
import videoMultiCaptionsMultiAnno from '../../fixtures/version-3/video_captions_other.json';
/** create wrapper */
function createWrapper(props, suspenseFallback) {
......@@ -18,17 +22,47 @@ function createWrapper(props, suspenseFallback) {
describe('VideoViewer', () => {
let wrapper;
describe('render', () => {
const canvasSimple = Utils.parseManifest(videoSimple).getSequences()[0].getCanvases()[0];
it('videoResources', () => {
it('video', () => {
wrapper = createWrapper({
canvas: canvasSimple,
canvas: Utils.parseManifest(videoSimple).getSequences()[0].getCanvases()[0],
}, true);
expect(wrapper.exists('video[crossOrigin="anonymous"]')).toBe(true); // eslint-disable-line jsx-a11y/media-has-caption
expect(wrapper.contains(<source src="https://fixtures.iiif.io/video/indiana/30-minute-clock/medium/30-minute-clock.mp4" type="video/mp4" />)).toBe(true);
});
it('passes through configurable options', () => {
it('one caption', () => {
const canvas = Utils.parseManifest(videoCaptions).getSequences()[0].getCanvases()[0];
/* cf selectors/annotations/getPresentAnnotationsCanvas */
const annotations = canvas.__jsonld.annotations.flatMap((a) => AnnotationFactory.determineAnnotation(a));
wrapper = createWrapper({
annotations,
canvas,
}, true);
expect(wrapper.contains(<track src="https://fixtures.iiif.io/video/indiana/lunchroom_manners/lunchroom_manners.vtt" srcLang="en" />)).toBe(true);
expect(wrapper.exists('video[crossOrigin="anonymous"]')).toBe(true); // eslint-disable-line jsx-a11y/media-has-caption
});
it('multiples captions', () => {
const canvas = Utils.parseManifest(videoMultiCaptions).getSequences()[0].getCanvases()[0];
/* cf selectors/annotations/getPresentAnnotationsCanvas */
const annotations = canvas.__jsonld.annotations.flatMap((a) => AnnotationFactory.determineAnnotation(a));
wrapper = createWrapper({
annotations,
canvas,
}, true);
expect(wrapper.contains(<track src="https://fixtures.iiif.io/video/indiana/lunchroom_manners/lunchroom_manners.vtt#en" srcLang="en" />)).toBe(true);
expect(wrapper.contains(<track src="https://fixtures.iiif.io/video/indiana/lunchroom_manners/lunchroom_manners.vtt#fr" srcLang="fr" />)).toBe(true);
expect(wrapper.exists('video[crossOrigin="anonymous"]')).toBe(true); // eslint-disable-line jsx-a11y/media-has-caption
});
it('multiples captions in multiples annotations', () => {
const canvas = Utils.parseManifest(videoMultiCaptionsMultiAnno).getSequences()[0].getCanvases()[0];
/* cf selectors/annotations/getPresentAnnotationsCanvas */
const annotations = canvas.__jsonld.annotations.flatMap((a) => AnnotationFactory.determineAnnotation(a));
wrapper = createWrapper({
canvas: canvasSimple,
annotations,
canvas,
}, true);
expect(wrapper.contains(<track src="https://fixtures.iiif.io/video/indiana/lunchroom_manners/lunchroom_manners.vtt#en" srcLang="en" />)).toBe(true);
expect(wrapper.contains(<track src="https://fixtures.iiif.io/video/indiana/lunchroom_manners/lunchroom_manners.vtt#fr" srcLang="fr" />)).toBe(true);
expect(wrapper.contains(<track src="https://fixtures.iiif.io/video/indiana/lunchroom_manners/lunchroom_manners.vtt#ru" srcLang="ru" />)).toBe(true);
expect(wrapper.exists('video[crossOrigin="anonymous"]')).toBe(true); // eslint-disable-line jsx-a11y/media-has-caption
});
});
......
......@@ -21,18 +21,11 @@ export class VideoViewer extends Component {
/** */
componentDidMount() {
const { annotations, setHasTextTrack, setPaused } = this.props;
const { setPaused, setHasTextTrack } = this.props;
setPaused(true);
const vttContent = flatten(
flattenDeep([
annotations.map(annotation => annotation.resources.map(
resources_ => resources_.resource,
)),
]).filter(resource => resource.body && resource.body[0] && resource.body[0].format === 'text/vtt'),
);
if (vttContent && vttContent.length > 0) {
setHasTextTrack(true);
}
const video = this.videoRef.current;
if (video && video.textTracks.length > 0) setHasTextTrack(true);
}
/** */
......@@ -69,7 +62,7 @@ export class VideoViewer extends Component {
video.muted = muted;
}
if (video.textTracks && video.textTracks.length > 0) {
const newMode = textTrackDisabled ? 'hidden' : 'showing';
const newMode = textTrackDisabled ? 'disabled' : 'showing';
if (video.textTracks[0].mode !== newMode) {
video.textTracks[0].mode = newMode;
}
......@@ -135,13 +128,10 @@ export class VideoViewer extends Component {
}),
]).filter((resource) => resource.body && resource.body[0].__jsonld && resource.body[0].__jsonld.type === 'Video'),
);
const vttContent = flatten(
flattenDeep([
annotations.map(annotation => annotation.resources.map(
resources_ => resources_.resource,
)),
]).filter(resource => resource.body && resource.body[0] && resource.body[0].format === 'text/vtt'),
);
const vttContent = annotations
.flatMap(annoPage => annoPage.json.items.map(anno => anno.body))
.flat().filter((body) => body.format === 'text/vtt');
// Only one video can be displayed at a time in this implementation.
const len = videoResources.length;
......@@ -149,12 +139,6 @@ export class VideoViewer extends Component {
? videoResources[len - 1].body[0] : null;
const videoTargetTemporalfragment = len > 0
? videoResources[len - 1].temporalfragment : [];
let caption = null;
if (vttContent && vttContent.length > 0) {
caption = {
id: vttContent[0].body[0].id,
};
}
return (
<div className={classes.flexContainer}>
<div className={classes.flexFill}>
......@@ -162,9 +146,7 @@ export class VideoViewer extends Component {
<>
<video className={classes.video} key={video.id} ref={this.videoRef} {...videoOptions}>
<source src={video.id} type={video.getFormat()} />
{ caption && (
<track src={caption.id} />
)}
{ vttContent.map(vttc => (<track key={vttc.id} src={vttc.id} srcLang={vttc.language} />)) }
</video>
<AnnotationsOverlayVideo windowId={windowId} videoRef={this.videoRef} videoTarget={videoTargetTemporalfragment} key={`${windowId} ${video.id}`} />
</>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment