小组件

还没有组件

图片

还没有图片

音乐

还没有音乐

便签

还没有便签

文件库

还没有文件

粘贴内容 · 套用正则后在上方渲染
正在播放
歌曲名
歌手
加载失败,可能是防盗链或非直链。
在新标签页打开原链接试试 ↗
文件预览
'; } return `
`; } // 没有默认内容:显示占位 return `
/.*/
${escH(item.pattern.substring(0,50))}
`; } return `
`; }).join(''); } function renderImages() { const grid = document.getElementById('grid-image'); const empty = document.getElementById('empty-image'); const imgs = filterByCat(store.image, 'image'); if (!imgs.length) { grid.innerHTML=''; empty.style.display='block'; return; } empty.style.display = 'none'; grid.innerHTML = imgs.map(img => `
${escH(img.name)}
`).join(''); } function renderMusic() { const grid = document.getElementById('grid-music'); const empty = document.getElementById('empty-music'); const songs = filterByCat(store.music, 'music'); if (!songs.length) { grid.innerHTML=''; empty.style.display='block'; return; } empty.style.display = 'none'; grid.innerHTML = songs.map(s => `
${escH(s.name)}
${escH(s.artist||'')}
${escH(s.url.substring(0,60))}${s.url.length>60?'...':''}
`).join(''); } function renderNotes() { const grid = document.getElementById('grid-note'); const empty = document.getElementById('empty-note'); const notes = filterByCat(store.note, 'note'); if (!notes.length) { grid.innerHTML=''; empty.style.display='block'; return; } empty.style.display = 'none'; grid.innerHTML = notes.map(n => `
${escH(n.name)}
${escH(n.body)}
`).join(''); } function renderFiles() { const list = document.getElementById('list-file'); const empty = document.getElementById('empty-file'); const files = filterByCat(store.file, 'file'); if (!files.length) { list.innerHTML=''; empty.style.display='block'; return; } empty.style.display = 'none'; list.innerHTML = files.map(f => `
${fileIcon(f.name)}
${escH(f.name)}
${formatSize(f.size)}
`).join(''); } function fileIcon(name) { const ext = name.split('.').pop().toLowerCase(); const map = { pdf:'📄', doc:'📝', docx:'📝', xls:'📊', xlsx:'📊', ppt:'🪧', pptx:'🪧', txt:'📃', json:'📋', png:'🖼', jpg:'🖼', jpeg:'🖼', gif:'🖼', mp3:'🎵', mp4:'🎬', zip:'📦', rar:'📦' }; return map[ext] || '📎'; } function openWidgetDetail(id) { const w = store.widget.find(x => x.id === id); if (!w) return; currentDetail = { type: 'widget', id }; showingCode = false; document.getElementById('dw-title').textContent = w.name; document.getElementById('dw-sub').textContent = '.' + w.tag; document.getElementById('dw-frame').srcdoc = wrap(w.code); document.getElementById('dw-code').value = w.code; document.getElementById('dw-frame').style.display = 'block'; document.getElementById('dw-code').style.display = 'none'; openDetail('detail-widget'); } function toggleWidgetCode() { showingCode = !showingCode; document.getElementById('dw-frame').style.display = showingCode ? 'none' : 'block'; document.getElementById('dw-code').style.display = showingCode ? 'block' : 'none'; } function openRegexDetail(id) { const r = store.regex.find(x => x.id === id); if (!r) return; currentDetail = { type: 'regex', id }; document.getElementById('drx-title').textContent = r.name; document.getElementById('drx-sub').textContent = r.pattern.substring(0, 80) + (r.pattern.length > 80 ? '…' : ''); const input = r.defaultContent || ''; document.getElementById('rx-content-input').value = input; document.getElementById('drx-frame').srcdoc = (input.trim() && r.replace) ? applyRegex(r, input) : ''; openDetail('detail-regex'); } function applyRegex(r, input) { try { const regex = new RegExp(r.pattern, r.flags || 'gs'); return input.replace(regex, function() { const groups = Array.from(arguments); return r.replace.replace(/\$(\d+)/g, (_, n) => groups[+n] !== undefined ? groups[+n] : ''); }); } catch(e) { return `正则错误:${e.message}
`; } } function runRegex() { const r = store.regex.find(x => x.id === currentDetail.id); if (!r) return; const input = document.getElementById('rx-content-input').value; if (!input.trim()) return; document.getElementById('drx-frame').srcdoc = applyRegex(r, input); } function openImageDetail(id) { const img = store.image.find(x => x.id === id); if (!img) return; currentDetail = { type: 'image', id }; document.getElementById('di-title').textContent = img.name; document.getElementById('di-img').src = img.url; openDetail('detail-image'); } // 播放音乐详情 function openMusicDetail(id) { const s = store.music.find(x => x.id === id); if (!s) return; currentDetail = { type: 'music', id }; document.getElementById('dm-polaroid-title').textContent = s.name; document.getElementById('dm-polaroid-artist').textContent = s.artist || 'Unknown Artist'; const audio = document.getElementById('dm-audio'); const errBox = document.getElementById('dm-error-box'); const errLink = document.getElementById('dm-error-link'); errBox.style.display = 'none'; const finalUrl = parseAudioUrl(s.url); if(audio.src !== finalUrl && !audio.src.endsWith(encodeURI(finalUrl))) { audio.src = finalUrl; audio.load(); } audio.onerror = () => { errBox.style.display = 'block'; errLink.href = s.url; }; lrcLines = parseLrc(s.lrc || ''); renderLrc(); openDetail('detail-music'); } function parseLrc(text) { if (!text) return []; const lines = []; text.split('\n').forEach(line => { const m = line.match(/\[(\d+):(\d+)\.?(\d*)\](.*)/); if (m) { const time = parseInt(m[1])*60 + parseFloat(m[2]+'.'+( m[3]||'0')); lines.push({ time, text: m[4].trim() }); } }); return lines.sort((a,b) => a.time - b.time); } function renderLrc() { const box = document.getElementById('dm-lyrics'); if (!lrcLines.length) { box.innerHTML = '
暂无歌词 / No Lyrics
'; return; } box.innerHTML = lrcLines.map((l,i) => `
${escH(l.text)}
`).join(''); } function syncLrc() { const t = document.getElementById('dm-audio').currentTime; let cur = 0; for (let i = 0; i < lrcLines.length; i++) { if (lrcLines[i].time <= t) cur = i; } document.querySelectorAll('.lrc-line').forEach((el,i) => { el.classList.toggle('active', i === cur); if (i === cur) el.scrollIntoView({ block: 'center', behavior: 'smooth' }); }); } function startLrcSync() { lrcTimer = setInterval(syncLrc, 300); } function stopLrcSync() { clearInterval(lrcTimer); } function openNoteDetail(id) { const n = store.note.find(x => x.id === id); if (!n) return; currentDetail = { type: 'note', id }; document.getElementById('dn-title').textContent = n.name; const bodyEl = document.getElementById('dn-body'); bodyEl.textContent = n.body; if (n.fontUrl) { let link = document.getElementById('note-font-link'); if (!link) { link = document.createElement('link'); link.id='note-font-link'; link.rel='stylesheet'; document.head.appendChild(link); } link.href = n.fontUrl; } bodyEl.style.fontFamily = n.fontName ? `'${n.fontName}', serif` : 'inherit'; openDetail('detail-note'); } // 文件全屏预览与回退卡片 function openFileDetail(id) { const f = store.file.find(x => x.id === id); if (!f) return; currentDetail = { type: 'file', id }; document.getElementById('df-title').textContent = f.name; document.getElementById('df-meta').textContent = formatSize(f.size); const content = document.getElementById('df-content'); const ext = f.name.split('.').pop().toLowerCase(); if (['png','jpg','jpeg','gif','webp','svg'].includes(ext)) { content.innerHTML = ``; } else if (['mp4','webm','ogg'].includes(ext)) { content.innerHTML = ``; } else if (['mp3','wav','m4a'].includes(ext)) { content.innerHTML = ``; } else if (['pdf'].includes(ext)) { content.innerHTML = ``; } else if (['txt','json','js','css','html','md','csv'].includes(ext) || f.type.startsWith('text/')) { content.innerHTML = ``; } else { content.innerHTML = `
${fileIcon(f.name)}
${escH(f.name)}
因浏览器限制,不支持直接预览 ${ext.toUpperCase()} 格式文件
`; } openDetail('detail-file'); } window.triggerDownload = function(id) { const f = store.file.find(x => x.id === id); if (!f) return; const a = document.createElement('a'); a.href = f.data; a.download = f.name; a.click(); } function wrap(code) { return `${code}
`; } function escH(s) { return String(s).replace(/&/g,'&').replace(//g,'>'); } function escA(s) { return String(s).replace(/&/g,'&').replace(/"/g,'"'); } document.addEventListener('keydown', e => { if (e.key !== 'Escape') return; const modals = document.querySelectorAll('.modal-bd.open'); if(modals.length > 0) { modals.forEach(m => m.classList.remove('open')); currentEditId = null; return; } document.querySelectorAll('.detail-fs.open').forEach(d => { const id = d.id; if (id === 'detail-music') { stopLrcSync(); document.getElementById('dm-audio').pause(); } if (id === 'detail-widget') document.getElementById('dw-frame').srcdoc = ''; if (id === 'detail-file') document.getElementById('df-content').innerHTML = ''; d.classList.remove('open'); }); currentDetail = { type: null, id: null }; }); document.querySelectorAll('.modal-bd').forEach(bd => { bd.addEventListener('click', e => { if (e.target === bd) { bd.classList.remove('open'); currentEditId = null; } }); }); // ===== 导入正则 JSON (Mufy/Fox 格式) ===== function importRegexJson(input) { const file = input.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = e => { try { const data = JSON.parse(e.target.result); const rules = Array.isArray(data) ? data : [data]; let count = 0; rules.forEach(rule => { const name = rule.ruleName || rule.name || '导入正则'; let pattern = rule.regexPattern || rule.pattern || ''; let flags = 'gs'; const pm = pattern.match(/^\/(.+)\/([gimsuy]*)$/s); if (pm) { pattern = pm[1]; flags = pm[2] || 'gs'; } let replace = rule.replaceString || rule.replace || ''; replace = replace.replace(/^\s*```html\s*/, '').replace(/\s*```\s*$/, '').trim(); if (!pattern) return; store.regex.push({ id: 'rx' + Date.now() + count, name, pattern, flags, replace, cat: '' }); count++; }); persist(); renderSection('widget'); alert('成功导入 ' + count + ' 个正则组件!'); } catch(err) { alert('JSON 解析失败:' + err.message); } input.value = ''; }; reader.readAsText(file); } // ===== 导出全量数据 ===== function exportData() { const out = { version: 2, timestamp: new Date().toISOString(), ...store }; const blob = new Blob([JSON.stringify(out, null, 2)], { type: 'application/json' }); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = 'kura_backup_' + new Date().toISOString().slice(0,10) + '.json'; a.click(); } // ===== 导入全量数据 (合并模式,不覆盖) ===== function importData(input) { const file = input.files[0]; if (!file) return; if (!confirm('导入会合并到当前数据(相同 ID 跳过),确定继续吗?')) { input.value = ''; return; } const reader = new FileReader(); reader.onload = e => { try { const data = JSON.parse(e.target.result); ['widget','regex','image','music','note','file'].forEach(key => { if (!Array.isArray(data[key])) return; const existing = new Set(store[key].map(x => x.id)); data[key].forEach(item => { if (!existing.has(item.id)) store[key].push(item); }); }); if (data.subcats) { Object.keys(data.subcats).forEach(type => { if (!store.subcats[type]) store.subcats[type] = []; const existIds = new Set(store.subcats[type].map(c => c.id)); (data.subcats[type] || []).forEach(c => { if (!existIds.has(c.id)) store.subcats[type].push(c); }); }); } persist(); renderAll(); alert('导入成功!'); } catch(err) { alert('文件格式错误:' + err.message); } input.value = ''; }; reader.readAsText(file); } load();