mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-04-03 14:20:50 +08:00
✨ feat: 优化打包和版本更新功能
This commit is contained in:
13
build/installer.nsh
Normal file
13
build/installer.nsh
Normal file
@@ -0,0 +1,13 @@
|
||||
# 设置 Windows 7 兼容性
|
||||
ManifestDPIAware true
|
||||
ManifestSupportedOS all
|
||||
|
||||
!macro customInit
|
||||
# 检查系统版本
|
||||
${If} ${AtLeastWin7}
|
||||
# Windows 7 或更高版本
|
||||
${Else}
|
||||
MessageBox MB_OK|MB_ICONSTOP "此应用程序需要 Windows 7 或更高版本。"
|
||||
Abort
|
||||
${EndIf}
|
||||
!macroend
|
||||
42
package.json
42
package.json
@@ -93,35 +93,47 @@
|
||||
"x64",
|
||||
"arm64"
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "zip",
|
||||
"arch": [
|
||||
"x64",
|
||||
"arm64"
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"artifactName": "${productName}-${version}-mac-${arch}.${ext}",
|
||||
"darkModeSupport": true
|
||||
},
|
||||
"win": {
|
||||
"icon": "resources/favicon.ico",
|
||||
"target": [
|
||||
"nsis",
|
||||
"zip"
|
||||
]
|
||||
{
|
||||
"target": "nsis",
|
||||
"arch": ["x64", "ia32"]
|
||||
}
|
||||
],
|
||||
"artifactName": "${productName}-${version}-win-${arch}.${ext}",
|
||||
"requestedExecutionLevel": "asInvoker"
|
||||
},
|
||||
"linux": {
|
||||
"icon": "resources/icon.png",
|
||||
"target": [
|
||||
"AppImage",
|
||||
"deb"
|
||||
]
|
||||
{
|
||||
"target": "AppImage",
|
||||
"arch": ["x64"]
|
||||
},
|
||||
{
|
||||
"target": "deb",
|
||||
"arch": ["x64"]
|
||||
}
|
||||
],
|
||||
"artifactName": "${productName}-${version}-linux-${arch}.${ext}",
|
||||
"category": "Audio",
|
||||
"maintainer": "Alger <algerkc@qq.com>"
|
||||
},
|
||||
"nsis": {
|
||||
"oneClick": false,
|
||||
"allowToChangeInstallationDirectory": true,
|
||||
"installerIcon": "resources/favicon.ico",
|
||||
"uninstallerIcon": "resources/favicon.ico"
|
||||
"uninstallerIcon": "resources/favicon.ico",
|
||||
"createDesktopShortcut": true,
|
||||
"createStartMenuShortcut": true,
|
||||
"shortcutName": "AlgerMusicPlayer",
|
||||
"include": "build/installer.nsh"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="update-info">
|
||||
<div class="update-title">更新内容:</div>
|
||||
<n-scrollbar style="max-height: 300px">
|
||||
<div class="update-body" v-html="parsedReleaseNotes"></div>
|
||||
</n-scrollbar>
|
||||
@@ -47,7 +46,7 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref, computed } from 'vue';
|
||||
import { marked } from 'marked';
|
||||
import { checkUpdate } from '@/utils';
|
||||
import { checkUpdate, UpdateResult } from '@/utils/update';
|
||||
import config from '../../../../package.json';
|
||||
|
||||
// 配置 marked
|
||||
@@ -56,23 +55,13 @@ marked.setOptions({
|
||||
gfm: true // 启用 GitHub 风格的 Markdown
|
||||
});
|
||||
|
||||
interface ReleaseInfo {
|
||||
tag_name: string;
|
||||
body?: string;
|
||||
html_url: string;
|
||||
assets: Array<{
|
||||
browser_download_url: string;
|
||||
name: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
const showModal = ref(false);
|
||||
const noPrompt = ref(false);
|
||||
const updateInfo = ref({
|
||||
const updateInfo = ref<UpdateResult>({
|
||||
hasUpdate: false,
|
||||
latestVersion: '',
|
||||
currentVersion: config.version,
|
||||
releaseInfo: null as ReleaseInfo | null
|
||||
releaseInfo: null
|
||||
});
|
||||
|
||||
// 解析 Markdown
|
||||
@@ -95,11 +84,12 @@ const closeModal = () => {
|
||||
|
||||
const checkForUpdates = async () => {
|
||||
try {
|
||||
const result = await checkUpdate();
|
||||
updateInfo.value = result;
|
||||
// 如果有更新且用户没有选择不再提示,则显示弹窗
|
||||
if (result.hasUpdate && localStorage.getItem('updatePromptDismissed') !== 'true') {
|
||||
showModal.value = true;
|
||||
const result = await checkUpdate(config.version);
|
||||
if (result) {
|
||||
updateInfo.value = result;
|
||||
if (localStorage.getItem('updatePromptDismissed') !== 'true') {
|
||||
showModal.value = true;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('检查更新失败:', error);
|
||||
@@ -107,28 +97,12 @@ const checkForUpdates = async () => {
|
||||
};
|
||||
|
||||
const handleUpdate = async () => {
|
||||
const { userAgent } = navigator;
|
||||
const isMac: boolean = userAgent.includes('Mac');
|
||||
const isWindows: boolean = userAgent.includes('Win');
|
||||
const isARM: boolean =
|
||||
userAgent.includes('ARM') || userAgent.includes('arm') || userAgent.includes('OS X');
|
||||
const isX64: boolean =
|
||||
userAgent.includes('x86_64') || userAgent.includes('Win64') || userAgent.includes('WOW64');
|
||||
const isX86: boolean =
|
||||
!isX64 &&
|
||||
(userAgent.includes('i686') || userAgent.includes('i386') || userAgent.includes('Win32'));
|
||||
|
||||
const getDownloadUrl = (os: string, arch: string): string => {
|
||||
const version = updateInfo.value.latestVersion;
|
||||
const setup = os !== 'mac' ? 'Setup_' : '';
|
||||
return `https://gh.llkk.cc/https://github.com/algerkong/AlgerMusicPlayer/releases/download/v${version}/AlgerMusic_${version}_${setup}${arch}.${os === 'mac' ? 'dmg' : 'exe'}`;
|
||||
};
|
||||
|
||||
const osType: string | null = isMac ? 'mac' : isWindows ? 'windows' : null;
|
||||
const archType: string | null = isARM ? 'arm64' : isX64 ? 'x64' : isX86 ? 'x86' : null;
|
||||
|
||||
const downloadUrl: string | null = osType && archType ? getDownloadUrl(osType, archType) : null;
|
||||
window.open(downloadUrl || 'https://github.com/algerkong/AlgerMusicPlayer/releases/latest', '_blank');
|
||||
const downloadUrl = updateInfo.value.releaseInfo?.assets[0]?.browser_download_url;
|
||||
if (downloadUrl) {
|
||||
window.open(downloadUrl, '_blank');
|
||||
} else {
|
||||
window.open('https://github.com/algerkong/AlgerMusicPlayer/releases/latest', '_blank');
|
||||
}
|
||||
closeModal();
|
||||
};
|
||||
|
||||
@@ -168,7 +142,7 @@ onMounted(() => {
|
||||
@apply text-base font-medium p-4 pb-2;
|
||||
}
|
||||
.update-body {
|
||||
@apply p-4 pt-2 text-gray-600 dark:text-gray-300;
|
||||
@apply p-4 pt-2 text-gray-600 dark:text-gray-300 rounded-lg overflow-hidden;
|
||||
|
||||
:deep(h1) {
|
||||
@apply text-xl font-bold mb-3;
|
||||
|
||||
@@ -102,7 +102,8 @@ import alipay from '@/assets/alipay.png';
|
||||
import wechat from '@/assets/wechat.png';
|
||||
import Coffee from '@/components/Coffee.vue';
|
||||
import { SEARCH_TYPES, USER_SET_OPTIONS } from '@/const/bar-const';
|
||||
import { getImgUrl, checkUpdate } from '@/utils';
|
||||
import { getImgUrl } from '@/utils';
|
||||
import { checkUpdate, UpdateResult } from '@/utils/update';
|
||||
|
||||
import config from '../../../../package.json';
|
||||
|
||||
@@ -212,7 +213,7 @@ const toGithub = () => {
|
||||
window.open('https://github.com/algerkong/AlgerMusicPlayer', '_blank');
|
||||
};
|
||||
|
||||
const updateInfo = ref({
|
||||
const updateInfo = ref<UpdateResult>({
|
||||
hasUpdate: false,
|
||||
latestVersion: '',
|
||||
currentVersion: config.version,
|
||||
@@ -221,8 +222,10 @@ const updateInfo = ref({
|
||||
|
||||
const checkForUpdates = async () => {
|
||||
try {
|
||||
const result = await checkUpdate();
|
||||
updateInfo.value = result;
|
||||
const result = await checkUpdate(config.version);
|
||||
if (result) {
|
||||
updateInfo.value = result;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('检查更新失败:', error);
|
||||
}
|
||||
@@ -230,7 +233,7 @@ const checkForUpdates = async () => {
|
||||
|
||||
const toGithubRelease = () => {
|
||||
if (updateInfo.value.hasUpdate) {
|
||||
window.open('https://github.com/algerkong/AlgerMusicPlayer/releases/latest', '_blank');
|
||||
window.open(updateInfo.value.releaseInfo?.html_url || 'https://github.com/algerkong/AlgerMusicPlayer/releases/latest', '_blank');
|
||||
} else {
|
||||
window.open('https://github.com/algerkong/AlgerMusicPlayer/releases', '_blank');
|
||||
}
|
||||
|
||||
@@ -100,45 +100,3 @@ export const isMobile = computed(() => {
|
||||
});
|
||||
|
||||
export const isElectron = (window as any).electron !== undefined;
|
||||
|
||||
/**
|
||||
* 检查版本更新
|
||||
* @returns {Promise<{hasUpdate: boolean, latestVersion: string, currentVersion: string}>}
|
||||
*/
|
||||
export const checkUpdate = async () => {
|
||||
try {
|
||||
const response = await axios.get('https://api.github.com/repos/algerkong/AlgerMusicPlayer/releases/latest');
|
||||
const latestVersion = response.data.tag_name.replace('v', '');
|
||||
const currentVersion = config.version;
|
||||
console.log(latestVersion, currentVersion);
|
||||
|
||||
// 版本号比较
|
||||
const latest = latestVersion.split('.').map(Number);
|
||||
const current = currentVersion.split('.').map(Number);
|
||||
|
||||
let hasUpdate = false;
|
||||
for (let i = 0; i < 3; i++) {
|
||||
if (latest[i] > current[i]) {
|
||||
hasUpdate = true;
|
||||
break;
|
||||
} else if (latest[i] < current[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
hasUpdate,
|
||||
latestVersion,
|
||||
currentVersion,
|
||||
releaseInfo: response.data
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('检查更新失败:', error);
|
||||
return {
|
||||
hasUpdate: false,
|
||||
latestVersion: '',
|
||||
currentVersion: config.version,
|
||||
releaseInfo: null
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
91
src/renderer/utils/update.ts
Normal file
91
src/renderer/utils/update.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import axios from 'axios';
|
||||
import config from '../../../package.json';
|
||||
import { useDateFormat } from '@vueuse/core';
|
||||
|
||||
interface GithubReleaseInfo {
|
||||
tag_name: string;
|
||||
body: string;
|
||||
published_at: string;
|
||||
html_url: string;
|
||||
assets: Array<{
|
||||
browser_download_url: string;
|
||||
name: string;
|
||||
size: number;
|
||||
}>;
|
||||
}
|
||||
|
||||
export interface UpdateResult {
|
||||
hasUpdate: boolean;
|
||||
latestVersion: string;
|
||||
currentVersion: string;
|
||||
releaseInfo: {
|
||||
tag_name: string;
|
||||
body: string;
|
||||
html_url: string;
|
||||
assets: Array<{
|
||||
browser_download_url: string;
|
||||
name: string;
|
||||
}>;
|
||||
} | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 GitHub 最新发布版本信息
|
||||
*/
|
||||
export const getLatestReleaseInfo = async (): Promise<GithubReleaseInfo | null> => {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
'https://api.github.com/repos/algerkong/AlgerMusicPlayer/releases/latest'
|
||||
);
|
||||
|
||||
if (response.data) {
|
||||
return response.data;
|
||||
}
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.error('获取 GitHub Release 信息失败:', error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 格式化时间
|
||||
*/
|
||||
const formatDate = (dateStr: string): string => {
|
||||
return useDateFormat(new Date(dateStr), 'YYYY-MM-DD HH:mm').value;
|
||||
};
|
||||
|
||||
/**
|
||||
* 检查更新
|
||||
*/
|
||||
export const checkUpdate = async (currentVersion: string = config.version): Promise<UpdateResult | null> => {
|
||||
try {
|
||||
const releaseInfo = await getLatestReleaseInfo();
|
||||
if (!releaseInfo) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const latestVersion = releaseInfo.tag_name.replace('v', '');
|
||||
if (latestVersion === currentVersion) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
hasUpdate: true,
|
||||
latestVersion,
|
||||
currentVersion,
|
||||
releaseInfo: {
|
||||
tag_name: latestVersion,
|
||||
body: `## 更新内容\n\n- 版本: ${latestVersion}\n- 发布时间: ${formatDate(releaseInfo.published_at)}\n\n${releaseInfo.body}`,
|
||||
html_url: releaseInfo.html_url,
|
||||
assets: releaseInfo.assets.map(asset => ({
|
||||
browser_download_url: asset.browser_download_url,
|
||||
name: asset.name
|
||||
}))
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('检查更新失败:', error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
@@ -109,13 +109,15 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, onMounted } from 'vue';
|
||||
import { useStore } from 'vuex';
|
||||
import { isElectron, checkUpdate } from '@/utils';
|
||||
import { useMessage } from 'naive-ui';
|
||||
import { isElectron } from '@/utils';
|
||||
import { checkUpdate, UpdateResult } from '@/utils/update';
|
||||
import config from '../../../../package.json';
|
||||
import PlayBottom from '@/components/common/PlayBottom.vue';
|
||||
|
||||
const store = useStore();
|
||||
const checking = ref(false);
|
||||
const updateInfo = ref({
|
||||
const updateInfo = ref<UpdateResult>({
|
||||
hasUpdate: false,
|
||||
latestVersion: '',
|
||||
currentVersion: config.version,
|
||||
@@ -144,18 +146,27 @@ const message = useMessage();
|
||||
const checkForUpdates = async (isClick = false) => {
|
||||
checking.value = true;
|
||||
try {
|
||||
const result = await checkUpdate();
|
||||
updateInfo.value = result;
|
||||
if (!result.hasUpdate && isClick) {
|
||||
const result = await checkUpdate(config.version);
|
||||
if (result) {
|
||||
updateInfo.value = result;
|
||||
if (!result.hasUpdate && isClick) {
|
||||
message.success('当前已是最新版本');
|
||||
}
|
||||
} else if (isClick) {
|
||||
message.success('当前已是最新版本');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('检查更新失败:', error);
|
||||
if (isClick) {
|
||||
message.error('检查更新失败,请稍后重试');
|
||||
}
|
||||
} finally {
|
||||
checking.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const openReleasePage = () => {
|
||||
window.open('https://github.com/algerkong/AlgerMusicPlayer/releases/latest');
|
||||
window.open(updateInfo.value.releaseInfo?.html_url || 'https://github.com/algerkong/AlgerMusicPlayer/releases/latest', '_blank');
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
Reference in New Issue
Block a user