UNPKG

labo-components

Version:
168 lines (148 loc) 5.66 kB
import React from 'react'; import PropTypes from 'prop-types'; import TimeUtil from '../../../util/TimeUtil'; import FlexPlayerUtil from '../../../util/FlexPlayerUtil'; import { VIEW_LIST, VIEW_WORDCLOUD } from '../ContentAnnotationsColumn'; import TimedList from './TimedList'; import WordCloud from './WordCloud'; import { sanitize } from '../../shared/WordCloudHelpers'; import MediaEvents from '../_MediaEvents'; /* This component shows Segments in a TimedList or WordCloud */ export default class Segments extends React.Component { constructor(props) { super(props); } /* ----------------------- RENDER LIST -------------------*/ renderList(mediaObject, searchTerm, mediaEvents) { // convert segments to item list for TimedList const items = mediaObject.segments .filter(segment => !segment.programSegment) .sort((a, b) => a.start - b.start) .map((segment, index) => ({ id: 'ca_seg_li_' + index, start: FlexPlayerUtil.timeRelativeToOnAir( segment.start, mediaObject ) * 1000, end: FlexPlayerUtil.timeRelativeToOnAir( segment.end, mediaObject ) * 1000, startLabel: TimeUtil.formatMillisToTime( FlexPlayerUtil.timeRelativeToOnAir( segment.start, mediaObject ) * 1000 ).replace(/^00:/g, ''), // remove prefixed 00: hours (as most videos are < 1h) endLabel: TimeUtil.formatMillisToTime( FlexPlayerUtil.timeRelativeToOnAir( segment.end, mediaObject ) * 1000 ).replace(/^00:/g, ''), // remove prefixed 00: hours (as most videos are < 1h) data: segment.title })); return ( <TimedList items={items} mediaEvents={mediaEvents} searchTerm={searchTerm} /> ); } /* ----------------------- RENDER WORDCLOUD -------------------*/ renderWordCloud(mediaObject, searchTerm, mediaEvents) { // prepare segments const segments = mediaObject.segments .filter(segment => !segment.programSegment) .sort((a, b) => a.start - b.start); // get raw word list from segment titles const words = segments.reduce( (w, segment) => w.concat(segment.title.split(' ')), [] ); // When click on a word, onSeek the player to the next occurence of the given word // Start on the start of the ASR item for context const onWordClick = word => { // get current player position const pos = mediaEvents.getData(MediaEvents.PLAYER_POS); // get next occurence let hit = null; segments.some(segment => { const segmentStart = FlexPlayerUtil.timeRelativeToOnAir( segment.start, mediaObject ); // if segment in the future, or no first hit if (segmentStart > pos || hit == null) { // sanitize the words const words = sanitize(segment.title); word = word.replace('_', ' '); // if word exists if (words.indexOf(word) !== -1) { // store first hit if (!hit) { hit = segment; } // if future hit, store and return if (segmentStart > pos) { hit = segment; return true; } } } return false; }); // check if an item was hit if (hit != null) { // Update player by triggering SET_PLAYER_POS event this.props.mediaEvents.trigger( MediaEvents.SET_PLAYER_POS, FlexPlayerUtil.timeRelativeToOnAir(hit.start, mediaObject) ); } }; return ( <WordCloud words={words} mediaEvents={mediaEvents} size={100} searchTerm={searchTerm} onClick={onWordClick} /> ); } /* ----------------------- RENDER -------------------*/ render = () => { const mediaObject = this.props.activeMediaObject; if (!mediaObject || !mediaObject.segments) { return null; } switch (this.props.view) { case VIEW_LIST: return this.renderList( mediaObject, this.props.searchTerm, this.props.mediaEvents ); case VIEW_WORDCLOUD: return this.renderWordCloud( mediaObject, this.props.searchTerm, this.props.mediaEvents ); default: return null; } }; } Segments.propTypes = { searchTerm: PropTypes.string.isRequired, view: PropTypes.string.isRequired, activeMediaObject: PropTypes.object.isRequired, mediaEvents: PropTypes.object.isRequired };