Skip to content

Commit

Permalink
feat: Transcript
Browse files Browse the repository at this point in the history
  • Loading branch information
Betree committed Jun 19, 2024
1 parent fe68439 commit a1d4d27
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 8 deletions.
12 changes: 11 additions & 1 deletion app/components/StyledUtils/Text.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import styled from 'styled-components'
import { color, display, fontSize, fontStyle, fontWeight, space, textAlign } from 'styled-system'
import {
color,
display,
fontSize,
fontStyle,
fontWeight,
lineHeight,
space,
textAlign,
} from 'styled-system'

export const Span = styled.span`
${color}
Expand All @@ -25,4 +34,5 @@ export const P = styled.p`
${space}
${display}
${textAlign}
${lineHeight}
`
96 changes: 96 additions & 0 deletions app/components/VideoDebate/CaptionsExtractor.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { gql, useQuery } from '@apollo/client'

Check failure on line 1 in app/components/VideoDebate/CaptionsExtractor.jsx

View workflow job for this annotation

GitHub Actions / lint

Run autofix to sort these imports!
import React from 'react'

import { P } from '../StyledUtils/Text'
import { LoadingFrame } from '../Utils'
import Message from '../Utils/Message'
import { connect } from 'react-redux'
import styled, { css } from 'styled-components'

const captionsQuery = gql`
query VideoCaptionsQuery($videoId: ID!) {
video(hashId: $videoId) {
id
captions {
text
start
duration
}
}
}
`

const CaptionText = styled.span`
color: #000;
transition:
color 0.3s,
text-shadow 0.3s;
${({ $isCurrent, $isPlaying, $isPast }) => {
if ($isPlaying) {
if ($isCurrent) {
return css`
text-shadow: #9f9f9f 1px 1px 0px;
color: #000;
`
} else if (!$isPast) {
return css`
color: #999;
`
}
}
}}
`

const CaptionsExtractor = ({ videoId, playbackPosition, statements }) => {

Check failure on line 45 in app/components/VideoDebate/CaptionsExtractor.jsx

View workflow job for this annotation

GitHub Actions / lint

'statements' is defined but never used
const { data, loading, error } = useQuery(captionsQuery, { variables: { videoId } })

// TODO watch only selection inside the captions container
React.useEffect(() => {
// Watch for selection changes
const eventListener = (e) => {

Check failure on line 51 in app/components/VideoDebate/CaptionsExtractor.jsx

View workflow job for this annotation

GitHub Actions / lint

'e' is defined but never used
console.log('selectionchange')

Check failure on line 52 in app/components/VideoDebate/CaptionsExtractor.jsx

View workflow job for this annotation

GitHub Actions / lint

Unexpected console statement
}

document.addEventListener('selectionchange', eventListener)
return () => {
document.removeEventListener('selectionchange', eventListener)
}
}, [])

if (loading) {
return <LoadingFrame title="Loading captions" />
} else if (error) {
// eslint-disable-next-line no-console
console.error(error)
return <Message type="danger">Error loading captions</Message>
} else if (!data.video.captions?.length) {
return <Message type="info">No captions available</Message>
}

return (
<P fontSize="20px" lineHeight="1.5">
{data.video.captions.map((caption, index) => {
return (
<React.Fragment key={index}>
<CaptionText
$isPlaying={Boolean(playbackPosition)}
$isPast={playbackPosition > caption.start + caption.duration}
$isCurrent={
playbackPosition >= caption.start &&
playbackPosition <= caption.start + caption.duration
}
>
{caption.text}
</CaptionText>{' '}
</React.Fragment>
)
})}
</P>
)
}

export default connect((state) => ({
statements: state.VideoDebate.statements.data,
playbackPosition: state.VideoDebate.video.playback.position,
}))(CaptionsExtractor)
12 changes: 10 additions & 2 deletions app/components/VideoDebate/ColumnDebate.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,19 @@ import { isLoadingVideoDebate } from '../../state/video_debate/selectors'
import { hasStatementForm } from '../../state/video_debate/statements/selectors'
import { withLoggedInUser } from '../LoggedInUser/UserProvider'
import StatementsList from '../Statements/StatementsList'
import Container from '../StyledUtils/Container'
import DismissableMessage from '../Utils/DismissableMessage'
import ExternalLinkNewTab from '../Utils/ExternalLinkNewTab'
import { Icon } from '../Utils/Icon'
import { LoadingFrame } from '../Utils/LoadingFrame'
import Message from '../Utils/Message'
import ActionBubbleMenu from './ActionBubbleMenu'
import CaptionsExtractor from './CaptionsExtractor'
import VideoDebateHistory from './VideoDebateHistory'

const TitleContainer = styled.div`
padding: 1.5rem;
margin-top: 1rem;
`
const TitleH1 = styled.h1`
color: #0a0a0a;
Expand Down Expand Up @@ -90,8 +93,13 @@ export class ColumnDebate extends React.PureComponent {

if (view === 'history') {
return <VideoDebateHistory videoId={videoId} />
}
if (view === 'debate') {
} else if (view === 'captions') {
return (
<Container p={4}>
<CaptionsExtractor videoId={videoId} />
</Container>
)
} else if (view === 'debate') {
if (isLoading) {
return <LoadingFrame title={this.props.t('loading.statements')} />
}
Expand Down
15 changes: 11 additions & 4 deletions app/components/VideoDebate/ColumnVideo.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { Flex } from '@rebass/grid'
import { FileText } from '@styled-icons/feather'
import classNames from 'classnames'
import React from 'react'
import { withNamespaces } from 'react-i18next'
import { connect } from 'react-redux'
import { Link } from 'react-router-dom'

import { MIN_REPUTATION_ADD_SPEAKER } from '../../constants'
import { videoHistoryURL, videoURL } from '../../lib/cf_routes'
import { videoCaptionsUrl, videoHistoryURL, videoURL } from '../../lib/cf_routes'
import {
videoDebateOnlineUsersCount,
videoDebateOnlineViewersCount,
Expand Down Expand Up @@ -40,8 +41,7 @@ export class ColumnVideo extends React.PureComponent {

const { video, view, t } = this.props
const { url, title, speakers } = video
const isDebate = view === 'debate'

const isDebate = !view || view === 'debate'
return (
<ResizableColumn>
<div id="col-video" className="column">
Expand All @@ -58,7 +58,7 @@ export class ColumnVideo extends React.PureComponent {
<span>{t('debate')}</span>
</Link>
</li>
<li className={classNames({ 'is-active': !isDebate })}>
<li className={classNames({ 'is-active': view === 'history' })}>
<Link to={videoHistoryURL(video.hash_id)} rel="nofollow">
<Icon size="small" name="history" />
<span>{t('history')}</span>
Expand All @@ -70,6 +70,13 @@ export class ColumnVideo extends React.PureComponent {
<span>{t('chat')}</span>
</ExternalLinkNewTab>
</li>
<li className={classNames({ 'is-active': view === 'captions' })}>
<Link to={videoCaptionsUrl(video.hash_id)} rel="nofollow">
<FileText size="20" />
&nbsp;
<span>{t('captions')}</span>
</Link>
</li>
</ul>
</div>
{isDebate && (
Expand Down
1 change: 1 addition & 0 deletions app/i18n/en/videoDebate.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"comments": "Comments",
"community": "Community",
"chat": "Chat",
"captions": "Captions",
"flagForm": {
"title": "Why do you want to flag this comment?",
"xAvailable": "{{count}} available",
Expand Down
1 change: 1 addition & 0 deletions app/i18n/fr/videoDebate.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"comments": "Commentaires",
"community": "Communaut茅",
"chat": "Conversations",
"captions": "Transcription",
"flagForm": {
"title": "Pourquoi signaler ce commentaire ?",
"xAvailable": "{{count}} disponnible",
Expand Down
4 changes: 4 additions & 0 deletions app/lib/cf_routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ export const videoHistoryURL = (videoHashID) => {
return `${videoURL(videoHashID)}/history`
}

export const videoCaptionsUrl = (videoHashID) => {
return `${videoURL(videoHashID)}/captions`
}

export const statementURL = (videoHashID, statementID) => {
return `${videoURL(videoHashID)}?statement=${statementID}`
}
Expand Down
6 changes: 5 additions & 1 deletion app/router.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,11 @@ const CFRouter = () => (
<Route path="/videos" exact component={VideosIndexPage} />
<Route path="/videos/add" exact component={AddVideoForm} />
<Route path="/videos/add/:videoUrl" exact component={AddVideoForm} />
<Route path="/videos/:videoId/:view(history|debate)?" exact component={VideoDebate} />
<Route
path="/videos/:videoId/:view(history|debate|captions)?"
exact
component={VideoDebate}
/>
<Route path="/s/:slug_or_id" exact component={SpeakerPage} />
<Route path="/help/:splat?" component={Help} />
<Route path="/extension" exact component={BrowserExtensionsPage} />
Expand Down

0 comments on commit a1d4d27

Please sign in to comment.