diff --git a/backend/routes/update.js b/backend/routes/update.js new file mode 100644 index 0000000..2e7c0e7 --- /dev/null +++ b/backend/routes/update.js @@ -0,0 +1,120 @@ +const express = require('express'); +const axios = require('axios'); +const { defaultLogger } = require('../utils/logger'); +const packageInfo = require('../../package.json'); + +const router = express.Router(); +const logger = defaultLogger.child('UpdateRoute'); + +/** + * 获取当前版本信息 + */ +router.get('/current-version', (req, res) => { + try { + res.json({ + success: true, + data: { + version: packageInfo.version, + name: packageInfo.name, + description: packageInfo.description + } + }); + } catch (error) { + logger.error('获取当前版本失败', error); + res.status(500).json({ + success: false, + error: '获取当前版本失败', + message: error.message + }); + } +}); + +/** + * 检查最新版本 + */ +router.get('/check-latest', async (req, res) => { + try { + logger.info('检查最新版本...'); + + // 获取GitHub发行版信息 + const response = await axios.get('https://api.github.com/repos/kjqwer/pixiv-D/releases/latest', { + timeout: 10000, + headers: { + 'User-Agent': 'Pixiv-Manager-Update-Checker' + } + }); + + const latestRelease = response.data; + const currentVersion = packageInfo.version; + const latestVersion = latestRelease.tag_name.replace(/^v/, ''); // 移除v前缀 + + // 版本比较 + const hasUpdate = compareVersions(latestVersion, currentVersion) > 0; + + const result = { + current: currentVersion, + latest: latestVersion, + hasUpdate, + releaseInfo: { + name: latestRelease.name, + body: latestRelease.body, + publishedAt: latestRelease.published_at, + htmlUrl: latestRelease.html_url, + downloadUrl: latestRelease.assets.find(asset => + asset.name.includes('pixiv-manager-portable.rar') + )?.browser_download_url || latestRelease.html_url + } + }; + + logger.info(`版本检查完成: 当前版本 ${currentVersion}, 最新版本 ${latestVersion}, 有更新: ${hasUpdate}`); + + res.json({ + success: true, + data: result + }); + + } catch (error) { + logger.error('检查最新版本失败', error); + + // 如果是网络错误,返回友好的错误信息 + let errorMessage = '检查更新失败'; + if (error.code === 'ENOTFOUND' || error.code === 'ECONNREFUSED') { + errorMessage = '无法连接到GitHub,请检查网络连接'; + } else if (error.response?.status === 404) { + errorMessage = '未找到发行版信息'; + } else if (error.response?.status === 403) { + errorMessage = 'GitHub API访问限制,请稍后再试'; + } + + res.status(500).json({ + success: false, + error: errorMessage, + message: error.message + }); + } +}); + +/** + * 版本比较函数 + * @param {string} version1 版本1 + * @param {string} version2 版本2 + * @returns {number} 1: version1 > version2, 0: 相等, -1: version1 < version2 + */ +function compareVersions(version1, version2) { + const v1Parts = version1.split('.').map(Number); + const v2Parts = version2.split('.').map(Number); + + const maxLength = Math.max(v1Parts.length, v2Parts.length); + + for (let i = 0; i < maxLength; i++) { + const v1Part = v1Parts[i] || 0; + const v2Part = v2Parts[i] || 0; + + if (v1Part > v2Part) return 1; + if (v1Part < v2Part) return -1; + } + + return 0; +} + +module.exports = router; \ No newline at end of file diff --git a/backend/server.js b/backend/server.js index 428a2e8..b4411a6 100644 --- a/backend/server.js +++ b/backend/server.js @@ -15,6 +15,7 @@ const proxyRoutes = require('./routes/proxy'); const repositoryRoutes = require('./routes/repository'); const rankingRoutes = require('./routes/ranking'); const watchlistRoutes = require('./routes/watchlist'); +const updateRoutes = require('./routes/update'); // 导入中间件 - 临时注释掉来定位问题 const { errorHandler } = require('./middleware/errorHandler'); @@ -114,16 +115,7 @@ function customLogger(req, res, next) { default: methodIcon = '❓'; } - - // 格式化时间 - const now = new Date(); - const timeStr = now.toLocaleTimeString('zh-CN', { - hour12: false, - hour: '2-digit', - minute: '2-digit', - second: '2-digit', - }); - + // 输出日志 logger.info(`${statusIcon} ${methodIcon} ${method} ${url} ${statusCode} ${duration}ms`); @@ -227,6 +219,7 @@ class PixivServer { this.app.use('/api/repository', repositoryRoutes); // 仓库管理,不需要认证 this.app.use('/api/proxy', proxyRoutes); // 图片代理,不需要认证 this.app.use('/api/watchlist', authMiddleware, watchlistRoutes); // 待看名单,需要认证 + this.app.use('/api/update', updateRoutes); // 更新检查,不需要认证 // 404 处理 this.app.use((req, res) => { diff --git a/package.json b/package.json index 15dbd04..7e15f4b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pixiv-backend", - "version": "1.0.0", + "version": "1.0.4", "description": "Pixiv 下载浏览管理器", "main": "backend/start.js", "bin": "backend/start.js", diff --git a/ui/src/App.vue b/ui/src/App.vue index 300ec26..0591f5f 100644 --- a/ui/src/App.vue +++ b/ui/src/App.vue @@ -4,13 +4,16 @@ import { computed, onMounted } from 'vue' import { useRoute } from 'vue-router' import { useAuthStore } from '@/stores/auth' import { useDownloadStore } from '@/stores/download' +import { useUpdateStore } from '@/stores/update' import SettingsWidget from '@/components/common/SettingsWidget.vue' import DownloadProgressWidget from '@/components/common/DownloadProgressWidget.vue' import WatchlistWidget from '@/components/common/WatchlistWidget.vue' +import UpdateChecker from '@/components/common/UpdateChecker.vue' const route = useRoute() const authStore = useAuthStore() const downloadStore = useDownloadStore() +const updateStore = useUpdateStore() const isLoggedIn = computed(() => authStore.isLoggedIn) const username = computed(() => authStore.username) @@ -23,11 +26,16 @@ const showDownloadWidget = computed(() => { onMounted(async () => { await authStore.fetchLoginStatus() - // 如果已登录,初始化下载store + // 如果已登录,初始化下载store和检查更新 if (authStore.isLoggedIn) { await downloadStore.fetchTasks() // 启动定期刷新 downloadStore.startRefreshInterval() + + // 自动检查更新(静默) + setTimeout(() => { + updateStore.autoCheckUpdate() + }, 2000) // 延迟2秒,避免影响登录流程 } }) @@ -64,6 +72,9 @@ onMounted(async () => { 登录 + + + @@ -176,6 +187,7 @@ onMounted(async () => { .nav-auth { display: flex; align-items: center; + gap: 0.75rem; } .user-info { diff --git a/ui/src/components/common/UpdateChecker.vue b/ui/src/components/common/UpdateChecker.vue new file mode 100644 index 0000000..0d0620d --- /dev/null +++ b/ui/src/components/common/UpdateChecker.vue @@ -0,0 +1,631 @@ + + + + + \ No newline at end of file diff --git a/ui/src/components/common/WatchlistWidget.vue b/ui/src/components/common/WatchlistWidget.vue index 2815258..65b52c7 100644 --- a/ui/src/components/common/WatchlistWidget.vue +++ b/ui/src/components/common/WatchlistWidget.vue @@ -10,11 +10,19 @@ -