summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJules Laplace <julescarbon@gmail.com>2020-11-09 16:27:49 +0100
committerJules Laplace <julescarbon@gmail.com>2020-11-09 16:27:49 +0100
commit0cffae759496a086eabe7459a8cfd066760f474e (patch)
tree6b2d9a89664670b9b57feff55791618c1b865acc
parent5c669a020e6db1c8095161941d3a62d5564eacd1 (diff)
video subtitles in SRT format
-rw-r--r--animism-align/frontend/app/views/media/components/media.formVideo.js4
-rw-r--r--animism-align/frontend/app/views/viewer/player/components.fullscreen/fullscreen.video.js6
-rw-r--r--animism-align/frontend/app/views/viewer/player/components.media/index.js2
-rw-r--r--animism-align/frontend/app/views/viewer/player/components.media/media.css29
-rw-r--r--animism-align/frontend/app/views/viewer/player/components.media/video.scrubber.js4
-rw-r--r--animism-align/frontend/app/views/viewer/player/components.media/video.subtitles.js61
-rw-r--r--animism-align/frontend/app/views/viewer/transcript/components/elementTypes.gallery.js2
-rw-r--r--animism-align/frontend/app/views/viewer/transcript/components/elementTypes.image.js2
8 files changed, 103 insertions, 7 deletions
diff --git a/animism-align/frontend/app/views/media/components/media.formVideo.js b/animism-align/frontend/app/views/media/components/media.formVideo.js
index d85fc4d..35cee2d 100644
--- a/animism-align/frontend/app/views/media/components/media.formVideo.js
+++ b/animism-align/frontend/app/views/media/components/media.formVideo.js
@@ -106,8 +106,8 @@ export default class MediaVideoForm extends Component {
title="Subtitles"
name="subtitles"
required
- data={data}
- onChange={this.handleChange}
+ data={data.settings}
+ onChange={this.handleSettingsChange}
autoComplete="off"
/>
</div>
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 84cf59e..252a278 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
@@ -4,7 +4,7 @@ import VimeoPlayer from 'app/utils/vendor/vimeo'
import actions from 'app/actions'
import { timestampToSeconds } from 'app/utils'
-import { VideoScrubber } from '../components.media'
+import { VideoScrubber, VideoSubtitles } from '../components.media'
class FullscreenVideo extends Component {
state = {
@@ -127,6 +127,10 @@ class FullscreenVideo extends Component {
timing={this.state}
onScrub={this.handleScrub}
/>
+ <VideoSubtitles
+ play_ts={seconds}
+ mediaItem={item}
+ />
</div>
)
}
diff --git a/animism-align/frontend/app/views/viewer/player/components.media/index.js b/animism-align/frontend/app/views/viewer/player/components.media/index.js
index 04b7f03..742d719 100644
--- a/animism-align/frontend/app/views/viewer/player/components.media/index.js
+++ b/animism-align/frontend/app/views/viewer/player/components.media/index.js
@@ -14,6 +14,7 @@ import {
import Carousel from './media.carousel'
import VideoScrubber from './video.scrubber'
+import VideoSubtitles from './video.subtitles'
import {
Grid
@@ -26,4 +27,5 @@ export {
Carousel,
Grid,
VideoScrubber,
+ VideoSubtitles,
} \ No newline at end of file
diff --git a/animism-align/frontend/app/views/viewer/player/components.media/media.css b/animism-align/frontend/app/views/viewer/player/components.media/media.css
index fea25ec..72eec07 100644
--- a/animism-align/frontend/app/views/viewer/player/components.media/media.css
+++ b/animism-align/frontend/app/views/viewer/player/components.media/media.css
@@ -424,3 +424,32 @@
opacity: 1.0;
}
+/* subtitles */
+
+.video-subtitles {
+ position: absolute;
+ bottom: 3rem;
+ height: 10rem;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ transform: translateZ(0) translateY(0);
+ transition: transform 0.2s;
+}
+.video-scrubber.show ~ .video-subtitles {
+ transform: translateZ(0) translateY(-3rem);
+}
+.video-subtitles span {
+ display: inline-block;
+ box-shadow: -3px -2px 0 #000,
+ 3px -2px 0 #000,
+ -3px 2px 0 #000,
+ 3px 2px 0 #000;
+ box-decoration-break: clone;
+ background: black;
+ color: white;
+ font-size: 1.25rem;
+ margin-bottom: 0.125rem;
+ padding: 0 0.125rem;
+}
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 e281559..f866628 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
@@ -60,7 +60,7 @@ class VideoScrubber extends Component {
// in case the video loops, modulo the length of the original video
const video_seek = ((seconds + video_start_ts) % timing.duration)
//
- console.log(start_ts, seconds)
+ // console.log(start_ts, seconds)
onScrub({
seek: video_seek,
seconds: seconds,
@@ -73,7 +73,7 @@ class VideoScrubber extends Component {
}
handleMouseMove(e) {
e.stopPropagation()
- console.log('move', this.defer)
+ // console.log('move', this.defer)
if (this.defer) {
this.defer = false
this.show()
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
new file mode 100644
index 0000000..dfa7a85
--- /dev/null
+++ b/animism-align/frontend/app/views/viewer/player/components.media/video.subtitles.js
@@ -0,0 +1,61 @@
+import React, { Component } from 'react'
+import { connect } from 'react-redux'
+
+import actions from 'app/actions'
+import { timestampToSeconds, floatInRange } from 'app/utils'
+
+const REGEXP_ALL_COMMAS = new RegExp(',', 'g')
+
+export default class VideoSubtitles extends Component {
+ state = {
+ subtitles: [],
+ current: null,
+ }
+ componentDidMount() {
+ this.loadSubtitles()
+ }
+ componentDidUpdate(prevProps) {
+ if (this.props.play_ts !== prevProps.play_ts) {
+ this.updateCurrentSubtitle()
+ }
+ }
+ 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 })
+ }
+ 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 { current } = this.state
+ if (!current) return <div className="video-subtitles hidden" />
+ return (
+ <div className="video-subtitles">
+ {current.lines.map(line => <span key={line}>{line}</span>)}
+ </div>
+ )
+ }
+}
diff --git a/animism-align/frontend/app/views/viewer/transcript/components/elementTypes.gallery.js b/animism-align/frontend/app/views/viewer/transcript/components/elementTypes.gallery.js
index 30a8fa5..effd8a7 100644
--- a/animism-align/frontend/app/views/viewer/transcript/components/elementTypes.gallery.js
+++ b/animism-align/frontend/app/views/viewer/transcript/components/elementTypes.gallery.js
@@ -10,7 +10,7 @@ export const MediaGallery = ({ paragraph, media, currentParagraph, currentAnnota
return <div />
}
const item = media.lookup[annotation.settings.media_id]
- console.log(item)
+ // console.log(item)
if (!item) return <div>Media not found: {annotation.settings.media_id}</div>
return (
<div
diff --git a/animism-align/frontend/app/views/viewer/transcript/components/elementTypes.image.js b/animism-align/frontend/app/views/viewer/transcript/components/elementTypes.image.js
index b1b846f..6e24c9a 100644
--- a/animism-align/frontend/app/views/viewer/transcript/components/elementTypes.image.js
+++ b/animism-align/frontend/app/views/viewer/transcript/components/elementTypes.image.js
@@ -36,7 +36,7 @@ export const MediaImage = ({ paragraph, media, currentParagraph, currentAnnotati
if (!media.lookup) return <div />
const className = currentParagraph ? 'media image current' : 'media image'
const annotation = paragraph.annotations[0]
- console.log(annotation.settings.hide_in_transcript)
+ // console.log(annotation.settings.hide_in_transcript)
if (annotation.settings.hide_in_transcript) {
return <div />
}