From 62c5fed2e9d87d1ef7a1deaa8bae2c98bebaaf92 Mon Sep 17 00:00:00 2001 From: ZF sun <34314687@qq.com> Date: Wed, 6 May 2026 17:39:00 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E5=AD=97=E5=B9=95=E6=A0=B7=E5=BC=8F):=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AD=97=E5=B9=95=E6=A0=B7=E5=BC=8F=E4=BF=9D?= =?UTF-8?q?=E5=AD=98=E4=B8=8E=E5=8A=A0=E8=BD=BD=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 实现字幕样式的本地存储功能,包括保存当前设置、加载已保存设置和应用默认设置。新增样式提示对话框让用户选择是否应用已保存样式,并完善透明背景色的处理逻辑。 --- frontend/scripts/main.js | 154 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 2 deletions(-) diff --git a/frontend/scripts/main.js b/frontend/scripts/main.js index b00b1c2..7de0ae3 100644 --- a/frontend/scripts/main.js +++ b/frontend/scripts/main.js @@ -601,6 +601,125 @@ function hexToRgba(hex, alpha) { return `rgba(${r}, ${g}, ${b}, ${alpha})`; } +const CAPTION_STYLE_KEY = 'captionStyleSettings'; + +function saveCaptionStyleToStorage() { + const styleData = { + containerBgColor: elements.containerBgColor.value, + containerBgOpacity: elements.containerBgOpacity.value, + containerBorderColor: elements.containerBorderColor.value, + containerBorderRadius: elements.containerBorderRadius.value, + containerPadding: elements.containerPadding.value, + tipFontSize: elements.tipFontSize.value, + tipFontWeight: elements.tipFontWeight.value, + tipColor: elements.tipColor.value, + tipLineHeight: elements.tipLineHeight.value, + tipBgColor: elements.tipBgColor.value, + tipBgOpacity: elements.tipBgOpacity.value, + tipBorderRadius: elements.tipBorderRadius.value, + tipPadding: elements.tipPadding.value, + messageFontSize: elements.messageFontSize.value, + messageFontWeight: elements.messageFontWeight.value, + messageColor: elements.messageColor.value, + messageLineHeight: elements.messageLineHeight.value, + messageBgColor: elements.messageBgColor.value, + messageBgOpacity: elements.messageBgOpacity.value, + messageBorderRadius: elements.messageBorderRadius.value, + messagePadding: elements.messagePadding.value, + hotTitleFontSize: elements.hotTitleFontSize.value, + hotTitleFontWeight: elements.hotTitleFontWeight.value, + hotTitleColor: elements.hotTitleColor.value, + hotTitleLineHeight: elements.hotTitleLineHeight.value, + hotTitleBgColor: elements.hotTitleBgColor.value, + hotTitleBgOpacity: elements.hotTitleBgOpacity.value, + hotTitleBorderRadius: elements.hotTitleBorderRadius.value, + hotTitlePadding: elements.hotTitlePadding.value, + hotIssuesFontSize: elements.hotIssuesFontSize.value, + hotIssuesFontWeight: elements.hotIssuesFontWeight.value, + hotIssuesColor: elements.hotIssuesColor.value, + hotIssuesLineHeight: elements.hotIssuesLineHeight.value, + hotIssuesBgColor: elements.hotIssuesBgColor.value, + hotIssuesBgOpacity: elements.hotIssuesBgOpacity.value, + hotIssuesBorderRadius: elements.hotIssuesBorderRadius.value, + hotIssuesPadding: elements.hotIssuesPadding.value + }; + localStorage.setItem(CAPTION_STYLE_KEY, JSON.stringify(styleData)); + logger.info('字幕样式已保存'); +} + +function loadCaptionStyleFromStorage() { + const savedData = localStorage.getItem(CAPTION_STYLE_KEY); + if (!savedData) return null; + try { + return JSON.parse(savedData); + } catch (e) { + logger.error('加载保存的字幕样式失败', e.message); + return null; + } +} + +function hasSavedCaptionStyle() { + return localStorage.getItem(CAPTION_STYLE_KEY) !== null; +} + +function applySavedCaptionStyle(savedData) { + if (savedData.containerBgColor) elements.containerBgColor.value = savedData.containerBgColor; + if (savedData.containerBgOpacity) elements.containerBgOpacity.value = savedData.containerBgOpacity; + if (savedData.containerBorderColor) elements.containerBorderColor.value = savedData.containerBorderColor; + if (savedData.containerBorderRadius) elements.containerBorderRadius.value = savedData.containerBorderRadius; + if (savedData.containerPadding) elements.containerPadding.value = savedData.containerPadding; + if (savedData.tipFontSize) elements.tipFontSize.value = savedData.tipFontSize; + if (savedData.tipFontWeight) elements.tipFontWeight.value = savedData.tipFontWeight; + if (savedData.tipColor) elements.tipColor.value = savedData.tipColor; + if (savedData.tipLineHeight) elements.tipLineHeight.value = savedData.tipLineHeight; + if (savedData.tipBgColor) elements.tipBgColor.value = savedData.tipBgColor; + if (savedData.tipBgOpacity) elements.tipBgOpacity.value = savedData.tipBgOpacity; + if (savedData.tipBorderRadius) elements.tipBorderRadius.value = savedData.tipBorderRadius; + if (savedData.tipPadding) elements.tipPadding.value = savedData.tipPadding; + if (savedData.messageFontSize) elements.messageFontSize.value = savedData.messageFontSize; + if (savedData.messageFontWeight) elements.messageFontWeight.value = savedData.messageFontWeight; + if (savedData.messageColor) elements.messageColor.value = savedData.messageColor; + if (savedData.messageLineHeight) elements.messageLineHeight.value = savedData.messageLineHeight; + if (savedData.messageBgColor) elements.messageBgColor.value = savedData.messageBgColor; + if (savedData.messageBgOpacity) elements.messageBgOpacity.value = savedData.messageBgOpacity; + if (savedData.messageBorderRadius) elements.messageBorderRadius.value = savedData.messageBorderRadius; + if (savedData.messagePadding) elements.messagePadding.value = savedData.messagePadding; + if (savedData.hotTitleFontSize) elements.hotTitleFontSize.value = savedData.hotTitleFontSize; + if (savedData.hotTitleFontWeight) elements.hotTitleFontWeight.value = savedData.hotTitleFontWeight; + if (savedData.hotTitleColor) elements.hotTitleColor.value = savedData.hotTitleColor; + if (savedData.hotTitleLineHeight) elements.hotTitleLineHeight.value = savedData.hotTitleLineHeight; + if (savedData.hotTitleBgColor) elements.hotTitleBgColor.value = savedData.hotTitleBgColor; + if (savedData.hotTitleBgOpacity) elements.hotTitleBgOpacity.value = savedData.hotTitleBgOpacity; + if (savedData.hotTitleBorderRadius) elements.hotTitleBorderRadius.value = savedData.hotTitleBorderRadius; + if (savedData.hotTitlePadding) elements.hotTitlePadding.value = savedData.hotTitlePadding; + if (savedData.hotIssuesFontSize) elements.hotIssuesFontSize.value = savedData.hotIssuesFontSize; + if (savedData.hotIssuesFontWeight) elements.hotIssuesFontWeight.value = savedData.hotIssuesFontWeight; + if (savedData.hotIssuesColor) elements.hotIssuesColor.value = savedData.hotIssuesColor; + if (savedData.hotIssuesLineHeight) elements.hotIssuesLineHeight.value = savedData.hotIssuesLineHeight; + if (savedData.hotIssuesBgColor) elements.hotIssuesBgColor.value = savedData.hotIssuesBgColor; + if (savedData.hotIssuesBgOpacity) elements.hotIssuesBgOpacity.value = savedData.hotIssuesBgOpacity; + if (savedData.hotIssuesBorderRadius) elements.hotIssuesBorderRadius.value = savedData.hotIssuesBorderRadius; + if (savedData.hotIssuesPadding) elements.hotIssuesPadding.value = savedData.hotIssuesPadding; + + document.querySelectorAll('#captionPanel input[type="range"]').forEach(slider => { + const valueSpan = slider.nextElementSibling; + if (valueSpan && valueSpan.classList.contains('range-value')) { + valueSpan.textContent = `${slider.value}%`; + } + }); +} + +function showCaptionStylePrompt(callback) { + const savedData = loadCaptionStyleFromStorage(); + if (!savedData) { + callback(false); + return; + } + + const confirmed = confirm('检测到已保存的字幕样式设置。\n\n点击"确定"应用保存的样式,\n点击"取消"使用全新默认设置。'); + callback(confirmed); +} + function loadCaptionStyleFromContainer() { const captionContainer = document.querySelector('.caption-container-hub'); if (!captionContainer) return; @@ -669,13 +788,18 @@ function loadCaptionStyleFromContainer() { } } - if (styles.backgroundColor && styles.backgroundColor !== 'transparent' && styles.backgroundColor !== 'rgba(0, 0, 0, 0)') { + if (styles.backgroundColor) { 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])); if (rgbaMatch[4]) { section.elements.bgOpacity.value = Math.round(parseFloat(rgbaMatch[4]) * 100); + } else { + section.elements.bgOpacity.value = 0; } + } else if (styles.backgroundColor === 'transparent' || styles.backgroundColor === 'rgba(0, 0, 0, 0)') { + section.elements.bgColor.value = '#000000'; + section.elements.bgOpacity.value = 0; } } @@ -831,6 +955,7 @@ function initCaptionDragAndResize(container) { let captionStyleObserver = null; let captionStyleApplied = false; +let captionStylePromptShown = false; function watchCaptionContainer() { const observer = new MutationObserver((mutations) => { @@ -947,6 +1072,7 @@ function bindEvents() { elements.getOnceCodeBtn.addEventListener('click', handleGetOnceCode); elements.applyCaptionStyleBtn.addEventListener('click', () => { applyCaptionStyle(); + saveCaptionStyleToStorage(); captionStyleApplied = true; watchCaptionContentChanges(); }); @@ -958,6 +1084,7 @@ function bindEvents() { valueSpan.textContent = `${e.target.value}%`; } updateSingleStyle(e.target.id); + saveCaptionStyleToStorage(); captionStyleApplied = true; watchCaptionContentChanges(); }); @@ -966,11 +1093,13 @@ function bindEvents() { document.querySelectorAll('#captionPanel input[type="number"], #captionPanel input[type="color"], #captionPanel select').forEach(input => { input.addEventListener('input', (e) => { updateSingleStyle(e.target.id); + saveCaptionStyleToStorage(); captionStyleApplied = true; watchCaptionContentChanges(); }); input.addEventListener('change', (e) => { updateSingleStyle(e.target.id); + saveCaptionStyleToStorage(); captionStyleApplied = true; watchCaptionContentChanges(); }); @@ -987,7 +1116,28 @@ function bindEvents() { elements.toggleConfigBtn.addEventListener('click', () => togglePanel('configPanel')); elements.toggleCaptionBtn.addEventListener('click', () => { togglePanel('captionPanel'); - loadCaptionStyleFromContainer(); + if (!captionStylePromptShown && hasSavedCaptionStyle()) { + captionStylePromptShown = true; + showCaptionStylePrompt((applySaved) => { + if (applySaved) { + const savedData = loadCaptionStyleFromStorage(); + if (savedData) { + applySavedCaptionStyle(savedData); + applyCaptionStyle(); + captionStyleApplied = true; + watchCaptionContentChanges(); + logger.info('已应用保存的字幕样式'); + } + } else { + loadCaptionStyleFromContainer(); + localStorage.removeItem(CAPTION_STYLE_KEY); + captionStyleApplied = false; + logger.info('已清除保存的字幕样式,使用全新默认设置'); + } + }); + } else { + loadCaptionStyleFromContainer(); + } }); elements.toggleLogBtn.addEventListener('click', () => togglePanel('logPanel')); elements.fullscreenBtn.addEventListener('click', toggleFullscreen);