diff options
| author | Jules Laplace <julescarbon@gmail.com> | 2020-11-09 17:50:42 +0100 |
|---|---|---|
| committer | Jules Laplace <julescarbon@gmail.com> | 2020-11-09 17:50:42 +0100 |
| commit | 634abd7cec252e61dd171ffbbaa83dec87062bd1 (patch) | |
| tree | 2141f45cdd3ea3427636ffeaa7baabf15fbb3583 /animism-align/frontend/app/views/viewer | |
| parent | 1b4da06342d36e5db84f2c6a6c0904c1a20be028 (diff) | |
subtitles in transcript. clicking them seeks video
Diffstat (limited to 'animism-align/frontend/app/views/viewer')
10 files changed, 102 insertions, 28 deletions
diff --git a/animism-align/frontend/app/views/viewer/nav/nav.parent.js b/animism-align/frontend/app/views/viewer/nav/nav.parent.js index 3df2ce4..abe4871 100644 --- a/animism-align/frontend/app/views/viewer/nav/nav.parent.js +++ b/animism-align/frontend/app/views/viewer/nav/nav.parent.js @@ -61,7 +61,7 @@ class NavParent extends Component { e && e.preventDefault() e && e.stopPropagation() const { viewer } = this.props - console.log('>> SEEK') + // console.log('>> SEEK') if (viewer.nextSection) { actions.viewer.seekToSection(viewer.nextSection) } else { diff --git a/animism-align/frontend/app/views/viewer/player/components.fullscreen/fullscreen.video.js b/animism-align/frontend/app/views/viewer/player/components.fullscreen/fullscreen.video.js index 252a278..da1e0ed 100644 --- a/animism-align/frontend/app/views/viewer/player/components.fullscreen/fullscreen.video.js +++ b/animism-align/frontend/app/views/viewer/player/components.fullscreen/fullscreen.video.js @@ -34,11 +34,11 @@ class FullscreenVideo extends Component { this.handleEnd = this.handleEnd.bind(this) } componentDidMount() { - const { video_start_ts } = this.props.element.settings - const seconds = timestampToSeconds(video_start_ts) || 0.0 + const video_start_ts = timestampToSeconds(this.props.element.settings.video_start_ts) || 0.0 + // TODO: here you can add the current play time modulo ... this.setState({ - video_start_ts: seconds, - seek: seconds, + seek: video_start_ts, + video_start_ts, }) } componentDidUpdate(prevProps) { diff --git a/animism-align/frontend/app/views/viewer/player/components.inline/inline.text.js b/animism-align/frontend/app/views/viewer/player/components.inline/inline.text.js index 2475801..b2633a4 100644 --- a/animism-align/frontend/app/views/viewer/player/components.inline/inline.text.js +++ b/animism-align/frontend/app/views/viewer/player/components.inline/inline.text.js @@ -61,17 +61,18 @@ export const Pullquote = ({ paragraph, currentParagraph, currentAnnotation, onAn /> ) } + const isPullquoteCredit = annotation.type === 'pullquote_credit' return ( <span key={annotation.id} className={ - annotation.type === 'pullquote_credit' + isPullquoteCredit ? 'pullquote_credit' : annotation.id === currentAnnotation ? 'current' : '' } - onClick={e => onAnnotationClick(e, paragraph, annotation)} + onClick={e => !isPullquoteCredit && onAnnotationClick(e, paragraph, annotation)} dangerouslySetInnerHTML={{ __html: ' ' + annotation.text + ' ' }} /> ) diff --git a/animism-align/frontend/app/views/viewer/player/components.inline/inline.video.js b/animism-align/frontend/app/views/viewer/player/components.inline/inline.video.js index d6de779..9a0ff7a 100644 --- a/animism-align/frontend/app/views/viewer/player/components.inline/inline.video.js +++ b/animism-align/frontend/app/views/viewer/player/components.inline/inline.video.js @@ -70,6 +70,7 @@ export class MediaVideo extends Component { ) } + // otherwise, inline the vimeo player const poster = annotation.settings.poster ? { backgroundImage: 'url(' + posterURL(item) + ')', } : {} diff --git a/animism-align/frontend/app/views/viewer/player/components.media/video.scrubber.js b/animism-align/frontend/app/views/viewer/player/components.media/video.scrubber.js index f866628..e1b22a7 100644 --- a/animism-align/frontend/app/views/viewer/player/components.media/video.scrubber.js +++ b/animism-align/frontend/app/views/viewer/player/components.media/video.scrubber.js @@ -73,6 +73,9 @@ class VideoScrubber extends Component { } handleMouseMove(e) { e.stopPropagation() + if (e.pageY < window.innerHeight / 2) { + return + } // console.log('move', this.defer) if (this.defer) { this.defer = false diff --git a/animism-align/frontend/app/views/viewer/player/components.media/video.subtitles.js b/animism-align/frontend/app/views/viewer/player/components.media/video.subtitles.js index dfa7a85..f056168 100644 --- a/animism-align/frontend/app/views/viewer/player/components.media/video.subtitles.js +++ b/animism-align/frontend/app/views/viewer/player/components.media/video.subtitles.js @@ -3,8 +3,7 @@ import { connect } from 'react-redux' import actions from 'app/actions' import { timestampToSeconds, floatInRange } from 'app/utils' - -const REGEXP_ALL_COMMAS = new RegExp(',', 'g') +import { parseSubtitles } from 'app/utils/transcript.utils' export default class VideoSubtitles extends Component { state = { @@ -20,23 +19,10 @@ export default class VideoSubtitles extends Component { } } loadSubtitles() { - if (!this.props.mediaItem || !this.props.mediaItem.settings.subtitles) return; - const groups = this.props.mediaItem.settings.subtitles.split("\n\n") - const subtitles = groups.map((group) => { - if (!group) return - const lines = group.trim().split("\n") - if (!lines.length || !parseInt(lines[0])) { - return null - } - let ts_parts = lines[1].replace(REGEXP_ALL_COMMAS, '.').split(" --> ").map(timestampToSeconds) - return { - id: parseInt(lines[0]), - start_ts: ts_parts[0], - end_ts: ts_parts[1], - lines: lines.slice(2), - } - }).filter(a => !!a) - this.setState({ subtitles, current: null }) + const subtitles = parseSubtitles(this.props.mediaItem, 0) + if (subtitles) { + this.setState({ subtitles, current: null }) + } } updateCurrentSubtitle() { const { play_ts } = this.props diff --git a/animism-align/frontend/app/views/viewer/player/player.transcript.css b/animism-align/frontend/app/views/viewer/player/player.transcript.css index 5c7056b..dcdcabb 100644 --- a/animism-align/frontend/app/views/viewer/player/player.transcript.css +++ b/animism-align/frontend/app/views/viewer/player/player.transcript.css @@ -157,6 +157,14 @@ cursor: pointer; transition: all 0.1s; } +.player-transcript .pullquote span.pullquote_credit, +.player-transcript .pullquote span.pullquote_credit.current, +.player-transcript .pullquote span.pullquote_credit.current:hover { + box-shadow: 0 0 0 rgba(255,255,255,0.0); + background: transparent; + color: inherit; + cursor: default; +} .player-transcript .paragraph { position: relative; diff --git a/animism-align/frontend/app/views/viewer/transcript/components/elementTypes.video.js b/animism-align/frontend/app/views/viewer/transcript/components/elementTypes.video.js index 1c1b3cc..8e65843 100644 --- a/animism-align/frontend/app/views/viewer/transcript/components/elementTypes.video.js +++ b/animism-align/frontend/app/views/viewer/transcript/components/elementTypes.video.js @@ -1,5 +1,9 @@ import React, { Component } from 'react' +import actions from 'app/actions' +import { timestampToSeconds, floatInRange } from 'app/utils' +import { parseSubtitles } from 'app/utils/transcript.utils' + import { MediaCitation } from './elementTypes.image' export const MediaVideo = ({ paragraph, media, currentParagraph, currentAnnotation, onAnnotationClick }) => { @@ -11,7 +15,7 @@ export const MediaVideo = ({ paragraph, media, currentParagraph, currentAnnotati } const item = media.lookup[annotation.settings.media_id] if (!item) return <div>Media not found: {annotation.settings.media_id}</div> - return ( + const el = ( <div className={className} data-startts={paragraph.start_ts} @@ -24,4 +28,74 @@ export const MediaVideo = ({ paragraph, media, currentParagraph, currentAnnotati {"]"} </div> ) + if (item.settings.subtitles) { + return ( + <div> + {el} + <TranscriptVideoSubtitles + annotation={annotation} + mediaItem={item} + /> + </div> + ) + } + return el +} + +class TranscriptVideoSubtitles extends Component { + state = { + subtitles: [], + current: null, + } + componentDidMount() { + this.loadSubtitles() + } + componentDidUpdate(prevProps) { + if (this.props.play_ts !== prevProps.play_ts) { + this.updateCurrentSubtitle() + } + } + loadSubtitles() { + const { annotation, mediaItem, } = this.props + const { start_ts } = annotation + const video_start_ts = timestampToSeconds(annotation.settings.video_start_ts) || 0.0 + const subtitles = parseSubtitles(mediaItem, start_ts - video_start_ts) + console.log('subtitles', start_ts, video_start_ts, subtitles) + if (subtitles) { + this.setState({ subtitles, current: null }) + } + } + updateCurrentSubtitle() { + const { play_ts } = this.props + const current = this.state.subtitles.filter(({ start_ts, end_ts }) => ( + floatInRange(start_ts, play_ts, end_ts) + )).slice(-1) + if (!current.length) { + this.setState({ current: null }) + } else { + this.setState({ current: current[0] }) + } + } + render() { + const { subtitles, current } = this.state + if (!subtitles) return + return ( + <div className="paragraph pullquote subtitles"> + {subtitles.map(subtitle => { + return ( + <span + onClick={e => { + e && e.stopPropagation() + console.log(subtitle, e) + actions.viewer.seekToTimestamp(subtitle.start_ts) + }} + className={subtitle === current ? 'current' : ""} + > + {subtitle.lines.join(" ")} + </span> + ) + })} + </div> + ) + } } diff --git a/animism-align/frontend/app/views/viewer/transcript/transcript.css b/animism-align/frontend/app/views/viewer/transcript/transcript.css index 1649f94..8b2903e 100644 --- a/animism-align/frontend/app/views/viewer/transcript/transcript.css +++ b/animism-align/frontend/app/views/viewer/transcript/transcript.css @@ -119,6 +119,7 @@ } .transcript .pullquote { border-left: 2px solid #ddd; + margin-top: 1rem; padding-left: 1rem; } .transcript .pullquote + .pullquote { diff --git a/animism-align/frontend/app/views/viewer/viewer.actions.js b/animism-align/frontend/app/views/viewer/viewer.actions.js index d0e0b3a..86c8d2d 100644 --- a/animism-align/frontend/app/views/viewer/viewer.actions.js +++ b/animism-align/frontend/app/views/viewer/viewer.actions.js @@ -190,7 +190,7 @@ export const loadSections = () => dispatch => { section.inlineParagraphCount = section.paragraphs.filter(p => !p.hidden).length // console.log(i, section.inlineParagraphCount) }) - console.log(sections) + // console.log(sections) // console.log(footnoteList) // console.log(fullscreenTimeline) dispatch({ type: types.viewer.load_sections, sections, footnoteList }) |
