Spaces:
Running
Running
Replacing the transcript viewer of the SRT result with a text area with a copy button
d8e57c8
verified
<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> |