Skip to content
Snippets Groups Projects
Commit 33655115 authored by Jack Reed's avatar Jack Reed Committed by Chris Beer
Browse files

Setup audio and video viewer support

parent c65dd369
Branches
Tags
No related merge requests found
......@@ -16,11 +16,12 @@
windows: [
{
manifestId: 'https://preview.iiif.io/cookbook/master/recipe/0003-mvm-video/manifest.json',
view: 'av'
},
{
manifestId: 'https://preview.iiif.io/cookbook/0026_0064_0065-opera-recipes/recipe/0064-opera-one-canvas/manifest.json',
view: 'av'
},
{
manifestId: 'https://iiif.io/api/cookbook/recipe/0014-accompanyingcanvas/manifest.json'
}
],
});
......
import React, { Component } from 'react';
import PropTypes from 'prop-types';
/** */
export class AVViewer extends Component {
/** */
render() {
const { currentCanvases } = this.props;
const video = currentCanvases[0].getContent()[0].getBody()[0];
return (
<div style={{ display: 'flex', 'alignItems': 'center' }}>
<video controls>
<source src={video.id} type={video.format} />
</video>
</div>
);
}
}
AVViewer.propTypes = {
currentCanvases: PropTypes.array.isRequired, // eslint-disable-line react/forbid-prop-types
windowId: PropTypes.string.isRequired,
};
import React, { Component } from 'react';
import PropTypes from 'prop-types';
/** */
export class AudioViewer extends Component {
/* eslint-disable jsx-a11y/media-has-caption */
/** */
render() {
const { classes, audioResources } = this.props;
const audio = audioResources && audioResources[0];
if (!audio) return <></>;
return (
<div className={classes.container}>
<audio controls className={classes.audio}>
<source src={audio.id} type={audio.getFormat()} />
</audio>
</div>
);
}
/* eslint-enable jsx-a11y/media-has-caption */
}
AudioViewer.propTypes = {
audioResources: PropTypes.arrayOf(PropTypes.object).isRequired,
classes: PropTypes.objectOf(PropTypes.string).isRequired,
};
......@@ -6,28 +6,29 @@ import CompanionArea from '../containers/CompanionArea';
import CollectionDialog from '../containers/CollectionDialog';
import ns from '../config/css-ns';
const AudioViewer = lazy(() => import('../containers/AudioViewer'));
const GalleryView = lazy(() => import('../containers/GalleryView'));
const SelectCollection = lazy(() => import('../containers/SelectCollection'));
const WindowViewer = lazy(() => import('../containers/WindowViewer'));
const AVViewer = lazy(() => import('../containers/AVViewer'));
const VideoViewer = lazy(() => import('../containers/VideoViewer'));
GalleryView.displayName = 'GalleryView';
SelectCollection.displayName = 'SelectCollection';
WindowViewer.displayName = 'WindowViewer';
/**
* WindowMiddleContent - component that renders the "middle" area of the
* Mirador Window
* PrimaryWindow - component that renders the primary content of a Mirador
* window. Right now this differentiates between a Image, Video, or Audio viewer.
*/
export class PrimaryWindow extends Component {
/**
* renderViewer
* renderViewer - logic used to determine what type of view to show
*
* @return {(String|null)}
*/
renderViewer() {
const {
isCollection, isCollectionDialogVisible, isFetching, view, windowId,
audioResources, isCollection, isCollectionDialogVisible, isFetching, videoResources, view, windowId,
} = this.props;
if (isCollection) {
return (
......@@ -47,9 +48,16 @@ export class PrimaryWindow extends Component {
/>
);
}
if (view === 'av') {
if (videoResources.length > 0) {
return (
<AVViewer
<VideoViewer
windowId={windowId}
/>
);
}
if (audioResources.length > 0) {
return (
<AudioViewer
windowId={windowId}
/>
);
......@@ -81,10 +89,12 @@ export class PrimaryWindow extends Component {
}
PrimaryWindow.propTypes = {
audioResources: PropTypes.arrayOf(PropTypes.object).isRequired,
classes: PropTypes.objectOf(PropTypes.string).isRequired,
isCollection: PropTypes.bool,
isCollectionDialogVisible: PropTypes.bool,
isFetching: PropTypes.bool,
videoResources: PropTypes.arrayOf(PropTypes.object).isRequired,
view: PropTypes.string,
windowId: PropTypes.string.isRequired,
};
......
import React, { Component } from 'react';
import PropTypes from 'prop-types';
/** */
export class VideoViewer extends Component {
/* eslint-disable jsx-a11y/media-has-caption */
/** */
render() {
const { classes, videoResources } = this.props;
const video = videoResources && videoResources[0];
if (!video) return <></>;
return (
<div className={classes.container}>
<video controls className={classes.video}>
<source src={video.id} type={video.getFormat()} />
</video>
</div>
);
}
/* eslint-enable jsx-a11y/media-has-caption */
}
VideoViewer.propTypes = {
classes: PropTypes.objectOf(PropTypes.string).isRequired,
videoResources: PropTypes.arrayOf(PropTypes.object).isRequired,
};
import { connect } from 'react-redux';
import { compose } from 'redux';
import { withTranslation } from 'react-i18next';
import { withStyles } from '@material-ui/core';
import { withPlugins } from '../extend/withPlugins';
import { AVViewer } from '../components/AVViewer';
import { getVisibleCanvases } from '../state/selectors';
import { AudioViewer } from '../components/AudioViewer';
import { getVisibleCanvasAudioResources } from '../state/selectors';
/** */
const mapStateToProps = (state, { windowId }) => (
{
currentCanvases: getVisibleCanvases(state, { windowId }) || [],
audioResources: getVisibleCanvasAudioResources(state, { windowId }) || [],
}
);
/** */
const styles = () => ({
audio: {
width: '100%',
},
container: {
alignItems: 'center',
display: 'flex',
width: '100%',
},
});
const enhance = compose(
withTranslation(),
withStyles(styles),
connect(mapStateToProps, null),
withPlugins('AVViewer'),
withPlugins('AudioViewer'),
);
export default enhance(AVViewer);
export default enhance(AudioViewer);
......@@ -2,15 +2,19 @@ import { compose } from 'redux';
import { connect } from 'react-redux';
import { withStyles } from '@material-ui/core/styles';
import { withPlugins } from '../extend/withPlugins';
import { getManifestoInstance, getWindow } from '../state/selectors';
import {
getManifestoInstance, getVisibleCanvasAudioResources, getVisibleCanvasVideoResources, getWindow,
} from '../state/selectors';
import { PrimaryWindow } from '../components/PrimaryWindow';
/** */
const mapStateToProps = (state, { windowId }) => {
const manifestoInstance = getManifestoInstance(state, { windowId });
return {
audioResources: getVisibleCanvasAudioResources(state, { windowId }) || [],
isCollection: manifestoInstance && manifestoInstance.isCollection(),
isCollectionDialogVisible: getWindow(state, { windowId }).collectionDialogOn,
videoResources: getVisibleCanvasVideoResources(state, { windowId }) || [],
};
};
......@@ -24,7 +28,7 @@ const styles = {
const enhance = compose(
withStyles(styles),
connect(mapStateToProps),
connect(mapStateToProps, null),
withPlugins('PrimaryWindow'),
);
......
import { connect } from 'react-redux';
import { compose } from 'redux';
import { withTranslation } from 'react-i18next';
import { withStyles } from '@material-ui/core';
import { withPlugins } from '../extend/withPlugins';
import { VideoViewer } from '../components/VideoViewer';
import { getVisibleCanvasVideoResources } from '../state/selectors';
/** */
const mapStateToProps = (state, { windowId }) => (
{
videoResources: getVisibleCanvasVideoResources(state, { windowId }) || [],
}
);
/** */
const styles = () => ({
container: {
alignItems: 'center',
display: 'flex',
width: '100%',
},
video: {
width: '100%',
},
});
const enhance = compose(
withTranslation(),
withStyles(styles),
connect(mapStateToProps, null),
withPlugins('VideoViewer'),
);
export default enhance(VideoViewer);
......@@ -81,6 +81,24 @@ export default class MiradorCanvas {
}));
}
/** */
get videoResources() {
const resources = flattenDeep([
this.canvas.getContent().map(i => i.getBody()),
]);
return flatten(resources.filter((resource) => resource.getProperty('type') === 'Video'));
}
/** */
get audioResources() {
const resources = flattenDeep([
this.canvas.getContent().map(i => i.getBody()),
]);
return flatten(resources.filter((resource) => resource.getProperty('type') === 'Sound'));
}
/** */
get resourceAnnotations() {
return flattenDeep([
......
......@@ -184,6 +184,22 @@ export const getVisibleCanvasNonTiledResources = createSelector(
.filter(resource => resource.getServices().length < 1),
);
export const getVisibleCanvasVideoResources = createSelector(
[
getVisibleCanvases,
],
canvases => flatten(canvases
.map(canvas => new MiradorCanvas(canvas).videoResources)),
);
export const getVisibleCanvasAudioResources = createSelector(
[
getVisibleCanvases,
],
canvases => flatten(canvases
.map(canvas => new MiradorCanvas(canvas).audioResources)),
);
export const selectInfoResponse = createSelector(
[
(state, { infoId }) => infoId,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment