Skip to content

Commit 286687d

Browse files
author
Pietro Passarelli
committed
Added option to double click on a word to jump to that point in media
1 parent 875aaab commit 286687d

File tree

9 files changed

+130
-15
lines changed

9 files changed

+130
-15
lines changed

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,17 @@
5757
"@fortawesome/free-solid-svg-icons": "^5.12.1",
5858
"@fortawesome/react-fontawesome": "^0.1.5",
5959
"@storybook/addon-storysource": "^5.3.18",
60+
"difflib": "^0.2.4",
6061
"docx": "4.7.1",
62+
"number-to-words": "^1.2.4",
6163
"prop-types": "^15.7.2",
6264
"react-bootstrap": "^1.0.1",
6365
"sbd": "^1.0.18",
6466
"slate": "^0.59.0",
6567
"slate-history": "^0.59.0",
6668
"slate-react": "^0.59.0",
6769
"smpte-timecode": "^1.2.3",
68-
"stt-align-node": "^1.1.7"
70+
"stt-align-node": "^1.1.8"
6971
},
7072
"husky": {
7173
"hooks": {

src/components/index.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ import updateTimestamps from '../util/export-adapters/slate-to-dpe/update-timest
4242
import exportAdapter from '../util/export-adapters';
4343
import isEmpty from '../util/is-empty';
4444
import generatePreviousTimingsUpToCurrent from '../util/dpe-to-slate/generate-previous-timings-up-to-current';
45+
import getSelectionNodes from '../util/get-selection-nodes';
46+
4547
const PLAYBACK_RATE_VALUES = [0.2, 0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 2.25, 2.5, 3, 3.5];
4648
const SEEK_BACK_SEC = 15;
4749
const PAUSE_WHILTE_TYPING_TIMEOUT_MILLISECONDS = 1500;
@@ -276,6 +278,10 @@ export default function SlateTranscriptEditor(props) {
276278
style={{ cursor: 'pointer' }}
277279
className={'timecode text-muted unselectable'}
278280
onClick={handleTimedTextClick}
281+
// onClick={(e) => {
282+
// e.preventDefault();
283+
// }}
284+
onDoubleClick={handleTimedTextClick}
279285
title={props.element.startTimecode}
280286
data-start={props.element.start}
281287
>
@@ -321,11 +327,19 @@ export default function SlateTranscriptEditor(props) {
321327
mediaRef.current.play();
322328
}
323329
} else if (e.target.dataset.slateString) {
330+
console.log('e.target.dataset.slateString');
324331
if (e.target.parentNode.dataset.start) {
325-
const start = e.target.parentNode.dataset.start;
326-
if (mediaRef && mediaRef.current && start) {
327-
mediaRef.current.currentTime = parseFloat(start);
332+
const { startSec } = getSelectionNodes(editor, editor.selection);
333+
console.log('startSec', startSec);
334+
if (mediaRef && mediaRef.current && startSec) {
335+
mediaRef.current.currentTime = parseFloat(startSec);
328336
mediaRef.current.play();
337+
} else {
338+
// const start = e.target.parentNode.dataset.start;
339+
// if (mediaRef && mediaRef.current && start) {
340+
// mediaRef.current.currentTime = parseFloat(start);
341+
// mediaRef.current.play();
342+
// }
329343
}
330344
}
331345
}

src/util/dpe-to-slate/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import { shortTimecode } from '../timecode-converter';
2222
* @param {Number} time - float, time in seconds
2323
*/
2424

25+
import getWordsForParagraph from '../get-words-for-paragraph';
26+
2527
export const generatePreviousTimings = (time) => {
2628
// https://stackoverflow.com/questions/3746725/how-to-create-an-array-containing-1-n
2729
if (time) {
@@ -96,7 +98,7 @@ const convertDpeToSlate = (transcript) => {
9698
{
9799
text: generateText(paragraph, words),
98100
// Adding list of words in slateJs paragraphs
99-
words,
101+
words: getWordsForParagraph(paragraph, words),
100102
},
101103
],
102104
}));

src/util/export-adapters/slate-to-dpe/index.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
* https://github.com/pietrop/react-transcript-editor/blob/master/packages/components/timed-text-editor/UpdateTimestamps/index.js
44
* similar to updateTimestamps
55
*/
6-
// import { alignSTT } from 'stt-align-node';
7-
// import slateToText from '../txt';
86
import countWords from '../../count-words';
97
import updateTimestampsHelper from './update-timestamps/update-timestamps-helper';
108
/**

src/util/export-adapters/slate-to-dpe/update-timestamps/index.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { shortTimecode } from '../../../timecode-converter';
77
import { generatePreviousTimingsUpToCurrentOne } from '../../../dpe-to-slate';
88
import countWords from '../../../count-words';
99
import updateTimestampsHelper from './update-timestamps-helper';
10+
import getWordsForParagraph from '../../../get-words-for-paragraph';
1011
/**
1112
* Transposes the timecodes from stt json list of words onto
1213
* slateJs value paragraphs
@@ -27,6 +28,8 @@ export const createSlateContentFromSlateJsParagraphs = (currentContent, newEntit
2728
const blockEntites = newEntities.slice(totalWords, totalWords + wordsInBlock);
2829
let speaker = block.speaker;
2930
const start = parseFloat(blockEntites[0].start);
31+
const end = parseFloat(blockEntites[blockEntites.length - 1].end);
32+
const currentParagraph = { start, end };
3033
if (!speaker) {
3134
speaker = 'U_UKN';
3235
}
@@ -36,7 +39,13 @@ export const createSlateContentFromSlateJsParagraphs = (currentContent, newEntit
3639
start,
3740
previousTimings: generatePreviousTimingsUpToCurrentOne(blockEntites, start),
3841
startTimecode: shortTimecode(start),
39-
children: [{ text }],
42+
children: [
43+
{
44+
text,
45+
words: blockEntites,
46+
// getWordsForParagraph(currentParagraph, newEntities)
47+
},
48+
],
4049
};
4150

4251
updatedBlockArray.push(updatedBlock);
@@ -53,6 +62,8 @@ export const createSlateContentFromSlateJsParagraphs = (currentContent, newEntit
5362
*/
5463
const updateTimestamps = (currentContent, words) => {
5564
const alignedWords = updateTimestampsHelper(currentContent, words);
65+
// TODO: there seem to be some words without text attribute, so doing a quick fix clean up
66+
5667
const updatedContent = createSlateContentFromSlateJsParagraphs(currentContent, alignedWords);
5768
return updatedContent;
5869
};

src/util/export-adapters/slate-to-dpe/update-timestamps/update-timestamps-helper.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,30 @@
44
*
55
*/
66
import { alignSTT } from 'stt-align-node';
7+
// import alignSTT from '../../../stt-align-node';
78
import slateToText from '../../txt';
9+
// Yo
810
/**
911
* Update timestamps usign stt-align module
1012
* @param {*} currentContent - slate js value
1113
* @param {*} words - list of stt words
1214
* @return slateJS value
1315
*/
1416
export const updateTimestampsHelper = (currentContent, words) => {
15-
const currentText = slateToText({ value: currentContent, speakers: false, timecodes: false, atlasFormat: false });
16-
const alignedWords = alignSTT(words, currentText);
17-
return alignedWords;
17+
let tmpWords = words;
18+
const currentText = slateToText({
19+
value: currentContent,
20+
speakers: false,
21+
timecodes: false,
22+
atlasFormat: false,
23+
});
24+
const alignedWords = alignSTT(tmpWords, currentText);
25+
const alignedWordsCleanedUp = alignedWords.filter((word) => {
26+
if (word.text) {
27+
return word;
28+
}
29+
});
30+
return alignedWordsCleanedUp;
1831
};
1932

2033
export default updateTimestampsHelper;

src/util/get-selection-nodes/index.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
const getSelectionNodes = (editor, selection) => {
2+
console.log('selection', selection);
3+
try {
4+
const orderedSelection = [selection.anchor, selection.focus].sort((a, b) => {
5+
return a.path[0] - b.path[0];
6+
});
7+
const selectionStart = orderedSelection[0];
8+
const selectionEnd = orderedSelection[1];
9+
let counterAnchor = 0;
10+
let goalAnchor = selectionStart.offset;
11+
let targetWordIndexAnchor = null;
12+
let selectedLeafWordsAnchor = editor.children[selectionStart.path[0]].children[0].words;
13+
// let pathValue = selectionStart.path;
14+
// console.log('editor.children[1]', editor.children[1]);
15+
// let selectedLeafWordsAnchor2 = editor.children[selectionStart.path].children[0].words;
16+
// console.log('selectedLeafWordsAnchor2', selectedLeafWordsAnchor2);
17+
selectedLeafWordsAnchor.forEach((word, wordIndex) => {
18+
const wordLength = (word.text + ' ').length;
19+
20+
counterAnchor = counterAnchor + wordLength;
21+
if (counterAnchor <= goalAnchor) {
22+
targetWordIndexAnchor = wordIndex;
23+
}
24+
});
25+
26+
const startWord = selectedLeafWordsAnchor[targetWordIndexAnchor + 1];
27+
console.log('startWord', startWord);
28+
console.log('selection', selection);
29+
30+
let counter = 0;
31+
let goal = selectionEnd.offset;
32+
console.log('goal', goal);
33+
let targetWordIndex = null;
34+
let selectedLeafWords = editor.children[selectionEnd.path[0]].children[0].words;
35+
selectedLeafWords.forEach((word, wordIndex) => {
36+
const wordLength = (word.text + ' ').length;
37+
38+
counter = counter + wordLength;
39+
if (counter <= goal) {
40+
targetWordIndex = wordIndex;
41+
}
42+
});
43+
44+
const endWord = selectedLeafWords[targetWordIndex + 1];
45+
// console.log('endWord', endWord);
46+
// console.log('selection', selection);
47+
console.log('startWord', startWord);
48+
// const startSec = startWord.start / 1000;
49+
// const endSec = endWord.end / 1000;
50+
// console.log('startSec', startSec);
51+
// const selObj = window.getSelection();
52+
// console.log(selObj.toString());
53+
// setSearch(selObj.toString())
54+
// createUserClip(startSec, endSec);
55+
return { startSec: startWord.start, endSec: endWord.end };
56+
} catch (error) {
57+
console.error('error creating clip', error);
58+
}
59+
};
60+
61+
export default getSelectionNodes;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
*
3+
* @param {*} currentParagraph a dpe paragraph object, with start, and end attribute eg in seconds
4+
* @param {*} words a list of word objects with start and end attributes
5+
* @returns a lsit of words obejcts that are included in the given paragraphs
6+
*/
7+
const getWordsForParagraph = (currentParagraph, words) => {
8+
const { start, end } = currentParagraph;
9+
return words.filter((word) => {
10+
return word.start >= start && word.end <= end;
11+
});
12+
};
13+
14+
export default getWordsForParagraph;

0 commit comments

Comments
 (0)