diff --git a/frontend/index.html b/frontend/index.html index 0a2361d..94a7565 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -77,7 +77,33 @@

📝 字幕样式设置

-
+
+ +
+

字幕容器 (container)

+
+ + +
+
+ + + 85% +
+
+ + +
+
+ + +
+
+ + +
+
+

提示文字 (tip)

@@ -100,6 +126,23 @@
+
+ + +
+
+ + + 60% +
+
+ + +
+
+ + +
@@ -124,6 +167,23 @@
+
+ + +
+
+ + + 60% +
+
+ + +
+
+ + +
@@ -148,6 +208,23 @@ +
+ + +
+
+ + + 60% +
+
+ + +
+
+ + +
@@ -172,6 +249,23 @@ +
+ + +
+
+ + + 60% +
+
+ + +
+
+ + +
diff --git a/frontend/scripts/main.js b/frontend/scripts/main.js index fe93edb..80ff213 100644 --- a/frontend/scripts/main.js +++ b/frontend/scripts/main.js @@ -60,25 +60,47 @@ const elements = { toggleLogBtn: document.getElementById('toggleLogBtn'), applyCaptionStyleBtn: document.getElementById('applyCaptionStyleBtn'), + containerBgColor: document.getElementById('containerBgColor'), + containerBgOpacity: document.getElementById('containerBgOpacity'), + containerBorderColor: document.getElementById('containerBorderColor'), + containerBorderRadius: document.getElementById('containerBorderRadius'), + containerPadding: document.getElementById('containerPadding'), + tipFontSize: document.getElementById('tipFontSize'), tipFontWeight: document.getElementById('tipFontWeight'), tipColor: document.getElementById('tipColor'), tipLineHeight: document.getElementById('tipLineHeight'), + tipBgColor: document.getElementById('tipBgColor'), + tipBgOpacity: document.getElementById('tipBgOpacity'), + tipBorderRadius: document.getElementById('tipBorderRadius'), + tipPadding: document.getElementById('tipPadding'), messageFontSize: document.getElementById('messageFontSize'), messageFontWeight: document.getElementById('messageFontWeight'), messageColor: document.getElementById('messageColor'), messageLineHeight: document.getElementById('messageLineHeight'), + messageBgColor: document.getElementById('messageBgColor'), + messageBgOpacity: document.getElementById('messageBgOpacity'), + messageBorderRadius: document.getElementById('messageBorderRadius'), + messagePadding: document.getElementById('messagePadding'), hotTitleFontSize: document.getElementById('hotTitleFontSize'), hotTitleFontWeight: document.getElementById('hotTitleFontWeight'), hotTitleColor: document.getElementById('hotTitleColor'), hotTitleLineHeight: document.getElementById('hotTitleLineHeight'), + hotTitleBgColor: document.getElementById('hotTitleBgColor'), + hotTitleBgOpacity: document.getElementById('hotTitleBgOpacity'), + hotTitleBorderRadius: document.getElementById('hotTitleBorderRadius'), + hotTitlePadding: document.getElementById('hotTitlePadding'), hotIssuesFontSize: document.getElementById('hotIssuesFontSize'), hotIssuesFontWeight: document.getElementById('hotIssuesFontWeight'), hotIssuesColor: document.getElementById('hotIssuesColor'), hotIssuesLineHeight: document.getElementById('hotIssuesLineHeight'), + hotIssuesBgColor: document.getElementById('hotIssuesBgColor'), + hotIssuesBgOpacity: document.getElementById('hotIssuesBgOpacity'), + hotIssuesBorderRadius: document.getElementById('hotIssuesBorderRadius'), + hotIssuesPadding: document.getElementById('hotIssuesPadding'), logLevel: document.getElementById('logLevel'), @@ -369,42 +391,165 @@ function applyCaptionStyle() { return; } - const tipEl = captionContainer.querySelector('.layout-hub-tip'); - const messageEl = captionContainer.querySelector('.layout-hub-message'); - const hotTitleEl = captionContainer.querySelector('.layout-hub-hot-title'); - const hotIssuesEl = captionContainer.querySelector('.layout-hub-hot-issues'); + captionContainer.style.backgroundColor = hexToRgba( + elements.containerBgColor.value, + elements.containerBgOpacity.value / 100 + ); + captionContainer.style.borderColor = elements.containerBorderColor.value; + captionContainer.style.borderRadius = `${elements.containerBorderRadius.value}px`; + captionContainer.style.padding = `${elements.containerPadding.value}px`; + const tipEl = captionContainer.querySelector('.layout-hub-tip'); if (tipEl) { tipEl.style.fontSize = `${elements.tipFontSize.value}px`; tipEl.style.fontWeight = elements.tipFontWeight.value; tipEl.style.color = elements.tipColor.value; tipEl.style.lineHeight = elements.tipLineHeight.value; + tipEl.style.backgroundColor = hexToRgba( + elements.tipBgColor.value, + elements.tipBgOpacity.value / 100 + ); + tipEl.style.borderRadius = `${elements.tipBorderRadius.value}px`; + tipEl.style.padding = `${elements.tipPadding.value}px`; } + const messageEl = captionContainer.querySelector('.layout-hub-message'); if (messageEl) { messageEl.style.fontSize = `${elements.messageFontSize.value}px`; messageEl.style.fontWeight = elements.messageFontWeight.value; messageEl.style.color = elements.messageColor.value; messageEl.style.lineHeight = elements.messageLineHeight.value; + messageEl.style.backgroundColor = hexToRgba( + elements.messageBgColor.value, + elements.messageBgOpacity.value / 100 + ); + messageEl.style.borderRadius = `${elements.messageBorderRadius.value}px`; + messageEl.style.padding = `${elements.messagePadding.value}px`; } + const hotTitleEl = captionContainer.querySelector('.layout-hub-hot-title'); if (hotTitleEl) { hotTitleEl.style.fontSize = `${elements.hotTitleFontSize.value}px`; hotTitleEl.style.fontWeight = elements.hotTitleFontWeight.value; hotTitleEl.style.color = elements.hotTitleColor.value; hotTitleEl.style.lineHeight = elements.hotTitleLineHeight.value; + hotTitleEl.style.backgroundColor = hexToRgba( + elements.hotTitleBgColor.value, + elements.hotTitleBgOpacity.value / 100 + ); + hotTitleEl.style.borderRadius = `${elements.hotTitleBorderRadius.value}px`; + hotTitleEl.style.padding = `${elements.hotTitlePadding.value}px`; } + const hotIssuesEl = captionContainer.querySelector('.layout-hub-hot-issues'); if (hotIssuesEl) { hotIssuesEl.style.fontSize = `${elements.hotIssuesFontSize.value}px`; hotIssuesEl.style.fontWeight = elements.hotIssuesFontWeight.value; hotIssuesEl.style.color = elements.hotIssuesColor.value; hotIssuesEl.style.lineHeight = elements.hotIssuesLineHeight.value; + hotIssuesEl.style.backgroundColor = hexToRgba( + elements.hotIssuesBgColor.value, + elements.hotIssuesBgOpacity.value / 100 + ); + hotIssuesEl.style.borderRadius = `${elements.hotIssuesBorderRadius.value}px`; + hotIssuesEl.style.padding = `${elements.hotIssuesPadding.value}px`; } logger.info('字幕样式已应用'); } +function hexToRgba(hex, alpha) { + const r = parseInt(hex.slice(1, 3), 16); + const g = parseInt(hex.slice(3, 5), 16); + const b = parseInt(hex.slice(5, 7), 16); + return `rgba(${r}, ${g}, ${b}, ${alpha})`; +} + +function loadCaptionStyleFromContainer() { + const captionContainer = document.querySelector('.caption-container-hub'); + if (!captionContainer) return; + + const containerStyles = window.getComputedStyle(captionContainer); + const containerBg = containerStyles.backgroundColor; + const containerBorder = containerStyles.borderColor; + const containerRadius = containerStyles.borderRadius; + const containerPad = containerStyles.padding; + + if (containerBg && containerBg !== 'transparent') { + const rgbaMatch = containerBg.match(/rgba?\((\d+),\s*(\d+),\s*(\d+),?\s*([\d.]*)\)/); + if (rgbaMatch) { + elements.containerBgColor.value = rgbToHex(parseInt(rgbaMatch[1]), parseInt(rgbaMatch[2]), parseInt(rgbaMatch[3])); + elements.containerBgOpacity.value = rgbaMatch[4] ? Math.round(parseFloat(rgbaMatch[4]) * 100) : 100; + } + } + + if (containerBorder && containerBorder !== 'transparent' && containerBorder !== 'rgba(0, 0, 0, 0)') { + const rgbaMatch = containerBorder.match(/rgba?\((\d+),\s*(\d+),\s*(\d+),?\s*([\d.]*)\)/); + if (rgbaMatch) { + elements.containerBorderColor.value = rgbToHex(parseInt(rgbaMatch[1]), parseInt(rgbaMatch[2]), parseInt(rgbaMatch[3])); + } + } + + elements.containerBorderRadius.value = parseInt(containerRadius) || 8; + elements.containerPadding.value = parseInt(containerPad) || 10; + + updateRangeValue(elements.containerBgOpacity); + + const sections = [ + { selector: '.layout-hub-tip', elements: { fontSize: elements.tipFontSize, fontWeight: elements.tipFontWeight, color: elements.tipColor, lineHeight: elements.tipLineHeight, bgColor: elements.tipBgColor, bgOpacity: elements.tipBgOpacity, borderRadius: elements.tipBorderRadius, padding: elements.tipPadding } }, + { selector: '.layout-hub-message', elements: { fontSize: elements.messageFontSize, fontWeight: elements.messageFontWeight, color: elements.messageColor, lineHeight: elements.messageLineHeight, bgColor: elements.messageBgColor, bgOpacity: elements.messageBgOpacity, borderRadius: elements.messageBorderRadius, padding: elements.messagePadding } }, + { selector: '.layout-hub-hot-title', elements: { fontSize: elements.hotTitleFontSize, fontWeight: elements.hotTitleFontWeight, color: elements.hotTitleColor, lineHeight: elements.hotTitleLineHeight, bgColor: elements.hotTitleBgColor, bgOpacity: elements.hotTitleBgOpacity, borderRadius: elements.hotTitleBorderRadius, padding: elements.hotTitlePadding } }, + { selector: '.layout-hub-hot-issues', elements: { fontSize: elements.hotIssuesFontSize, fontWeight: elements.hotIssuesFontWeight, color: elements.hotIssuesColor, lineHeight: elements.hotIssuesLineHeight, bgColor: elements.hotIssuesBgColor, bgOpacity: elements.hotIssuesBgOpacity, borderRadius: elements.hotIssuesBorderRadius, padding: elements.hotIssuesPadding } } + ]; + + sections.forEach(section => { + const el = captionContainer.querySelector(section.selector); + if (!el) return; + + const styles = window.getComputedStyle(el); + section.elements.fontSize.value = parseInt(styles.fontSize) || 14; + section.elements.fontWeight.value = styles.fontWeight === 'bold' ? 'bold' : 'normal'; + section.elements.color.value = parseColor(styles.color); + section.elements.lineHeight.value = parseFloat(styles.lineHeight) || 1.5; + + if (styles.backgroundColor && styles.backgroundColor !== 'transparent') { + const rgbaMatch = styles.backgroundColor.match(/rgba?\((\d+),\s*(\d+),\s*(\d+),?\s*([\d.]*)\)/); + if (rgbaMatch) { + section.elements.bgColor.value = rgbToHex(parseInt(rgbaMatch[1]), parseInt(rgbaMatch[2]), parseInt(rgbaMatch[3])); + section.elements.bgOpacity.value = rgbaMatch[4] ? Math.round(parseFloat(rgbaMatch[4]) * 100) : 100; + } + } + + section.elements.borderRadius.value = parseInt(styles.borderRadius) || 4; + section.elements.padding.value = parseInt(styles.padding) || 6; + + updateRangeValue(section.elements.bgOpacity); + }); + + logger.info('已从字幕容器加载样式'); +} + +function parseColor(colorStr) { + if (!colorStr) return '#ffffff'; + if (colorStr.startsWith('#')) return colorStr; + const rgbaMatch = colorStr.match(/rgba?\((\d+),\s*(\d+),\s*(\d+),?\s*([\d.]*)\)/); + if (rgbaMatch) { + return rgbToHex(parseInt(rgbaMatch[1]), parseInt(rgbaMatch[2]), parseInt(rgbaMatch[3])); + } + return '#ffffff'; +} + +function rgbToHex(r, g, b) { + return '#' + [r, g, b].map(x => x.toString(16).padStart(2, '0')).join(''); +} + +function updateRangeValue(rangeInput) { + const valueSpan = rangeInput.nextElementSibling; + if (valueSpan && valueSpan.classList.contains('range-value')) { + valueSpan.textContent = `${rangeInput.value}%`; + } +} + function initCaptionDragAndResize(container) { container.dataset.dragInitialized = 'true'; @@ -524,6 +669,7 @@ function watchCaptionContainer() { captionContainer.style.userSelect = 'none'; captionContainer.style.zIndex = '9999'; initCaptionDragAndResize(captionContainer); + loadCaptionStyleFromContainer(); } } } @@ -534,6 +680,10 @@ function watchCaptionContainer() { subtree: true }); + if (document.querySelector('.caption-container-hub')) { + setTimeout(loadCaptionStyleFromContainer, 100); + } + logger.info('已启动字幕容器监听'); } @@ -593,6 +743,15 @@ function bindEvents() { elements.getOnceCodeBtn.addEventListener('click', handleGetOnceCode); elements.applyCaptionStyleBtn.addEventListener('click', applyCaptionStyle); + document.querySelectorAll('input[type="range"]').forEach(slider => { + slider.addEventListener('input', (e) => { + const valueSpan = e.target.nextElementSibling; + if (valueSpan && valueSpan.classList.contains('range-value')) { + valueSpan.textContent = `${e.target.value}%`; + } + }); + }); + elements.clearLogBtn.addEventListener('click', clearLogs); elements.logLevel.addEventListener('change', () => { if (state.isInitialized) { @@ -602,7 +761,10 @@ function bindEvents() { }); elements.toggleConfigBtn.addEventListener('click', () => togglePanel('configPanel')); - elements.toggleCaptionBtn.addEventListener('click', () => togglePanel('captionPanel')); + elements.toggleCaptionBtn.addEventListener('click', () => { + togglePanel('captionPanel'); + loadCaptionStyleFromContainer(); + }); elements.toggleLogBtn.addEventListener('click', () => togglePanel('logPanel')); elements.fullscreenBtn.addEventListener('click', toggleFullscreen); diff --git a/frontend/styles/main.css b/frontend/styles/main.css index 1ddcc01..822b701 100644 --- a/frontend/styles/main.css +++ b/frontend/styles/main.css @@ -373,6 +373,32 @@ body { height: 32px; } +.caption-style-section input[type="range"] { + width: calc(100% - 50px); + height: 6px; + border-radius: 3px; + background: var(--bg-tertiary); + outline: none; + -webkit-appearance: none; + margin-right: 8px; +} + +.caption-style-section input[type="range"]::-webkit-slider-thumb { + -webkit-appearance: none; + width: 16px; + height: 16px; + border-radius: 50%; + background: var(--primary-color); + cursor: pointer; +} + +.caption-style-section .range-value { + font-size: 0.75rem; + color: var(--text-muted); + min-width: 35px; + display: inline-block; +} + /* ===== 日志面板 ===== */ .log-panel { bottom: calc(var(--spacing-xl) + 60px);