CTM-to-SRT / index.html
abdelhaqueidali's picture
Replacing the transcript viewer of the SRT result with a text area with a copy button
d8e57c8 verified
raw
history blame contribute delete
7.37 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CTM to SRT Converter</title>
<style>
body {
font-family: sans-serif;
margin: 20px;
}
label {
display: block;
margin-bottom: 5px;
}
textarea, input[type="file"] {
width: 100%;
margin-bottom: 10px;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
}
button {
padding: 10px 15px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #45a049;
}
#downloadBtn {
margin-top: 10px;
background-color: #008CBA;
}
#downloadBtn:hover {
background-color: #0077a3;
}
#ctmFileName{
margin-bottom: 10px;
}
#srtOutput {
margin-top: 10px;
min-height: 200px; /* Added for better visibility */
}
#copyBtn {
background-color: #2196F3; /* Different color for distinction */
margin-left: 10px; /* Space between buttons */
}
#copyBtn:hover{
background-color: #0d8bf2;
}
/* Styling for the container holding the textarea and copy button */
.output-container {
display: flex;
align-items: flex-start; /* Align items to the top */
gap: 10px; /* Space between textarea and button */
}
.output-container textarea {
flex-grow: 1; /* Allow textarea to take up remaining space */
}
</style>
</head>
<body>
<h1>CTM to SRT Converter</h1>
<label for="ctmInput">Paste CTM Data:</label>
<textarea id="ctmInput" rows="10" placeholder="Paste your CTM data here..."></textarea>
<label for="ctmFile">Or Upload CTM File:</label>
<input type="file" id="ctmFile" accept=".ctm">
<div id="ctmFileName"></div>
<button id="convertBtn">Convert</button>
<button id="downloadBtn" class="hidden">Download SRT</button>
<h2>SRT Output</h2>
<div class="output-container">
<textarea id="srtOutput" readonly></textarea>
<button id="copyBtn">Copy</button>
</div>
<script>
const ctmInput = document.getElementById('ctmInput');
const ctmFile = document.getElementById('ctmFile');
const ctmFileName = document.getElementById('ctmFileName');
const convertBtn = document.getElementById('convertBtn');
const downloadBtn = document.getElementById('downloadBtn');
const srtOutput = document.getElementById('srtOutput'); // SRT output textarea
const copyBtn = document.getElementById('copyBtn'); // Copy button
let segments = [];
let fileData = null; // Store file data
function parseCTM(ctmData) {
const lines = ctmData.trim().split('\n');
const segments = [];
for (const line of lines) {
const parts = line.split(/\s+/);
if (parts.length >= 5) {
const segment = {
filename: parts[0],
channel: parts[1],
startTime: parseFloat(parts[2]),
duration: parseFloat(parts[3]),
text: parts.slice(4).join(' ').replace(/<space>/g, ' '),
};
segments.push(segment);
} else {
console.warn("Skipping invalid CTM line:", line);
}
}
return segments;
}
function generateSRT(segments) {
let srtContent = '';
segments.forEach((segment, index) => {
const startTime = formatTime(segment.startTime);
const endTime = formatTime(segment.startTime + segment.duration);
srtContent += `${index + 1}\n${startTime} --> ${endTime}\n${segment.text}\n\n`;
});
return srtContent;
}
function formatTime(seconds) {
const date = new Date(seconds * 1000);
const hh = date.getUTCHours().toString().padStart(2, '0');
const mm = date.getUTCMinutes().toString().padStart(2, '0');
const ss = date.getUTCSeconds().toString().padStart(2, '0');
const ms = date.getUTCMilliseconds().toString().padStart(3, '0');
return `${hh}:${mm}:${ss},${ms}`;
}
function processData() {
let ctmData = null;
if (fileData) {
ctmData = fileData; // Prioritize file data
} else {
ctmData = ctmInput.value;
}
if (ctmData) {
segments = parseCTM(ctmData);
if (segments.length > 0) {
const srtData = generateSRT(segments); // Generate SRT content
srtOutput.value = srtData; // Display in textarea
downloadBtn.classList.remove('hidden');
} else {
srtOutput.value = 'No valid CTM data found.';
downloadBtn.classList.add('hidden');
}
} else {
srtOutput.value = 'No CTM data provided.';
downloadBtn.classList.add('hidden');
}
}
ctmFile.addEventListener('change', (event) => {
const file = event.target.files[0];
if (file) {
ctmFileName.textContent = "Current CTM file: " + file.name;
const reader = new FileReader();
reader.onload = (e) => {
fileData = e.target.result; // Store the file data
// Don't process here, wait for the Convert button
};
reader.onerror = () => {
console.error("Error reading CTM file.");
srtOutput.value = 'Error reading CTM file.';
downloadBtn.classList.add('hidden');
fileData = null; // Reset on error
};
reader.readAsText(file);
} else {
// No file selected, clear stored data
fileData = null;
ctmFileName.textContent = "";
}
});
convertBtn.addEventListener('click', processData);
downloadBtn.addEventListener('click', () => {
const srtData = srtOutput.value; // Get SRT data from textarea
const blob = new Blob([srtData], { type: 'text/srt' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
let srtFilename = "transcript.srt";
if (segments.length > 0 && segments[0].filename) {
srtFilename = segments[0].filename + ".srt";
}
a.download = srtFilename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
});
// Copy button functionality
copyBtn.addEventListener('click', () => {
srtOutput.select(); // Select the text in the textarea
document.execCommand('copy'); // Execute the copy command
// Optional: Provide user feedback (e.g., change button text)
copyBtn.textContent = 'Copied!';
setTimeout(() => {
copyBtn.textContent = 'Copy';
}, 2000); // Reset after 2 seconds
});
</script>
</body>
</html>