{"id":826,"date":"2025-12-25T04:23:30","date_gmt":"2025-12-25T07:23:30","guid":{"rendered":"https:\/\/chilemosaico.cl\/acusgrafia\/?page_id=826"},"modified":"2025-12-26T05:34:07","modified_gmt":"2025-12-26T08:34:07","slug":"convertidor-de-letras-lrc-%e2%87%84-srt","status":"publish","type":"page","link":"https:\/\/chilemosaico.cl\/acusgrafia\/convertidor-de-letras-lrc-%e2%87%84-srt\/","title":{"rendered":"Convertidor Express: LRC \u21c4 SRT"},"content":{"rendered":"<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-thumbnail\"><img loading=\"lazy\" decoding=\"async\" width=\"150\" height=\"150\" src=\"https:\/\/chilemosaico.cl\/acusgrafia\/wp-content\/uploads\/2025\/12\/Convertidor-extress-LCR-SRT-150x150.jpg\" alt=\"\" class=\"wp-image-868\" srcset=\"https:\/\/chilemosaico.cl\/acusgrafia\/wp-content\/uploads\/2025\/12\/Convertidor-extress-LCR-SRT-150x150.jpg 150w, https:\/\/chilemosaico.cl\/acusgrafia\/wp-content\/uploads\/2025\/12\/Convertidor-extress-LCR-SRT-300x300.jpg 300w, https:\/\/chilemosaico.cl\/acusgrafia\/wp-content\/uploads\/2025\/12\/Convertidor-extress-LCR-SRT.jpg 700w\" sizes=\"auto, (max-width: 150px) 100vw, 150px\" \/><\/figure>\n<\/div>\n\n\n<!DOCTYPE html>\n<html lang=\"es\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Convertidor Express LRC \u21c4 SRT<\/title>\n    <style>\n        :root {\n            --primary: #667eea;\n            --secondary: #764ba2;\n            --success: #2ecc71;\n        }\n\n        body {\n            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\n            background: linear-gradient(135deg, var(--primary), var(--secondary));\n            min-height: 100vh;\n            margin: 0;\n            display: flex;\n            justify-content: center;\n            align-items: center;\n            padding: 20px;\n            color: #333;\n        }\n        \n        .box {\n            background: white;\n            border-radius: 20px;\n            padding: 40px;\n            width: 100%;\n            max-width: 800px;\n            box-shadow: 0 15px 35px rgba(0,0,0,0.3);\n        }\n        \n        h1 {\n            text-align: center;\n            margin: 0 0 10px 0;\n            font-size: 28px;\n        }\n        \n        .subtitle {\n            text-align: center;\n            color: #666;\n            margin-bottom: 30px;\n        }\n        \n        \/* ZONA DE CARGA MEJORADA *\/\n        .drop-area {\n            border: 3px dashed #cbd5e0;\n            border-radius: 15px;\n            padding: 50px 20px;\n            text-align: center;\n            background: #f8fafc;\n            cursor: pointer;\n            transition: all 0.3s ease;\n            position: relative;\n        }\n        \n        .drop-area:hover {\n            border-color: var(--primary);\n            background: #edf2f7;\n        }\n        \n        .drop-area.active {\n            border-color: var(--success);\n            background: #f0fff4;\n        }\n\n        .drop-area p {\n            pointer-events: none; \/* Evita interferencia con el clic *\/\n            margin: 5px 0;\n        }\n        \n        .file-input {\n            display: none;\n        }\n        \n        \/* RESULTADO *\/\n        .result-box {\n            display: none;\n            margin-top: 25px;\n            animation: fadeIn 0.5s ease;\n        }\n        \n        @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }\n\n        .result-header {\n            display: flex;\n            justify-content: space-between;\n            align-items: center;\n            margin-bottom: 10px;\n        }\n        \n        .conversion-tag {\n            background: #ebf4ff;\n            color: #2b6cb0;\n            padding: 4px 12px;\n            border-radius: 20px;\n            font-size: 0.85rem;\n            font-weight: bold;\n        }\n        \n        textarea {\n            width: 100%;\n            height: 300px;\n            border: 2px solid #e2e8f0;\n            border-radius: 10px;\n            padding: 15px;\n            font-family: 'Consolas', 'Monaco', monospace;\n            font-size: 13px;\n            line-height: 1.6;\n            resize: vertical;\n            box-sizing: border-box;\n        }\n        \n        \/* BOTONES *\/\n        .buttons-group {\n            display: flex;\n            gap: 15px;\n            margin-top: 20px;\n            justify-content: center;\n        }\n        \n        button {\n            padding: 12px 28px;\n            border: none;\n            border-radius: 8px;\n            cursor: pointer;\n            font-weight: 600;\n            display: flex;\n            align-items: center;\n            gap: 10px;\n            transition: transform 0.2s, background 0.2s;\n        }\n\n        button:active { transform: scale(0.98); }\n        \n        .btn-download { background: var(--primary); color: white; }\n        .btn-download:hover { background: #5a6fd8; }\n        \n        .btn-copy { background: #edf2f7; color: #4a5568; }\n        .btn-copy:hover { background: #e2e8f0; }\n\n        .info-note {\n            background: #fffaf0;\n            border-left: 4px solid #ed8936;\n            padding: 12px;\n            margin-top: 20px;\n            font-size: 0.9rem;\n            color: #7b341e;\n            border-radius: 4px;\n        }\n    <\/style>\n<\/head>\n<body>\n\n<div class=\"box\">\n    <h1>\ud83d\udd04 Convertidor Express LRC \u21c4 SRT <\/h1>\n    <p class=\"subtitle\">Para cambiar formato de subt\u00edtulos, al instante<\/p>\n    \n    <div class=\"drop-area\" id=\"dropArea\">\n        <p style=\"font-size: 1.2rem; font-weight: bold;\">\ud83d\udcc1 Seleccionar archivo<\/p>\n        <p>o arrastra y suelta aqu\u00ed (.lrc \/ .srt)<\/p>\n        <input type=\"file\" id=\"fileInput\" class=\"file-input\" accept=\".lrc,.srt,.txt\">\n    <\/div>\n\n    <div class=\"result-box\" id=\"resultBox\">\n        <div class=\"result-header\">\n            <span style=\"font-weight: bold;\">Vista previa:<\/span>\n            <span class=\"conversion-tag\" id=\"tagFormat\">&#8212;<\/span>\n        <\/div>\n        <textarea id=\"resultText\" spellcheck=\"false\"><\/textarea>\n        \n        <div class=\"info-note\" id=\"silenceNote\">\n            <strong>\u2728 Modo Precisi\u00f3n:<\/strong> Se han detectado l\u00edneas vac\u00edas en el origen y se han convertido en intervalos de silencio autom\u00e1ticos.\n        <\/div>\n\n        <div class=\"buttons-group\">\n            <button class=\"btn-download\" id=\"btnDownload\"><span>\u2b07\ufe0f<\/span> Descargar archivo<\/button>\n            <button class=\"btn-copy\" id=\"btnCopy\"><span>\ud83d\udccb<\/span> Copiar texto<\/button>\n        <\/div>\n    <\/div>\n<\/div>\n\n<script>\n    const dropArea = document.getElementById('dropArea');\n    const fileInput = document.getElementById('fileInput');\n    const resultBox = document.getElementById('resultBox');\n    const resultText = document.getElementById('resultText');\n    const tagFormat = document.getElementById('tagFormat');\n    const silenceNote = document.getElementById('silenceNote');\n\n    let currentConvertedData = \"\";\n    let currentFileName = \"subtitulo_convertido\";\n    let targetExt = \"srt\";\n\n    \/\/ --- EVENTOS DE INTERFAZ ---\n\n    dropArea.addEventListener('click', () => fileInput.click());\n\n    fileInput.addEventListener('change', (e) => {\n        if (e.target.files.length > 0) handleFile(e.target.files[0]);\n    });\n\n    \/\/ Drag & Drop\n    dropArea.addEventListener('dragover', (e) => { e.preventDefault(); dropArea.classList.add('active'); });\n    dropArea.addEventListener('dragleave', () => dropArea.classList.remove('active'));\n    dropArea.addEventListener('drop', (e) => {\n        e.preventDefault();\n        dropArea.classList.remove('active');\n        if (e.dataTransfer.files.length > 0) handleFile(e.dataTransfer.files[0]);\n    });\n\n    \/\/ Pegar texto directo\n    document.addEventListener('paste', (e) => {\n        const text = e.clipboardData.getData('text');\n        if (text.trim().length > 5) processContent(text, \"pegado_directo\");\n    });\n\n    \/\/ --- LOGICA DE PROCESAMIENTO ---\n\n    function handleFile(file) {\n        currentFileName = file.name.split('.').slice(0, -1).join('.');\n        const reader = new FileReader();\n        reader.onload = (e) => processContent(e.target.result, file.name);\n        reader.readAsText(file);\n    }\n\n    function processContent(content, name) {\n        const isLRC = content.includes('[') && \/\\d{2}:\\d{2}\/.test(content);\n        const isSRT = content.includes('-->');\n\n        if (isLRC && !isSRT) {\n            currentConvertedData = lrcToSrt(content);\n            targetExt = \"srt\";\n            tagFormat.textContent = \"LRC \u2794 SRT\";\n        } else if (isSRT) {\n            currentConvertedData = srtToLrc(content);\n            targetExt = \"lrc\";\n            tagFormat.textContent = \"SRT \u2794 LRC\";\n        } else {\n            alert(\"Formato no reconocido. Aseg\u00farate de que el archivo tenga marcas de tiempo.\");\n            return;\n        }\n\n        resultText.value = currentConvertedData;\n        resultBox.style.display = 'block';\n        dropArea.innerHTML = `<p>\u2705 Archivo cargado:<\/p><p><strong>${name}<\/strong><\/p>`;\n        \n        \/\/ Mostrar nota de silencios solo si el contenido tiene l\u00edneas de tiempo vac\u00edas\n        silenceNote.style.display = content.match(\/\\]\\s*$\/m) ? 'block' : 'none';\n    }\n\n    \/\/ --- ALGORITMOS (CORREGIDOS) ---\n\n    function lrcToSrt(lrc) {\n        const lines = lrc.split('\\n');\n        let srt = '';\n        let index = 1;\n        let entries = [];\n\n        \/\/ Parsear LRC\n        lines.forEach(line => {\n            const match = line.match(\/\\[(\\d+):(\\d+)\\.(\\d+)\\](.*)\/);\n            if (match) {\n                const ms = parseInt(match[1]) * 60 * 1000 + parseInt(match[2]) * 1000 + parseInt(match[3]) * 10;\n                entries.push({ time: ms, text: match[4].trim() });\n            }\n        });\n\n        \/\/ Ordenar por tiempo\n        entries.sort((a, b) => a.time - b.time);\n\n        \/\/ Convertir a SRT respetando silencios\n        for (let i = 0; i < entries.length; i++) {\n            const current = entries[i];\n            const next = entries[i + 1];\n\n            \/\/ Si la l\u00ednea actual tiene texto, creamos un bloque SRT\n            if (current.text !== \"\") {\n                const startTime = formatSrtTime(current.time);\n                \/\/ El tiempo final es el inicio de la siguiente marca (sea texto o silencio)\n                const endTime = next ? formatSrtTime(next.time) : formatSrtTime(current.time + 3000);\n\n                srt += `${index}\\n${startTime} --> ${endTime}\\n${current.text}\\n\\n`;\n                index++;\n            }\n            \/\/ Si current.text es vac\u00edo, simplemente no creamos bloque, \n            \/\/ lo que genera el \"hueco\" visual en el reproductor.\n        }\n        return srt.trim();\n    }\n\n    function srtToLrc(srt) {\n        const blocks = srt.trim().split(\/\\n\\s*\\n\/);\n        let lrc = '';\n        blocks.forEach(block => {\n            const lines = block.split('\\n');\n            const timeMatch = lines[1]?.match(\/(\\d{2}):(\\d{2}):(\\d{2}),(\\d{3})\/);\n            if (timeMatch) {\n                const min = String(parseInt(timeMatch[1]) * 60 + parseInt(timeMatch[2])).padStart(2, '0');\n                const sec = timeMatch[3];\n                const ms = timeMatch[4].substring(0, 2);\n                const text = lines.slice(2).join(' ');\n                lrc += `[${min}:${sec}.${ms}]${text}\\n`;\n            }\n        });\n        return lrc.trim();\n    }\n\n    function formatSrtTime(totalMs) {\n        const ms = totalMs % 1000;\n        const totalSecs = Math.floor(totalMs \/ 1000);\n        const secs = totalSecs % 60;\n        const mins = Math.floor(totalSecs \/ 60) % 60;\n        const hrs = Math.floor(totalSecs \/ 3600);\n        return `${String(hrs).padStart(2, '0')}:${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')},${String(ms).padStart(3, '0')}`;\n    }\n\n    \/\/ --- ACCIONES DE BOTONES ---\n\n    document.getElementById('btnDownload').onclick = () => {\n        const blob = new Blob([currentConvertedData], { type: 'text\/plain' });\n        const url = URL.createObjectURL(blob);\n        const a = document.createElement('a');\n        a.href = url;\n        a.download = `${currentFileName}.${targetExt}`;\n        a.click();\n        URL.revokeObjectURL(url);\n    };\n\n    document.getElementById('btnCopy').onclick = () => {\n        navigator.clipboard.writeText(currentConvertedData);\n        const btn = document.getElementById('btnCopy');\n        const original = btn.innerHTML;\n        btn.innerHTML = \"\u2705 \u00a1Copiado!\";\n        setTimeout(() => btn.innerHTML = original, 2000);\n    };\n<\/script>\n\n<\/body>\n<\/html>\n","protected":false},"excerpt":{"rendered":"<p>Convertidor Express LRC \u21c4 SRT \ud83d\udd04 Convertidor Express LRC \u21c4 SRT Para cambiar formato de subt\u00edtulos, al instante \ud83d\udcc1 Seleccionar archivo o arrastra y suelta aqu\u00ed (.lrc \/ .srt) Vista previa: &#8212; \u2728 Modo Precisi\u00f3n: Se han detectado l\u00edneas vac\u00edas en el origen y se han convertido en intervalos de silencio autom\u00e1ticos. \u2b07\ufe0f Descargar archivo&#8230;<\/p>\n","protected":false},"author":1,"featured_media":868,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_kad_post_transparent":"","_kad_post_title":"hide","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"","footnotes":""},"class_list":["post-826","page","type-page","status-publish","has-post-thumbnail","hentry"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/chilemosaico.cl\/acusgrafia\/wp-json\/wp\/v2\/pages\/826","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/chilemosaico.cl\/acusgrafia\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/chilemosaico.cl\/acusgrafia\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/chilemosaico.cl\/acusgrafia\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/chilemosaico.cl\/acusgrafia\/wp-json\/wp\/v2\/comments?post=826"}],"version-history":[{"count":38,"href":"https:\/\/chilemosaico.cl\/acusgrafia\/wp-json\/wp\/v2\/pages\/826\/revisions"}],"predecessor-version":[{"id":872,"href":"https:\/\/chilemosaico.cl\/acusgrafia\/wp-json\/wp\/v2\/pages\/826\/revisions\/872"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/chilemosaico.cl\/acusgrafia\/wp-json\/wp\/v2\/media\/868"}],"wp:attachment":[{"href":"https:\/\/chilemosaico.cl\/acusgrafia\/wp-json\/wp\/v2\/media?parent=826"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}