Skip to content
Snippets Groups Projects
Select Git revision
  • d3ad9ff3d27c8823d1f6f7e8db8481a5c0536e9a
  • mui5-tetras-main-stable default protected
  • mui5-tetras-main-old-stable
  • preprod protected
  • 75-dernieres-ameliorations-avant-workshop-du-7-02
  • wip-fix-xywh
  • wip-positionement-annot
  • wip-surface-transformer
  • uploads-file
  • 69-la-video-demare-quand-on-fait-glisser-le-slider-et-le-clic-creer-un-decalage-entre-le-player
  • 61-recettage-des-outils-d-annotation
  • gestion_multiple_ouverture_pannel_annotation
  • autorisation_un_pannel_annotation
  • autorisation_un_pannel_edition_annotation
  • récupération_temps_video
  • save-shapes-and-position
  • fix-error-create-annotation-pannel
  • time-saving-on-annotation
  • tetras-main protected
  • fix-poc-mirador
  • tetras-antho-test
21 results

jest.config.js

Blame
  • VideoViewer.js 5.90 KiB
    import flatten from 'lodash/flatten';
    import flattenDeep from 'lodash/flattenDeep';
    import { createRef, Component } from 'react';
    import PropTypes from 'prop-types';
    import AnnotationItem from '../lib/AnnotationItem';
    import AnnotationsOverlayVideo from '../containers/AnnotationsOverlayVideo';
    import WindowCanvasNavigationControlsVideo from '../containers/WindowCanvasNavigationControlsVideo';
    
    /** */
    export class VideoViewer extends Component {
      /** */
      constructor(props) {
        super(props);
        this.videoRef = createRef();
    
        this.state = {
          start: 0,
          time: 0,
        };
      }
    
      /** */
      componentDidMount() {
        const { annotations, setHasTextTrack, setPaused } = 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);
        }
      }
    
      /** */
      componentDidUpdate(prevProps) {
        const {
          canvas, currentTime, muted, paused,
          setCurrentTime, setPaused,
          textTrackDisabled,
        } = this.props;
    
        if (paused !== prevProps.paused) {
          if (currentTime === 0) {
            this.timerReset();
          }
          if (paused) {
            this.timerStop();
          } else {
            this.timerStart();
          }
        }
        if (currentTime !== prevProps.currentTime) {
          const duration = canvas.getDuration();
          if (duration && duration < currentTime) {
            if (!paused) {
              setPaused(true);
              setCurrentTime(0);
              this.timerReset();
            }
          }
        }
        const video = this.videoRef.current;
        if (video) {
          if (video.muted !== muted) {
            video.muted = muted;
          }
          if (video.textTracks && video.textTracks.length > 0) {
            const newMode = textTrackDisabled ? 'hidden' : 'showing';
            if (video.textTracks[0].mode !== newMode) {
              video.textTracks[0].mode = newMode;
            }
          }
        }
      }
    
      /** */
      componentWillUnmount() {
        this.timerStop();
      }
    
      /** */
      timerStart() {
        const { currentTime } = this.props;
        this.setState({
          start: Date.now() - currentTime * 1000,
          time: currentTime * 1000,
        });
        this.timer = setInterval(() => {
          const { setCurrentTime } = this.props;
          this.setState(prevState => ({
            time: Date.now() - prevState.start,
          }));
          const { time } = this.state;
          setCurrentTime(time / 1000);
        }, 100);
      }
    
      /** */
      timerStop() {
        clearInterval(this.timer);
      }
    
      /** */
      timerReset() {
        this.setState({ time: 0 });
      }
    
      /* eslint-disable jsx-a11y/media-has-caption */
      /** */
      render() {
        const {
          annotations, canvas, classes, currentTime, videoOptions, windowId,
        } = this.props;
    
        const videoResources = flatten(
          flattenDeep([
            canvas.getContent().map(annot => {
              const annotaion = new AnnotationItem(annot.__jsonld);
              const temporalfragment = annotaion.temporalfragmentSelector;
              if (temporalfragment && temporalfragment.length > 0) {
                const start = temporalfragment[0] || 0;
                const end = (temporalfragment.length > 1) ? temporalfragment[1] : Number.MAX_VALUE;
                if (start <= currentTime && currentTime < end) {
                  //
                } else {
                  return {};
                }
              }
              const body = annot.getBody();
              return { body, temporalfragment };
            }),
          ]).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'),
        );
    
        // Only one video can be displayed at a time in this implementation.
        const len = videoResources.length;
        const video = len > 0
          ? 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}>
              { video && (
                <>
                  <video className={classes.video} key={video.id} ref={this.videoRef} {...videoOptions}>
                    <source src={video.id} type={video.getFormat()} />
                    { caption && (
                      <track src={caption.id} />
                    )}
                  </video>
                  <AnnotationsOverlayVideo windowId={windowId} videoRef={this.videoRef} videoTarget={videoTargetTemporalfragment} key={`${windowId} ${video.id}`} />
                </>
              )}
              <WindowCanvasNavigationControlsVideo windowId={windowId} />
            </div>
          </div>
        );
      }
      /* eslint-enable jsx-a11y/media-has-caption */
    }
    
    VideoViewer.propTypes = {
      annotations: PropTypes.arrayOf(PropTypes.object),
      canvas: PropTypes.object, // eslint-disable-line react/forbid-prop-types
      classes: PropTypes.objectOf(PropTypes.string).isRequired,
      currentTime: PropTypes.number,
      muted: PropTypes.bool,
      paused: PropTypes.bool,
      setCurrentTime: PropTypes.func,
      setHasTextTrack: PropTypes.func,
      setPaused: PropTypes.func,
      textTrackDisabled: PropTypes.bool,
      videoOptions: PropTypes.object, // eslint-disable-line react/forbid-prop-types
      windowId: PropTypes.string.isRequired,
    };
    
    VideoViewer.defaultProps = {
      annotations: [],
      canvas: {},
      currentTime: 0,
      muted: false,
      paused: true,
      setCurrentTime: () => {},
      setHasTextTrack: () => {},
      setPaused: () => {},
      textTrackDisabled: true,
      videoOptions: {},
    };