Compare commits

..

16 Commits

Author SHA1 Message Date
db881da671 feat: 重构更新弹窗为智能版本检测系统
Some checks are pending
构建扩展程序 / 构建 Safari 扩展程序 (push) Waiting to run
构建扩展程序 / 构建 Chrome 扩展程序 (push) Successful in 1m7s
构建扩展程序 / 构建 Firefox 附加组件 (push) Successful in 58s
构建扩展程序 / 发布至 Chrome 应用商店 (push) Has been skipped
构建扩展程序 / 发布至 Edge 附加组件商店 (push) Has been skipped
构建扩展程序 / 发布至 Firefox 附加组件库 (push) Has been skipped
- 重命名 updated.vue 为 UpdatePopup.vue
- 新增 useUpdatePopup store 进行版本检测和存储管理
- 实现基于版本变化的智能弹窗显示逻辑
- 支持 Chrome storage API 和 localStorage 双重存储方案
- 添加弹窗关闭后的状态记录,避免重复显示
- 更新 App.vue 中的组件引用

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-25 12:56:59 +10:00
c0e26c0c80 feat: 更新弹窗添加 Safari 兼容性说明
- 添加 select-none 防止文本选择
- 更新说明内容,增加 Safari 兼容性支持描述

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-25 12:07:13 +10:00
195f3eced9 Merge branch 'dev' into feature/updated-popup 2025-06-25 12:05:07 +10:00
c262149d51 feat: 添加更新弹窗组件
- 在 App.vue 中引入并使用 Updated 组件
- 新增 src/components/updated.vue 组件文件

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-25 12:02:36 +10:00
38f37bba08
fix: 移除未使用的 props 变量声明
All checks were successful
构建扩展程序 / 构建 Chrome 扩展程序 (push) Successful in 1m15s
构建扩展程序 / 构建 Firefox 附加组件 (push) Successful in 1m30s
构建扩展程序 / 发布至 Chrome 应用商店 (push) Successful in 57s
构建扩展程序 / 发布至 Edge 附加组件商店 (push) Successful in 1m49s
构建扩展程序 / 发布至 Firefox 附加组件库 (push) Successful in 1m59s
修复 TypeScript 编译错误 TS6133

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-06 10:37:34 +10:00
fdd45f2c85
Merge branch 'prepare-release/v0.0.6'
Some checks failed
构建扩展程序 / 构建 Chrome 扩展程序 (push) Failing after 59s
构建扩展程序 / 发布至 Chrome 应用商店 (push) Has been skipped
构建扩展程序 / 发布至 Edge 附加组件商店 (push) Has been skipped
构建扩展程序 / 构建 Firefox 附加组件 (push) Failing after 49s
构建扩展程序 / 发布至 Firefox 附加组件库 (push) Has been skipped
2025-06-06 10:31:01 +10:00
33ed04bb35
chore: 发布 v0.0.6 版本
更新 manifest.json 版本号

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-06 10:26:19 +10:00
a3d82f12ec Merge pull request 'dev' (#9) from dev into main
Some checks failed
构建扩展程序 / 构建 Chrome 扩展程序 (push) Successful in 51s
构建扩展程序 / 构建 Firefox 附加组件 (push) Successful in 52s
构建扩展程序 / 发布至 Chrome 应用商店 (push) Successful in 36s
构建扩展程序 / 发布至 Edge 附加组件商店 (push) Failing after 48s
构建扩展程序 / 发布至 Firefox 附加组件库 (push) Failing after 16m2s
Reviewed-on: #9
2025-05-30 01:46:26 +00:00
6f7e161c0f Merge pull request 'fix: update song information in favourites when source URL changes' (#8) from dev into main
Some checks failed
构建扩展程序 / 构建 Chrome 扩展程序 (push) Successful in 54s
构建扩展程序 / 构建 Firefox 附加组件 (push) Successful in 55s
构建扩展程序 / 发布至 Chrome 应用商店 (push) Successful in 34s
构建扩展程序 / 发布至 Edge 附加组件商店 (push) Failing after 59s
构建扩展程序 / 发布至 Firefox 附加组件库 (push) Failing after 16m19s
Reviewed-on: #8
2025-05-30 00:36:01 +00:00
aaf58f03e1 Merge pull request 'dev' (#7) from dev into main
Some checks failed
构建扩展程序 / 构建 Chrome 扩展程序 (push) Successful in 55s
构建扩展程序 / 构建 Firefox 附加组件 (push) Successful in 59s
构建扩展程序 / 发布至 Chrome 应用商店 (push) Successful in 34s
构建扩展程序 / 发布至 Edge 附加组件商店 (push) Failing after 48s
构建扩展程序 / 发布至 Firefox 附加组件库 (push) Failing after 16m4s
Reviewed-on: #7
2025-05-29 05:58:05 +00:00
ba93f7db0b Merge pull request 'dev' (#6) from dev into main
Some checks failed
构建扩展程序 / 构建 Chrome 扩展程序 (push) Successful in 1m2s
构建扩展程序 / 构建 Firefox 附加组件 (push) Successful in 1m1s
构建扩展程序 / 发布至 Chrome 应用商店 (push) Successful in 36s
构建扩展程序 / 发布至 Edge 附加组件商店 (push) Failing after 48s
构建扩展程序 / 发布至 Firefox 附加组件库 (push) Has been cancelled
Reviewed-on: #6
2025-05-29 05:02:43 +00:00
49cc0676fc Merge pull request 'dev' (#5) from dev into main
Some checks failed
构建扩展程序 / 构建 Chrome 扩展程序 (push) Successful in 1m7s
构建扩展程序 / 构建 Firefox 附加组件 (push) Successful in 1m9s
构建扩展程序 / 发布至 Chrome 应用商店 (push) Failing after 36s
构建扩展程序 / 发布至 Edge 附加组件商店 (push) Failing after 55s
构建扩展程序 / 发布至 Firefox 附加组件库 (push) Failing after 1m5s
Reviewed-on: #5
2025-05-29 02:17:54 +00:00
3a1443db9c Merge pull request 'fix: correct artifact download path for Chrome extension publishing' (#4) from dev into main
Some checks failed
构建扩展程序 / 构建 Chrome 扩展程序 (push) Successful in 49s
构建扩展程序 / 构建 Firefox 附加组件 (push) Successful in 48s
构建扩展程序 / 发布至 Chrome 应用商店 (push) Failing after 28s
构建扩展程序 / 发布至 Firefox 附加组件库 (push) Failing after 1m2s
Reviewed-on: #4
2025-05-29 01:07:23 +00:00
592758ec6d Merge pull request 'fix: streamline artifact handling in workflow by removing ZIP compression steps' (#3) from dev into main
Some checks failed
构建扩展程序 / 构建 Chrome 扩展程序 (push) Successful in 51s
构建扩展程序 / 构建 Firefox 附加组件 (push) Successful in 54s
构建扩展程序 / 发布至 Chrome 应用商店 (push) Failing after 17s
构建扩展程序 / 发布至 Firefox 附加组件库 (push) Failing after 1m1s
Reviewed-on: #3
2025-05-29 01:01:54 +00:00
c098e0c37f Merge pull request 'fix: add channel option for Firefox Add-ons publishing' (#2) from dev into main
Some checks failed
构建扩展程序 / 构建 Chrome 扩展程序 (push) Successful in 46s
构建扩展程序 / 构建 Firefox 附加组件 (push) Successful in 40s
构建扩展程序 / 发布至 Chrome 应用商店 (push) Failing after 28s
构建扩展程序 / 发布至 Firefox 附加组件库 (push) Failing after 34s
Reviewed-on: #2
2025-05-29 00:50:34 +00:00
e0533ce2e1 Merge pull request 'dev' (#1) from dev into main
Some checks failed
构建扩展程序 / 构建 Chrome 扩展程序 (push) Successful in 48s
构建扩展程序 / 构建 Firefox 附加组件 (push) Successful in 41s
构建扩展程序 / 发布至 Chrome 应用商店 (push) Failing after 27s
构建扩展程序 / 发布至 Firefox 附加组件库 (push) Failing after 37s
Reviewed-on: #1
2025-05-29 00:44:21 +00:00
4 changed files with 264 additions and 2 deletions

View File

@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "MSR Mod",
"version": "0.0.5",
"version": "0.0.6",
"description": "塞壬唱片Monster Siren Records官网的替代前端。",
"content_scripts": [
{

View File

@ -9,6 +9,8 @@ import LeftArrowIcon from './assets/icons/leftarrow.vue'
import CorgIcon from './assets/icons/corg.vue'
import { watch } from 'vue'
import UpdatePopup from './components/UpdatePopup.vue'
const presentPreferencePanel = ref(false)
const route = useRoute()
@ -21,6 +23,8 @@ watch(() => presentPreferencePanel, (value) => {
</script>
<template>
<UpdatePopup />
<div class="w-screen h-screen overflow-hidden bg-[#191919]">
<div class="flex flex-col w-full h-full overflow-y-auto">
<div class="py-8 px-4 md:px-8 w-screen bg-gradient-to-b from-[#00000080] to-transparent z-20 absolute top-0">
@ -77,4 +81,4 @@ watch(() => presentPreferencePanel, (value) => {
</div>
<PreferencePanel :present="presentPreferencePanel" @dismiss="presentPreferencePanel = false" />
</div>
</template>
</template>

View File

@ -0,0 +1,54 @@
<script lang="ts" setup>
import XIcon from '../assets/icons/x.vue'
import { ref, onMounted } from 'vue'
import { useUpdatePopup } from '../stores/useUpdatePopup'
const updatePopupStore = useUpdatePopup()
const showPopup = ref(false)
const version = updatePopupStore.getCurrentVersion()
//
const handleDismiss = async () => {
showPopup.value = false
//
await updatePopupStore.markUpdatePopupShown()
}
//
onMounted(async () => {
// store
if (!updatePopupStore.isLoaded) {
await updatePopupStore.initializeUpdatePopup()
}
//
const shouldShow = await updatePopupStore.shouldShowUpdatePopup()
showPopup.value = shouldShow
})
</script>
<template>
<div v-if="showPopup" class="absolute top-0 left-0 w-screen h-screen bg-neutral-700/30 flex justify-center items-center select-none z-50">
<div class="bg-neutral-900/80 shadow-[0_0_16px_0_rgba(0,0,0,0.5)] backdrop-blur-2xl border border-[#ffffff39] rounded-lg w-[60rem] h-3/4 relative overflow-y-auto text-white">
<div
class="flex justify-between items-center p-8 sticky top-0 bg-gradient-to-b from-neutral-900 to-neutral-900/0 z-10">
<div class="text-white text-2xl font-semibold">MSR Mod 已更新至 {{version}}</div>
<button
class="text-white w-9 h-9 bg-neutral-800/80 border border-[#ffffff39] rounded-full text-center backdrop-blur-3xl flex justify-center items-center transition-all duration-200 hover:bg-neutral-700/80"
@click="handleDismiss">
<XIcon :size="4" />
</button>
</div>
<div class="flex flex-col gap-4 mb-8 px-8 text-lg">
<p>MSR Mod 现在有两种渠道接收错误及意见反馈如果你对 MSR Mod 有任何的意见建议或是想要回报错误及体验困惑之处欢迎前往 <a href="https://github.com/Astrian/msr-mod/issues" target="_blank" class="underline">GitHub Issue</a> <a href="https://discord.gg/QQUfeb2gzH" target="_blank" class="underline">Discord 社群</a> 向我们反馈如果你的意见或错误回报被接受我们会将其放入 <a href="https://trello.com/b/Ju1TRXla" target="_blank" class="underline">Trello 看板</a> 中进行跟踪敬请留意</p>
<ul class="list-disc list-inside">
<li>新增版本更新提示对话框将在 MSR Mod 更新后首次启动显示</li>
<li>增强对 Apple Safari 浏览器的兼容性支持</li>
</ul>
</div>
</div>
</div>
</template>

View File

@ -0,0 +1,204 @@
import { defineStore } from "pinia"
import { ref } from "vue"
// 声明全局类型
declare global {
interface Window {
browser?: any
}
}
export const useUpdatePopup = defineStore('updatePopup', () => {
const isLoaded = ref(false)
const storageType = ref<'chrome' | 'localStorage' | 'memory'>('chrome')
// 获取当前版本号
const getCurrentVersion = (): string => {
try {
// 尝试从 Chrome 扩展 API 获取版本号
return chrome?.runtime?.getManifest?.()?.version || 'unknown'
} catch (error) {
return 'unknown'
}
}
// 检测可用的 API
const detectAvailableAPIs = () => {
// 检查原生 chrome API
try {
if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.sync) {
storageType.value = 'chrome'
return 'chrome'
}
} catch (error) {
// Silent fail
}
// 检查 window.chrome
try {
if (window.chrome && window.chrome.storage && window.chrome.storage.sync) {
storageType.value = 'chrome'
return 'chrome'
}
} catch (error) {
// Silent fail
}
// 检查 localStorage
try {
if (typeof localStorage !== 'undefined') {
localStorage.setItem('msr_test', 'test')
localStorage.removeItem('msr_test')
storageType.value = 'localStorage'
return 'localStorage'
}
} catch (error) {
// Silent fail
}
// 都不可用,使用内存存储
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?.sync || window.chrome?.storage?.sync
if (api) {
api.get({ [key]: defaultValue }, (result) => {
if (chrome.runtime.lastError) {
resolve(defaultValue)
} else {
resolve(result[key])
}
})
} else {
resolve(defaultValue)
}
})
case 'localStorage':
const stored = localStorage.getItem(`msr_${key}`)
const value = stored ? JSON.parse(stored) : defaultValue
return value
case 'memory':
default:
return defaultValue
}
} catch (error) {
return defaultValue
}
}
// 通用的设置存储值函数
const setStoredValue = async (key: string, value: any) => {
const type = storageType.value
try {
switch (type) {
case 'chrome':
return await new Promise<void>((resolve, reject) => {
const api = chrome?.storage?.sync || window.chrome?.storage?.sync
if (api) {
api.set({ [key]: value }, () => {
if (chrome.runtime.lastError) {
reject(new Error(chrome.runtime.lastError.message))
} else {
resolve()
}
})
} else {
reject(new Error('Chrome storage API 不可用'))
}
})
case 'localStorage':
localStorage.setItem(`msr_${key}`, JSON.stringify(value))
break
case 'memory':
// 内存存储(不持久化)
break
}
} catch (error) {
throw error
}
}
// 检查是否需要显示更新弹窗
const shouldShowUpdatePopup = async (): Promise<boolean> => {
try {
const currentVersion = getCurrentVersion()
// 如果无法获取当前版本,不显示弹窗
if (currentVersion === 'unknown') {
return false
}
// 获取上次显示弹窗的版本号
const lastShownVersion = await getStoredValue('lastUpdatePopupVersion', '')
// 如果版本号不同,需要显示弹窗并更新存储的版本号
if (lastShownVersion !== currentVersion) {
await setStoredValue('lastUpdatePopupVersion', currentVersion)
return true
}
return false
} catch (error) {
console.error('检查更新弹窗状态失败:', error)
return false
}
}
// 标记已显示过更新弹窗(手动关闭时调用)
const markUpdatePopupShown = async () => {
try {
const currentVersion = getCurrentVersion()
if (currentVersion !== 'unknown') {
await setStoredValue('lastUpdatePopupVersion', currentVersion)
}
} catch (error) {
console.error('标记更新弹窗已显示失败:', error)
}
}
// 获取当前存储的版本号
const getLastShownVersion = async (): Promise<string> => {
return await getStoredValue('lastUpdatePopupVersion', '')
}
// 异步初始化函数
const initializeUpdatePopup = async () => {
try {
// 初始化存储类型检测
detectAvailableAPIs()
isLoaded.value = true
} catch (error) {
console.error('初始化更新弹窗 store 失败:', error)
isLoaded.value = true
}
}
// 立即初始化
initializeUpdatePopup()
return {
isLoaded,
storageType,
getCurrentVersion,
shouldShowUpdatePopup,
markUpdatePopupShown,
getLastShownVersion,
initializeUpdatePopup,
getStoredValue,
setStoredValue
}
})