Skip to content

Commit

Permalink
caption character count guidelines and warnings
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeybird248 committed Dec 11, 2024
1 parent d5d09ee commit 00271a5
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 21 deletions.
90 changes: 86 additions & 4 deletions src/screens/Watch/Components/Transcriptions/CaptionLine/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ function CaptionLine({ caption = {}, allowEdit, dispatch, fontSize }) {
const [fullBeginTime, setFullBeginTime] = useState(begin);
const [fullEndTime, setFullEndTime] = useState(end);
const [savedText, setSavedText] = useState(text);
const [violations, setViolations] = useState([]);
const [isTextInvalid, setIsTextInvalid] = useState(false);

const [displayedStartTime, setDisplayedStartTime] = useState(prettierTimeStr(begin, false));
const [displayedEndTime, setDisplayedEndTime] = useState(prettierTimeStr(end, false));
Expand All @@ -28,16 +30,89 @@ function CaptionLine({ caption = {}, allowEdit, dispatch, fontSize }) {
return true;
};

const validateText = (input) => {
const MAX_LINE_LENGTH = 42;
let lines = [];
let violations = [];

const splitText = (text) => {
let currentLine = '';
let words = text.split(' ');
let currentLineLength = 0;

console.log(`Processing text: "${text}"`);

words.forEach((word) => {
if (currentLineLength + word.length + (currentLineLength > 0 ? 1 : 0) > MAX_LINE_LENGTH) {
lines.push(currentLine.trim());
currentLine = word;
currentLineLength = word.length;
} else {
if (currentLineLength > 0) {
currentLine += ' ';
currentLineLength += 1;
}
currentLine += word;
currentLineLength += word.length;
}
});

if (currentLine) {
lines.push(currentLine.trim());
}
};
splitText(input);

console.log(`Lines after split: ${JSON.stringify(lines)}`);

lines.forEach((line, index) => {
if (line.length > MAX_LINE_LENGTH) {
violations.push(`Line ${index + 1} exceeds the max character length.`);
}
});

if (input.length <= MAX_LINE_LENGTH && lines.length > 1) {
violations.push("Text is incorrectly flagged as multi-line for a short subtitle.");
}

if (lines.length > 2) {
violations.push('Text exceeds two lines.');
}

console.log(`Violations: ${JSON.stringify(violations)}`);

return { lines, violations };
};


// The control flow is that a change to time is saved in handleTimeKeyDown,
// which triggers handleSave, which then changes the displayedTime to the correct truncated time
const handleSave = () => {
const { lines, violations: textViolations } = validateText(savedText);

const beginTime = parseFloat(fullBeginTime.replace(/:/g, ''));
const endTime = parseFloat(fullEndTime.replace(/:/g, ''));
const duration = endTime - beginTime;

const durationViolations = [];
if (duration < 1.5) {
durationViolations.push('Caption duration is too short (less than 1.5 seconds).');
} else if (duration > 6) {
durationViolations.push('Caption duration is too long (more than 6 seconds).');
}

const allViolations = [...textViolations, ...durationViolations];

dispatch({
type: 'watch/saveCaption',
payload: { caption, text: savedText, begin: fullBeginTime, end: fullEndTime },
payload: { caption, text: lines.join('\n'), begin: fullBeginTime, end: fullEndTime },
});
setDisplayedStartTime(prettierTimeStr(fullBeginTime, false));
setDisplayedEndTime(prettierTimeStr(fullEndTime, false));
setViolations(allViolations);
setIsTextInvalid(allViolations.length > 0);
};


useEffect(() => {
handleSave()
Expand All @@ -54,7 +129,11 @@ function CaptionLine({ caption = {}, allowEdit, dispatch, fontSize }) {
// update the DOM
const handleTextBlur = () => {
if (textRef.current) {
textRef.current.innerText = savedText
// textRef.current.innerText = savedText
const { lines, violations: newViolations } = validateText(savedText);
textRef.current.innerText = lines.join('\n');
setViolations(newViolations);
setIsTextInvalid(newViolations.length > 0);
}
};

Expand Down Expand Up @@ -113,7 +192,7 @@ function CaptionLine({ caption = {}, allowEdit, dispatch, fontSize }) {
return (
<div
id={`caption-line-${id}`}
className="watch-caption-line"
className={`watch-caption-line ${isTextInvalid ? 'invalid-text' : ''}`}
kind={kind}
data-unsaved
>
Expand Down Expand Up @@ -143,14 +222,17 @@ function CaptionLine({ caption = {}, allowEdit, dispatch, fontSize }) {
role="textbox"
tabIndex={0}
id={`caption-line-textarea-${id}`}
className={`caption-line-text-${fontSize}`}
className={`caption-line-text-${fontSize} ${isTextInvalid ? 'invalid-text' : ''}`}
spellCheck={false}
onFocus={handleTextFocus}
onBlur={() => { handleTextBlur(text) }}
onKeyDown={(e) => { handleTextKeyDown(e, textRef) }}
>
{savedText}
</div>
<div className="violations">
<span className="tooltip">{violations.join(', ')}</span>
</div>

{/* Editable End Time */}
<div
Expand Down
41 changes: 41 additions & 0 deletions src/screens/Watch/Components/Transcriptions/CaptionLine/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -362,3 +362,44 @@
line-height: 2em;
color: var(--ct-text-white-hover);
}

.invalid-text {
color: red !important;
}

.tooltip {
visibility: hidden;
width: 200px;
background-color: rgba(0, 0, 0, 0.8);
color: #fff;
text-align: center;
border-radius: 5px;
padding: 8px;
position: absolute;
z-index: 1;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
opacity: 0;
transition: opacity 0.2s ease-in-out;
}

.tooltip::after {
content: '';
position: absolute;
top: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: rgba(0, 0, 0, 0.8) transparent transparent transparent;
}

.caption-line-text-small:hover .tooltip,
.caption-line-text-medium:hover .tooltip,
.caption-line-text-large:hover .tooltip,
.caption-line-text-normal:hover .tooltip,
.watch-caption-line.invalid-text:hover .tooltip {
visibility: visible;
opacity: 1;
}
34 changes: 17 additions & 17 deletions src/screens/Watch/model/trans_effects.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,36 +62,36 @@ export default {

// We have an array of transcript Ids to display, time to get the actual transcripts from the server
*setCurrTrans({ payload: trans }, { all, call, put }) {
// console.log("Starting setCurrTrans with trans payload:", trans);
// // console.log("Starting setCurrTrans with trans payload:", trans);

// Ensure trans is an array
if (!Array.isArray(trans)) {
trans = [trans];
}
// console.log("Normalized trans array:", trans);
// // console.log("Normalized trans array:", trans);

let alldata;
if (trans.length > 0) {
// console.log("Fetching captions for each transcription ID...");
// // console.log("Fetching captions for each transcription ID...");

// Fetch data for each transcription ID
const allTranscriptionData = yield all(
trans.map((tran) => call(api.getCaptionsByTranscriptionId, tran.id))
);
// console.log("Fetched allTranscriptionData:", allTranscriptionData);
// // console.log("Fetched allTranscriptionData:", allTranscriptionData);

// Attach transcription reference to each caption
allTranscriptionData.forEach((captionList, listIndex) => {
const t = trans[listIndex];
captionList.data?.forEach((c) => {
c.transcription = t;
// console.log(`Assigned transcription for caption (ID: ${c.id}):`, c.transcription);
// // console.log(`Assigned transcription for caption (ID: ${c.id}):`, c.transcription);
});
});

// Merge all caption data into alldata
alldata = allTranscriptionData.reduce((acc, { data = [] }) => [...acc, ...data], []);
// console.log("Combined alldata:", alldata);
// // console.log("Combined alldata:", alldata);
}

if (alldata === undefined) {
Expand All @@ -101,20 +101,20 @@ export default {
// Filter captions by transcription type
let closedcaptions = alldata.filter((c) => c.transcription.transcriptionType === 0);
let descriptions = alldata.filter((c) => c.transcription.transcriptionType !== 0);
// console.log("Filtered closedcaptions:", closedcaptions);
// console.log("Filtered descriptions:", descriptions);
// // console.log("Filtered closedcaptions:", closedcaptions);
// // console.log("Filtered descriptions:", descriptions);

// Dispatch closed captions
yield put({ type: 'setCaptions', payload: closedcaptions });

// Dispatch descriptions
const descriptionData = descriptions;
// console.log("Dispatching descriptionData:", descriptionData);
// // console.log("Dispatching descriptionData:", descriptionData);
yield put.resolve({ type: 'setDescriptions', payload: descriptionData });

// Dispatch final transcript set
yield put({ type: 'setTranscript' });
// console.log("Completed setCurrTrans");
// // console.log("Completed setCurrTrans");
},

*setTranscriptions({ payload: trans }, { put, select }) {
Expand Down Expand Up @@ -155,7 +155,7 @@ export default {

const next = findCurrent(watch.transcript, prevCaption_, currentTime);
if (next && next.id) {
// console.log(next);
// // console.log(next);
// pause video if it's AD

// determine whether should scroll smoothly
Expand All @@ -170,8 +170,8 @@ export default {
} else {
yield put({ type: 'setCurrCaption', payload: null });
}
// console.log(watch)
// console.log(`pauseWhileAD:${playerpref.pauseWhileAD}`);
// // console.log(watch)
// // console.log(`pauseWhileAD:${playerpref.pauseWhileAD}`);
const nextDescription = findCurrentDescription(watch.descriptions, currentTime);
if (playerpref.openAD && nextDescription) {
const nextDescriptionBeginTime = timeStrToSec(nextDescription.begin);
Expand All @@ -180,7 +180,7 @@ export default {
yield put({ type: 'media_pause' });
}
// Speak out loud
// console.log(`SPEAK ${nextDescription.text}`);
// // console.log(`SPEAK ${nextDescription.text}`);
yield put({ type: 'playerpref/setPreference', payload: { description: nextDescription.text } })
}
}
Expand Down Expand Up @@ -254,7 +254,7 @@ export default {

// currEditing could be missing if captions are frozen
// if (!text || !watch?.currEditing || (watch.currEditing && watch.currEditing.text === text && watch.currEditing.begin === begin)) {
// console.log("Exiting saveCaption early. Conditions not met.");
// // console.log("Exiting saveCaption early. Conditions not met.");
// promptControl.closePrompt();
// return;
// // return this.edit(null); NOT IMPLEMENTED
Expand Down Expand Up @@ -297,10 +297,10 @@ export default {
yield call(api.updateCaptionLine, { id, text, begin, end });

if (isClosedCaption) {
console.log("Updating closed captions in state.");
// console.log("Updating closed captions in state.");
yield put({ type: 'setCaptions', payload: watch.captions });
} else {
console.log("Updating descriptions in state.");
// console.log("Updating descriptions in state.");
yield put({ type: 'setDescriptions', payload: watch.descriptions });
}
// another elif here for chapter breaks eventually
Expand Down

0 comments on commit 00271a5

Please sign in to comment.