From 145a2d2dbb966f2e68a9e3a1946fa0e5423312cd Mon Sep 17 00:00:00 2001 From: Astrian Zheng Date: Mon, 26 May 2025 18:44:25 +1000 Subject: [PATCH] fix: storage / network permission issue --- package-lock.json | 36 ++++++ package.json | 1 + public/manifest.json | 8 +- src/components/ScrollingLyrics.vue | 1 + src/pages/Playroom.vue | 1 + src/stores/usePreferences.ts | 201 ++++++++++++++++++++++++++--- 6 files changed, 229 insertions(+), 19 deletions(-) diff --git a/package-lock.json b/package-lock.json index 97da531..eb5a86a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ }, "devDependencies": { "@biomejs/biome": "1.9.4", + "@types/chrome": "^0.0.323", "@types/node": "^22.15.21", "@types/webextension-polyfill": "^0.12.3", "@vitejs/plugin-vue": "^5.2.1", @@ -1232,12 +1233,47 @@ "vite": "^5.2.0 || ^6" } }, + "node_modules/@types/chrome": { + "version": "0.0.323", + "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.323.tgz", + "integrity": "sha512-ipiDwx41lmGeLnbiT6ENOayvWXdkqKqNwqDQWEuz6dujaX7slSkk1nbSt5Q5c6xnQ708+kuCFrC00VLltSbWVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/filesystem": "*", + "@types/har-format": "*" + } + }, "node_modules/@types/estree": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", "license": "MIT" }, + "node_modules/@types/filesystem": { + "version": "0.0.36", + "resolved": "https://registry.npmjs.org/@types/filesystem/-/filesystem-0.0.36.tgz", + "integrity": "sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/filewriter": "*" + } + }, + "node_modules/@types/filewriter": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/filewriter/-/filewriter-0.0.33.tgz", + "integrity": "sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/har-format": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@types/har-format/-/har-format-1.2.16.tgz", + "integrity": "sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { "version": "22.15.21", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.21.tgz", diff --git a/package.json b/package.json index ae3de31..f14ab95 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ }, "devDependencies": { "@biomejs/biome": "1.9.4", + "@types/chrome": "^0.0.323", "@types/node": "^22.15.21", "@types/webextension-polyfill": "^0.12.3", "@vitejs/plugin-vue": "^5.2.1", diff --git a/public/manifest.json b/public/manifest.json index 3ada09e..af0e735 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -17,7 +17,8 @@ "host_permissions": [ "https://monster-siren.hypergryph.com/*", "http://localhost:5173/*", - "https://res01.hycdn.cn/*" + "https://res01.hycdn.cn/*", + "https://web.hycdn.cn/*" ], "icons": { "16": "vite.svg", @@ -29,10 +30,11 @@ }, "permissions": [ "tabs", - "webRequest" + "webRequest", + "storage" ], "content_security_policy": { - "extension_pages": "default-src 'self'; script-src 'self' http://localhost:5173; style-src 'self' 'unsafe-inline'; connect-src 'self' ws://localhost:5173 https://monster-siren.hypergryph.com; img-src 'self' https://web.hycdn.cn; media-src 'self' https://res01.hycdn.cn;", + "extension_pages": "default-src 'self'; script-src 'self' http://localhost:5173; style-src 'self' 'unsafe-inline'; connect-src 'self' ws://localhost:5173 https://monster-siren.hypergryph.com https://web.hycdn.cn; img-src 'self' https://web.hycdn.cn; media-src 'self' https://res01.hycdn.cn;", "sandbox": "sandbox" } } \ No newline at end of file diff --git a/src/components/ScrollingLyrics.vue b/src/components/ScrollingLyrics.vue index ec65abf..6411b6e 100644 --- a/src/components/ScrollingLyrics.vue +++ b/src/components/ScrollingLyrics.vue @@ -511,6 +511,7 @@ watch(() => playQueueStore.currentTime, (time) => { // 监听歌词源变化 watch(() => props.lrcSrc, async (newSrc) => { + console.log('Loading new lyrics from:', newSrc) // 重置状态 currentLineIndex.value = -1 lineRefs.value = [] diff --git a/src/pages/Playroom.vue b/src/pages/Playroom.vue index d858fd3..dd5c2dc 100644 --- a/src/pages/Playroom.vue +++ b/src/pages/Playroom.vue @@ -41,6 +41,7 @@ const songInfo = useTemplateRef('songInfo') const playButton = useTemplateRef('playButton') const presentQueueListDialog = ref(false) +// const presentLyrics = ref(false) onMounted(async () => { Draggable.create(progressBarThumb.value, { diff --git a/src/stores/usePreferences.ts b/src/stores/usePreferences.ts index 7dbde17..d6ccd51 100644 --- a/src/stores/usePreferences.ts +++ b/src/stores/usePreferences.ts @@ -1,23 +1,164 @@ import { defineStore } from "pinia" import { ref, watch } from "vue" -import browser from 'webextension-polyfill' + +// 声明全局类型 +declare global { + interface Window { + browser?: any + } +} export const usePreferences = defineStore('preferences', () => { - const displayTimeLeft = ref(false) // 设置默认值 - const isLoaded = ref(false) // 添加加载状态 + const displayTimeLeft = ref(false) + const isLoaded = ref(false) + const storageType = ref<'chrome' | 'localStorage' | 'memory'>('chrome') + const debugInfo = ref([]) + + // 添加调试日志 + const addDebugInfo = (info: string) => { + debugInfo.value.push(`[${new Date().toISOString()}] ${info}`) + console.log(info) + } + + // 检测可用的 API + const detectAvailableAPIs = () => { + addDebugInfo('开始检测可用的存储 API...') + + // 检查原生 chrome API + try { + if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.local) { + addDebugInfo('✅ 检测到 chrome.storage.local') + storageType.value = 'chrome' + return 'chrome' + } else { + addDebugInfo('❌ 未检测到原生 chrome.storage.local') + } + } catch (error) { + addDebugInfo(`❌ chrome API 检测失败: ${error}`) + } + + // 检查 window.chrome + try { + if (window.chrome && window.chrome.storage && window.chrome.storage.local) { + addDebugInfo('✅ 检测到 window.chrome.storage.local') + storageType.value = 'chrome' + return 'chrome' + } + } catch (error) { + addDebugInfo(`❌ window.chrome API 检测失败: ${error}`) + } + + // 检查 localStorage + try { + if (typeof localStorage !== 'undefined') { + localStorage.setItem('msr_test', 'test') + localStorage.removeItem('msr_test') + addDebugInfo('✅ 检测到 localStorage') + storageType.value = 'localStorage' + return 'localStorage' + } + } catch (error) { + addDebugInfo(`❌ localStorage 检测失败: ${error}`) + } + + // 都不可用,使用内存存储 + addDebugInfo('⚠️ 使用内存存储(不持久化)') + storageType.value = 'memory' + return 'memory' + } + + // 通用的获取存储值函数 + const getStoredValue = async (key: string, defaultValue: any) => { + const type = detectAvailableAPIs() + + try { + switch (type) { + case 'chrome': + return await new Promise((resolve) => { + const api = chrome?.storage?.local || window.chrome?.storage?.local + if (api) { + api.get({ [key]: defaultValue }, (result) => { + if (chrome.runtime.lastError) { + addDebugInfo(`Chrome storage 错误: ${chrome.runtime.lastError.message}`) + resolve(defaultValue) + } else { + addDebugInfo(`从 Chrome storage 读取: ${key} = ${result[key]}`) + resolve(result[key]) + } + }) + } else { + resolve(defaultValue) + } + }) + + case 'localStorage': + const stored = localStorage.getItem(`msr_${key}`) + const value = stored ? JSON.parse(stored) : defaultValue + addDebugInfo(`从 localStorage 读取: ${key} = ${value}`) + return value + + case 'memory': + default: + addDebugInfo(`从内存返回默认值: ${key} = ${defaultValue}`) + return defaultValue + } + } catch (error) { + addDebugInfo(`获取存储值失败 (${type}): ${error}`) + return defaultValue + } + } + + // 通用的设置存储值函数 + const setStoredValue = async (key: string, value: any) => { + const type = storageType.value + + try { + switch (type) { + case 'chrome': + return await new Promise((resolve, reject) => { + const api = chrome?.storage?.local || window.chrome?.storage?.local + if (api) { + api.set({ [key]: value }, () => { + if (chrome.runtime.lastError) { + const error = `Chrome storage 保存错误: ${chrome.runtime.lastError.message}` + addDebugInfo(error) + reject(new Error(error)) + } else { + addDebugInfo(`保存到 Chrome storage: ${key} = ${value}`) + resolve() + } + }) + } else { + reject(new Error('Chrome storage API 不可用')) + } + }) + + case 'localStorage': + localStorage.setItem(`msr_${key}`, JSON.stringify(value)) + addDebugInfo(`保存到 localStorage: ${key} = ${value}`) + break + + case 'memory': + addDebugInfo(`内存存储(不持久化): ${key} = ${value}`) + break + } + } catch (error) { + addDebugInfo(`保存设置失败 (${type}): ${error}`) + throw error + } + } // 异步初始化函数 const initializePreferences = async () => { + addDebugInfo('开始初始化偏好设置...') + try { - // 指定默认值对象 - const result = await browser.storage.local.get({ - displayTimeLeft: false // 如果键不存在,使用这个默认值 - }) - - displayTimeLeft.value = result.displayTimeLeft as boolean // 现在类型是安全的 + const value = await getStoredValue('displayTimeLeft', false) + displayTimeLeft.value = value as boolean isLoaded.value = true + addDebugInfo(`✅ 偏好设置初始化完成: displayTimeLeft = ${value}`) } catch (error) { - console.error('加载偏好设置失败:', error) + addDebugInfo(`❌ 初始化失败: ${error}`) displayTimeLeft.value = false isLoaded.value = true } @@ -25,23 +166,51 @@ export const usePreferences = defineStore('preferences', () => { // 监听变化并保存 watch(displayTimeLeft, async (val) => { - if (isLoaded.value) { // 只有在初始化完成后才保存 + if (isLoaded.value) { try { - await browser.storage.local.set({ - displayTimeLeft: val - }) + await setStoredValue('displayTimeLeft', val) } catch (error) { - console.error('保存偏好设置失败:', error) + addDebugInfo(`❌ 监听器保存失败: ${error}`) } } }) + // 手动保存函数(用于调试) + const manualSave = async () => { + try { + await setStoredValue('displayTimeLeft', displayTimeLeft.value) + addDebugInfo(`✅ 手动保存成功`) + } catch (error) { + addDebugInfo(`❌ 手动保存失败: ${error}`) + } + } + + // 获取调试信息 + const getDebugInfo = () => { + return { + storageType: storageType.value, + isLoaded: isLoaded.value, + displayTimeLeft: displayTimeLeft.value, + logs: debugInfo.value, + chromeAvailable: typeof chrome !== 'undefined', + chromeStorageAvailable: !!(chrome?.storage?.local), + windowChromeAvailable: !!(window.chrome?.storage?.local), + localStorageAvailable: typeof localStorage !== 'undefined' + } + } + // 立即初始化 initializePreferences() return { displayTimeLeft, isLoaded, - initializePreferences + storageType, + debugInfo, + initializePreferences, + getStoredValue, + setStoredValue, + manualSave, + getDebugInfo } }) \ No newline at end of file