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> |