mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-04-14 14:50:50 +08:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ddb814da10 | ||
|
|
e266ea8ef8 | ||
|
|
a894954641 | ||
|
|
f640ab9969 | ||
|
|
9eb17fd978 | ||
|
|
020aca7384 | ||
|
|
fcc47dc0ff | ||
|
|
17ce268da6 | ||
|
|
43c64b1b43 | ||
|
|
11ced6b418 |
16
CHANGELOG.md
16
CHANGELOG.md
@@ -1,13 +1,11 @@
|
|||||||
# 更新日志
|
# 更新日志
|
||||||
|
|
||||||
## [v3.2.0] - 2024-01-04
|
## [v3.3.0] - 2024-01-04
|
||||||
|
|
||||||
### ✨ 新功能
|
### ✨ 新功能
|
||||||
- 添加代理功能和 realIP配置功能 解决内网访问问题 和 国外访问问题 (d7e94a3)
|
- 添加音质选择功能,优化灰色歌曲解析 (020aca7)
|
||||||
- 关闭应用的提示修改,可存储配置最小化或关闭 (46f8067)
|
- 收藏功能改为接口对接 与 网易云同步 (43c64b1)
|
||||||
- 解决检查更新请求失败问题 (cdb9524)
|
- 添加退出登录 (fcc47dc)
|
||||||
|
- 优化登录失效处理 (9eb17fd)
|
||||||
### 🐞 问题修复
|
- 修复未登录状态下的收藏问题 (17ce268)
|
||||||
- 修复歌词页面与底栏冲突问题(#26) (1dc7d0c)
|
- 优化更新检查和下载功能 (11ced6b)
|
||||||
- 修复搜索歌曲列表页面显示错误问题(#33) (1dc7d0c)
|
|
||||||
- 修复搜索类型切换没有重新加载搜索的问题(#25) (ba64631)
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "AlgerMusicPlayer",
|
"name": "AlgerMusicPlayer",
|
||||||
"version": "3.2.0",
|
"version": "3.3.0",
|
||||||
"description": "Alger Music Player",
|
"description": "Alger Music Player",
|
||||||
"author": "Alger <algerkc@qq.com>",
|
"author": "Alger <algerkc@qq.com>",
|
||||||
"main": "./out/main/index.js",
|
"main": "./out/main/index.js",
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ if (!fs.existsSync(path.resolve(os.tmpdir(), 'anonymous_token'))) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 处理解锁音乐请求
|
// 处理解锁音乐请求
|
||||||
ipcMain.handle('unblock-music', async (_, id) => {
|
ipcMain.handle('unblock-music', async (_, id, data) => {
|
||||||
return unblockMusic(id);
|
return unblockMusic(id, data);
|
||||||
});
|
});
|
||||||
|
|
||||||
import server from 'netease-cloud-music-api-alger/server';
|
import server from 'netease-cloud-music-api-alger/server';
|
||||||
|
|||||||
@@ -6,12 +6,13 @@
|
|||||||
"host": "127.0.0.1",
|
"host": "127.0.0.1",
|
||||||
"port": 7890
|
"port": 7890
|
||||||
},
|
},
|
||||||
"enableRealIP":false,
|
"enableRealIP": false,
|
||||||
"realIP":"",
|
"realIP": "",
|
||||||
"noAnimate": false,
|
"noAnimate": false,
|
||||||
"animationSpeed": 1,
|
"animationSpeed": 1,
|
||||||
"author": "Alger",
|
"author": "Alger",
|
||||||
"authorUrl": "https://github.com/algerkong",
|
"authorUrl": "https://github.com/algerkong",
|
||||||
"musicApiPort": 30488,
|
"musicApiPort": 30488,
|
||||||
"closeAction": "ask"
|
"closeAction": "ask",
|
||||||
|
"musicQuality": "higher"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import match from '@unblockneteasemusic/server';
|
import match from '@unblockneteasemusic/server';
|
||||||
|
|
||||||
const unblockMusic = async (id: any): Promise<any> => {
|
const unblockMusic = async (id: any, songData: any): Promise<any> => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
match(parseInt(id, 10), ['qq', 'migu', 'kugou', 'joox'])
|
match(parseInt(id, 10), ['qq', 'migu', 'kugou', 'joox'], songData)
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
resolve({
|
resolve({
|
||||||
data: {
|
data: {
|
||||||
|
|||||||
3
src/preload/index.d.ts
vendored
3
src/preload/index.d.ts
vendored
@@ -12,7 +12,8 @@ declare global {
|
|||||||
dragStart: (data: string) => void;
|
dragStart: (data: string) => void;
|
||||||
miniTray: () => void;
|
miniTray: () => void;
|
||||||
restart: () => void;
|
restart: () => void;
|
||||||
unblockMusic: (id: number) => Promise<any>;
|
unblockMusic: (id: number, data: any) => Promise<any>;
|
||||||
};
|
};
|
||||||
|
$message:any
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,10 +32,6 @@ onMounted(() => {
|
|||||||
'setMenus',
|
'setMenus',
|
||||||
homeRouter.filter((item) => item.meta.isMobile)
|
homeRouter.filter((item) => item.meta.isMobile)
|
||||||
);
|
);
|
||||||
console.log(
|
|
||||||
'qqq ',
|
|
||||||
homeRouter.filter((item) => item.meta.isMobile)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,11 +1,33 @@
|
|||||||
import { ILyric } from '@/type/lyric';
|
import { ILyric } from '@/type/lyric';
|
||||||
import { IPlayMusicUrl } from '@/type/music';
|
|
||||||
import { isElectron } from '@/utils';
|
import { isElectron } from '@/utils';
|
||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
import requestMusic from '@/utils/request_music';
|
import requestMusic from '@/utils/request_music';
|
||||||
|
import store from '@/store';
|
||||||
|
|
||||||
|
// 获取音乐音质详情
|
||||||
|
export const getMusicQualityDetail = (id: number) => {
|
||||||
|
return request.get('/song/music/detail', { params: { id } });
|
||||||
|
};
|
||||||
|
|
||||||
// 根据音乐Id获取音乐播放URl
|
// 根据音乐Id获取音乐播放URl
|
||||||
export const getMusicUrl = (id: number) => {
|
export const getMusicUrl = async (id: number) => {
|
||||||
return request.get<IPlayMusicUrl>('/song/url', { params: { id } });
|
const res = await request.get('/song/download/url/v1', {
|
||||||
|
params: {
|
||||||
|
id,
|
||||||
|
level: store.state.setData.musicQuality || 'higher'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.data.data.url) {
|
||||||
|
return {data:{ data:[{url:res.data.data.url}]}};
|
||||||
|
}
|
||||||
|
|
||||||
|
return await request.get('/song/url/v1', {
|
||||||
|
params: {
|
||||||
|
id,
|
||||||
|
level: store.state.setData.musicQuality || 'higher'
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取歌曲详情
|
// 获取歌曲详情
|
||||||
@@ -18,9 +40,19 @@ export const getMusicLrc = (id: number) => {
|
|||||||
return request.get<ILyric>('/lyric', { params: { id } });
|
return request.get<ILyric>('/lyric', { params: { id } });
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getParsingMusicUrl = (id: number) => {
|
export const getParsingMusicUrl = (id: number, data: any) => {
|
||||||
if (isElectron) {
|
if (isElectron) {
|
||||||
return window.api.unblockMusic(id);
|
return window.api.unblockMusic(id, data);
|
||||||
}
|
}
|
||||||
return requestMusic.get<any>('/music', { params: { id } });
|
return requestMusic.get<any>('/music', { params: { id } });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 收藏歌曲
|
||||||
|
export const likeSong = (id: number, like: boolean = true) => {
|
||||||
|
return request.get('/like', { params: { id, like } });
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取用户喜欢的音乐列表
|
||||||
|
export const getLikedList = () => {
|
||||||
|
return request.get('/likelist');
|
||||||
|
};
|
||||||
|
|||||||
@@ -38,11 +38,6 @@
|
|||||||
:step="0.1"
|
:step="0.1"
|
||||||
@update:value="handleProgressChange"
|
@update:value="handleProgressChange"
|
||||||
>
|
>
|
||||||
<template #rail>
|
|
||||||
<div class="progress-rail">
|
|
||||||
<div class="progress-buffer" :style="{ width: `${bufferedProgress}%` }"></div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</n-slider>
|
</n-slider>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -643,10 +638,44 @@ const isMobile = computed(() => store.state.isMobile);
|
|||||||
.custom-slider {
|
.custom-slider {
|
||||||
:deep(.n-slider) {
|
:deep(.n-slider) {
|
||||||
--n-rail-height: 4px;
|
--n-rail-height: 4px;
|
||||||
--n-rail-color: rgba(255, 255, 255, 0.2);
|
--n-rail-color: theme('colors.gray.200');
|
||||||
--n-fill-color: #10b981;
|
--n-rail-color-dark: theme('colors.gray.700');
|
||||||
|
--n-fill-color: theme('colors.green.500');
|
||||||
--n-handle-size: 12px;
|
--n-handle-size: 12px;
|
||||||
--n-handle-color: #10b981;
|
--n-handle-color: theme('colors.green.500');
|
||||||
|
|
||||||
|
&.n-slider--vertical {
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.n-slider-rail {
|
||||||
|
width: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.n-slider-rail {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.n-slider-handle {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.n-slider-rail {
|
||||||
|
@apply overflow-hidden transition-all duration-200;
|
||||||
|
@apply bg-gray-500 dark:bg-dark-300 bg-opacity-10 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.n-slider-handle {
|
||||||
|
@apply transition-all duration-200;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover .n-slider-handle {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="ml-4">
|
<div class="ml-4">
|
||||||
<div class="recommend-singer-item-info-name text-el">{{ item.name }}</div>
|
<div class="recommend-singer-item-info-name text-el">{{ item.name }}</div>
|
||||||
<div class="recommend-singer-item-info-name text-el">{{ item.name }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ import type { SongResult } from '@/type/music';
|
|||||||
import { getImgUrl, isElectron } from '@/utils';
|
import { getImgUrl, isElectron } from '@/utils';
|
||||||
import { getImageBackground } from '@/utils/linearColor';
|
import { getImageBackground } from '@/utils/linearColor';
|
||||||
import { getSongUrl } from '@/hooks/MusicListHook';
|
import { getSongUrl } from '@/hooks/MusicListHook';
|
||||||
|
import { cloneDeep } from 'lodash';
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
@@ -148,7 +149,7 @@ const downloadMusic = async () => {
|
|||||||
isDownloading.value = true;
|
isDownloading.value = true;
|
||||||
const loadingMessage = message.loading('正在下载中...', { duration: 0 });
|
const loadingMessage = message.loading('正在下载中...', { duration: 0 });
|
||||||
|
|
||||||
const url = await getSongUrl(props.item.id);
|
const url = await getSongUrl(props.item.id, cloneDeep(props.item));
|
||||||
if (!url) {
|
if (!url) {
|
||||||
loadingMessage.destroy();
|
loadingMessage.destroy();
|
||||||
message.error('获取音乐下载地址失败');
|
message.error('获取音乐下载地址失败');
|
||||||
|
|||||||
@@ -44,10 +44,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, ref, computed } from 'vue';
|
import { onMounted, ref, computed, watch } from 'vue';
|
||||||
import { marked } from 'marked';
|
import { marked } from 'marked';
|
||||||
import { checkUpdate, UpdateResult } from '@/utils/update';
|
import { checkUpdate, UpdateResult } from '@/utils/update';
|
||||||
import config from '../../../../package.json';
|
import config from '../../../../package.json';
|
||||||
|
import { useStore } from 'vuex';
|
||||||
|
|
||||||
// 配置 marked
|
// 配置 marked
|
||||||
marked.setOptions({
|
marked.setOptions({
|
||||||
@@ -64,6 +65,25 @@ const updateInfo = ref<UpdateResult>({
|
|||||||
releaseInfo: null
|
releaseInfo: null
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const store = useStore()
|
||||||
|
|
||||||
|
// 添加计算属性
|
||||||
|
const showUpdateModalState = computed({
|
||||||
|
get: () => store.state.showUpdateModal,
|
||||||
|
set: (val) => store.commit('setShowUpdateModal', val)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 替换原来的 watch
|
||||||
|
watch(showUpdateModalState, (newVal) => {
|
||||||
|
if (newVal) {
|
||||||
|
showModal.value = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(() => showModal.value, (newVal) => {
|
||||||
|
showUpdateModalState.value = newVal
|
||||||
|
})
|
||||||
|
|
||||||
// 解析 Markdown
|
// 解析 Markdown
|
||||||
const parsedReleaseNotes = computed(() => {
|
const parsedReleaseNotes = computed(() => {
|
||||||
if (!updateInfo.value.releaseInfo?.body) return '';
|
if (!updateInfo.value.releaseInfo?.body) return '';
|
||||||
@@ -96,12 +116,30 @@ const checkForUpdates = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const handleUpdate = async () => {
|
const handleUpdate = async () => {
|
||||||
|
|
||||||
const assets = updateInfo.value.releaseInfo?.assets || [];
|
const assets = updateInfo.value.releaseInfo?.assets || [];
|
||||||
const platform = window.electron.process.platform;
|
const platform = window.electron.process.platform;
|
||||||
const arch = window.electron.ipcRenderer.sendSync('get-arch');
|
const arch = window.electron.ipcRenderer.sendSync('get-arch');
|
||||||
console.log(arch);
|
console.log('arch',arch)
|
||||||
console.log(platform);
|
console.log('platform',platform)
|
||||||
|
const version = updateInfo.value.latestVersion
|
||||||
|
const downUrls = {
|
||||||
|
win32: {
|
||||||
|
all: `https://github.com/algerkong/AlgerMusicPlayer/releases/download/v${version}/AlgerMusicPlayer-${version}-win.exe`,
|
||||||
|
x64: `https://github.com/algerkong/AlgerMusicPlayer/releases/download/v${version}/AlgerMusicPlayer-${version}-win-x64.exe`,
|
||||||
|
ia32: `https://github.com/algerkong/AlgerMusicPlayer/releases/download/v${version}/AlgerMusicPlayer-${version}-win-ia32.exe`,
|
||||||
|
},
|
||||||
|
darwin: {
|
||||||
|
all: `https://github.com/algerkong/AlgerMusicPlayer/releases/download/v${version}AlgerMusicPlayer-${version}-mac-universal.dmg`,
|
||||||
|
},
|
||||||
|
linux: {
|
||||||
|
AppImage: `https://github.com/algerkong/AlgerMusicPlayer/releases/download/v${version}/AlgerMusicPlayer-${version}-linux-x64.AppImage`,
|
||||||
|
deb: `https://github.com/algerkong/AlgerMusicPlayer/releases/download/v${version}/AlgerMusicPlayer-${version}-linux-x64.deb`,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let downloadUrl = '';
|
let downloadUrl = '';
|
||||||
|
|
||||||
@@ -111,30 +149,29 @@ const handleUpdate = async () => {
|
|||||||
const macAsset = assets.find(asset =>
|
const macAsset = assets.find(asset =>
|
||||||
asset.name.includes('mac')
|
asset.name.includes('mac')
|
||||||
);
|
);
|
||||||
downloadUrl = macAsset?.browser_download_url || '';
|
downloadUrl = macAsset?.browser_download_url || downUrls.darwin.all || '';
|
||||||
} else if (platform === 'win32') {
|
} else if (platform === 'win32') {
|
||||||
// Windows
|
// Windows
|
||||||
const winAsset = assets.find(asset =>
|
const winAsset = assets.find(asset =>
|
||||||
asset.name.includes('win') &&
|
asset.name.includes('win') &&
|
||||||
(arch === 'x64' ? asset.name.includes('x64') : asset.name.includes('ia32'))
|
(arch === 'x64' ? asset.name.includes('x64') : asset.name.includes('ia32'))
|
||||||
);
|
);
|
||||||
downloadUrl = winAsset?.browser_download_url || '';
|
downloadUrl = winAsset?.browser_download_url || downUrls.win32[arch] || downUrls.win32.all || '';
|
||||||
} else if (platform === 'linux') {
|
} else if (platform === 'linux') {
|
||||||
// Linux
|
// Linux
|
||||||
const linuxAsset = assets.find(asset =>
|
const linuxAsset = assets.find(asset =>
|
||||||
(asset.name.endsWith('.AppImage') || asset.name.endsWith('.deb')) &&
|
(asset.name.endsWith('.AppImage') || asset.name.endsWith('.deb')) &&
|
||||||
asset.name.includes('x64')
|
asset.name.includes('x64')
|
||||||
);
|
);
|
||||||
downloadUrl = linuxAsset?.browser_download_url || '';
|
downloadUrl = linuxAsset?.browser_download_url || downUrls.linux[arch] || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (downloadUrl) {
|
if (downloadUrl) {
|
||||||
window.open(`https://ghproxy.cn/${downloadUrl}`, '_blank');
|
window.open(`https://www.ghproxy.cn/${downloadUrl}`, '_blank');
|
||||||
} else {
|
} else {
|
||||||
// 如果没有找到对应的安装包,跳转到 release 页面
|
// 如果没有找到对应的安装包,跳转到 release 页面
|
||||||
window.open('https://github.com/algerkong/AlgerMusicPlayer/releases/latest', '_blank');
|
window.open('https://github.com/algerkong/AlgerMusicPlayer/releases/latest', '_blank');
|
||||||
}
|
}
|
||||||
closeModal();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|||||||
@@ -4,31 +4,31 @@ import { getMusicLrc, getMusicUrl, getParsingMusicUrl } from '@/api/music';
|
|||||||
import { useMusicHistory } from '@/hooks/MusicHistoryHook';
|
import { useMusicHistory } from '@/hooks/MusicHistoryHook';
|
||||||
import { audioService } from '@/services/audioService';
|
import { audioService } from '@/services/audioService';
|
||||||
import type { ILyric, ILyricText, SongResult } from '@/type/music';
|
import type { ILyric, ILyricText, SongResult } from '@/type/music';
|
||||||
import { getImgUrl, getMusicProxyUrl } from '@/utils';
|
import { getImgUrl } from '@/utils';
|
||||||
import { getImageLinearBackground } from '@/utils/linearColor';
|
import { getImageLinearBackground } from '@/utils/linearColor';
|
||||||
|
import { cloneDeep } from 'lodash';
|
||||||
|
|
||||||
const musicHistory = useMusicHistory();
|
const musicHistory = useMusicHistory();
|
||||||
|
|
||||||
// 获取歌曲url
|
// 获取歌曲url
|
||||||
export const getSongUrl = async (id: number) => {
|
export const getSongUrl = async (id: number, songData: any) => {
|
||||||
const { data } = await getMusicUrl(id);
|
const { data } = await getMusicUrl(id);
|
||||||
let url = '';
|
let url = '';
|
||||||
try {
|
try {
|
||||||
if (data.data[0].freeTrialInfo || !data.data[0].url) {
|
if (data.data[0].freeTrialInfo || !data.data[0].url) {
|
||||||
const res = await getParsingMusicUrl(id);
|
const res = await getParsingMusicUrl(id, songData);
|
||||||
console.log('res', res);
|
|
||||||
url = res.data.data.url;
|
url = res.data.data.url;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('error', error);
|
console.error('error', error);
|
||||||
}
|
}
|
||||||
url = url || data.data[0].url;
|
url = url || data.data[0].url;
|
||||||
return getMusicProxyUrl(url);
|
return url;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getSongDetail = async (playMusic: SongResult) => {
|
const getSongDetail = async (playMusic: SongResult) => {
|
||||||
playMusic.playLoading = true;
|
playMusic.playLoading = true;
|
||||||
const playMusicUrl = await getSongUrl(playMusic.id);
|
const playMusicUrl = await getSongUrl(playMusic.id, cloneDeep(playMusic));
|
||||||
const { backgroundColor, primaryColor } =
|
const { backgroundColor, primaryColor } =
|
||||||
playMusic.backgroundColor && playMusic.primaryColor
|
playMusic.backgroundColor && playMusic.primaryColor
|
||||||
? playMusic
|
? playMusic
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
<play-bar v-if="isPlay" :style="isMobile && store.state.musicFull ? 'bottom: 0;' : ''" />
|
<play-bar v-if="isPlay" :style="isMobile && store.state.musicFull ? 'bottom: 0;' : ''" />
|
||||||
</div>
|
</div>
|
||||||
<install-app-modal v-if="!isElectron"></install-app-modal>
|
<install-app-modal v-if="!isElectron"></install-app-modal>
|
||||||
<update-modal />
|
<update-modal v-if="isElectron"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,10 @@
|
|||||||
<i class="iconfont ri-login-box-line"></i>
|
<i class="iconfont ri-login-box-line"></i>
|
||||||
<span>去登录</span>
|
<span>去登录</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="store.state.user" class="menu-item" @click="selectItem('logout')">
|
||||||
|
<i class="iconfont ri-logout-box-r-line"></i>
|
||||||
|
<span>退出登录</span>
|
||||||
|
</div>
|
||||||
<!-- 切换主题 -->
|
<!-- 切换主题 -->
|
||||||
<div class="menu-item" @click="selectItem('set')">
|
<div class="menu-item" @click="selectItem('set')">
|
||||||
<i class="iconfont ri-settings-3-line"></i>
|
<i class="iconfont ri-settings-3-line"></i>
|
||||||
@@ -195,8 +199,7 @@ const selectItem = async (key: string) => {
|
|||||||
switch (key) {
|
switch (key) {
|
||||||
case 'logout':
|
case 'logout':
|
||||||
logout().then(() => {
|
logout().then(() => {
|
||||||
store.state.user = null;
|
store.commit('logout');
|
||||||
localStorage.clear();
|
|
||||||
router.push('/login');
|
router.push('/login');
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
@@ -237,7 +240,7 @@ const checkForUpdates = async () => {
|
|||||||
|
|
||||||
const toGithubRelease = () => {
|
const toGithubRelease = () => {
|
||||||
if (updateInfo.value.hasUpdate) {
|
if (updateInfo.value.hasUpdate) {
|
||||||
window.open(updateInfo.value.releaseInfo?.html_url || 'https://github.com/algerkong/AlgerMusicPlayer/releases/latest', '_blank');
|
store.commit('setShowUpdateModal', true)
|
||||||
} else {
|
} else {
|
||||||
window.open('https://github.com/algerkong/AlgerMusicPlayer/releases', '_blank');
|
window.open('https://github.com/algerkong/AlgerMusicPlayer/releases', '_blank');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,15 +5,11 @@ import homeRouter from '@/router/home';
|
|||||||
import type { SongResult } from '@/type/music';
|
import type { SongResult } from '@/type/music';
|
||||||
import { applyTheme, getCurrentTheme, ThemeType } from '@/utils/theme';
|
import { applyTheme, getCurrentTheme, ThemeType } from '@/utils/theme';
|
||||||
import { isElectron } from '@/utils';
|
import { isElectron } from '@/utils';
|
||||||
|
import { likeSong, getLikedList } from '@/api/music';
|
||||||
|
import setData from '@/../main/set.json'
|
||||||
|
|
||||||
// 默认设置
|
// 默认设置
|
||||||
const defaultSettings = {
|
const defaultSettings = setData;
|
||||||
isProxy: false,
|
|
||||||
noAnimate: false,
|
|
||||||
animationSpeed: 1,
|
|
||||||
author: 'Alger',
|
|
||||||
authorUrl: 'https://github.com/algerkong'
|
|
||||||
};
|
|
||||||
|
|
||||||
function getLocalStorageItem<T>(key: string, defaultValue: T): T {
|
function getLocalStorageItem<T>(key: string, defaultValue: T): T {
|
||||||
const item = localStorage.getItem(key);
|
const item = localStorage.getItem(key);
|
||||||
@@ -38,6 +34,7 @@ interface State {
|
|||||||
playMode: number;
|
playMode: number;
|
||||||
theme: ThemeType;
|
theme: ThemeType;
|
||||||
musicFull: boolean;
|
musicFull: boolean;
|
||||||
|
showUpdateModal: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const state: State = {
|
const state: State = {
|
||||||
@@ -57,7 +54,8 @@ const state: State = {
|
|||||||
favoriteList: getLocalStorageItem('favoriteList', []),
|
favoriteList: getLocalStorageItem('favoriteList', []),
|
||||||
playMode: getLocalStorageItem('playMode', 0),
|
playMode: getLocalStorageItem('playMode', 0),
|
||||||
theme: getCurrentTheme(),
|
theme: getCurrentTheme(),
|
||||||
musicFull: false
|
musicFull: false,
|
||||||
|
showUpdateModal: false
|
||||||
};
|
};
|
||||||
|
|
||||||
const { handlePlayMusic, nextPlay, prevPlay } = useMusicListHook();
|
const { handlePlayMusic, nextPlay, prevPlay } = useMusicListHook();
|
||||||
@@ -100,15 +98,25 @@ const mutations = {
|
|||||||
localStorage.setItem('appSettings', JSON.stringify(setData));
|
localStorage.setItem('appSettings', JSON.stringify(setData));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addToFavorite(state: State, songId: number) {
|
async addToFavorite(state: State, songId: number) {
|
||||||
if (!state.favoriteList.includes(songId)) {
|
try {
|
||||||
state.favoriteList = [songId, ...state.favoriteList];
|
state.user && localStorage.getItem('token') && await likeSong(songId, true);
|
||||||
localStorage.setItem('favoriteList', JSON.stringify(state.favoriteList));
|
if (!state.favoriteList.includes(songId)) {
|
||||||
|
state.favoriteList = [songId, ...state.favoriteList];
|
||||||
|
localStorage.setItem('favoriteList', JSON.stringify(state.favoriteList));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('收藏歌曲失败:', error);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
removeFromFavorite(state: State, songId: number) {
|
async removeFromFavorite(state: State, songId: number) {
|
||||||
state.favoriteList = state.favoriteList.filter((id) => id !== songId);
|
try {
|
||||||
localStorage.setItem('favoriteList', JSON.stringify(state.favoriteList));
|
state.user && localStorage.getItem('token') && await likeSong(songId, false);
|
||||||
|
state.favoriteList = state.favoriteList.filter((id) => id !== songId);
|
||||||
|
localStorage.setItem('favoriteList', JSON.stringify(state.favoriteList));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('取消收藏歌曲失败:', error);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
togglePlayMode(state: State) {
|
togglePlayMode(state: State) {
|
||||||
state.playMode = (state.playMode + 1) % 3;
|
state.playMode = (state.playMode + 1) % 3;
|
||||||
@@ -117,13 +125,20 @@ const mutations = {
|
|||||||
toggleTheme(state: State) {
|
toggleTheme(state: State) {
|
||||||
state.theme = state.theme === 'dark' ? 'light' : 'dark';
|
state.theme = state.theme === 'dark' ? 'light' : 'dark';
|
||||||
applyTheme(state.theme);
|
applyTheme(state.theme);
|
||||||
|
},
|
||||||
|
setShowUpdateModal(state, value) {
|
||||||
|
state.showUpdateModal = value
|
||||||
|
},
|
||||||
|
logout(state: State) {
|
||||||
|
state.user = null;
|
||||||
|
localStorage.removeItem('user');
|
||||||
|
localStorage.removeItem('token');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
initializeSettings({ commit }: { commit: any }) {
|
initializeSettings({ commit }: { commit: any }) {
|
||||||
if (isElectron) {
|
if (isElectron) {
|
||||||
// const setData = (window as any).electron.ipcRenderer.getStoreValue('set');
|
|
||||||
const setData = window.electron.ipcRenderer.sendSync('get-store-value', 'set');
|
const setData = window.electron.ipcRenderer.sendSync('get-store-value', 'set');
|
||||||
commit('setSetData', setData || defaultSettings);
|
commit('setSetData', setData || defaultSettings);
|
||||||
} else {
|
} else {
|
||||||
@@ -140,6 +155,24 @@ const actions = {
|
|||||||
},
|
},
|
||||||
initializeTheme({ state }: { state: State }) {
|
initializeTheme({ state }: { state: State }) {
|
||||||
applyTheme(state.theme);
|
applyTheme(state.theme);
|
||||||
|
},
|
||||||
|
async initializeFavoriteList({ state }: { state: State }) {
|
||||||
|
try {
|
||||||
|
if(state.user && localStorage.getItem('token')){
|
||||||
|
const res = await getLikedList();
|
||||||
|
if (res.data?.ids) {
|
||||||
|
state.favoriteList = res.data.ids.reverse();
|
||||||
|
localStorage.setItem('favoriteList', JSON.stringify(state.favoriteList));
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
const localFavoriteList = localStorage.getItem('favoriteList');
|
||||||
|
if (localFavoriteList) {
|
||||||
|
state.favoriteList = JSON.parse(localFavoriteList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取收藏列表失败:', error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -54,34 +54,9 @@ export const formatNumber = (num: string | number) => {
|
|||||||
return num.toString();
|
return num.toString();
|
||||||
};
|
};
|
||||||
|
|
||||||
const windowData = window as any;
|
|
||||||
export const getIsMc = () => {
|
|
||||||
if (!windowData.electron) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const setData = window.electron.ipcRenderer.sendSync('get-store-value', 'set');
|
|
||||||
if (setData.isProxy) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
const ProxyUrl = import.meta.env.VITE_API_PROXY;
|
|
||||||
|
|
||||||
export const getMusicProxyUrl = (url: string) => {
|
|
||||||
if (!getIsMc()) {
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
const PUrl = url.split('').join('+');
|
|
||||||
return `${ProxyUrl}/mc?url=${PUrl}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getImgUrl = (url: string | undefined, size: string = '') => {
|
export const getImgUrl = (url: string | undefined, size: string = '') => {
|
||||||
const bdUrl = 'https://image.baidu.com/search/down?url=';
|
|
||||||
const imgUrl = `${url}?param=${size}`;
|
const imgUrl = `${url}?param=${size}`;
|
||||||
if (!getIsMc()) {
|
return imgUrl;
|
||||||
return imgUrl;
|
|
||||||
}
|
|
||||||
return `${bdUrl}${encodeURIComponent(imgUrl)}`;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isMobile = computed(() => {
|
export const isMobile = computed(() => {
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
import axios, { InternalAxiosRequestConfig } from 'axios';
|
import axios, { InternalAxiosRequestConfig } from 'axios';
|
||||||
import { isElectron } from '.';
|
import { isElectron } from '.';
|
||||||
|
import store from '@/store';
|
||||||
|
import { createDiscreteApi } from 'naive-ui'
|
||||||
|
|
||||||
|
|
||||||
|
const { notification } = createDiscreteApi(
|
||||||
|
['notification']
|
||||||
|
)
|
||||||
|
|
||||||
let setData: any = null;
|
let setData: any = null;
|
||||||
|
|
||||||
const getSetData = ()=>{
|
const getSetData = ()=>{
|
||||||
if (window.electron) {
|
if (window.electron) {
|
||||||
setData = window.electron.ipcRenderer.sendSync('get-store-value', 'set');
|
setData = window.electron.ipcRenderer.sendSync('get-store-value', 'set');
|
||||||
@@ -44,7 +50,9 @@ request.interceptors.request.use(
|
|||||||
};
|
};
|
||||||
const token = localStorage.getItem('token');
|
const token = localStorage.getItem('token');
|
||||||
if (token) {
|
if (token) {
|
||||||
config.params.cookie = token;
|
config.params.cookie = token + ' os=pc;';
|
||||||
|
}else{
|
||||||
|
config.params.cookie = 'os=pc;';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,6 +80,7 @@ request.interceptors.response.use(
|
|||||||
return response;
|
return response;
|
||||||
},
|
},
|
||||||
async (error) => {
|
async (error) => {
|
||||||
|
console.log('error',error)
|
||||||
const config = error.config as CustomAxiosRequestConfig;
|
const config = error.config as CustomAxiosRequestConfig;
|
||||||
|
|
||||||
// 如果没有配置,直接返回错误
|
// 如果没有配置,直接返回错误
|
||||||
@@ -79,6 +88,30 @@ request.interceptors.response.use(
|
|||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理 301 状态码
|
||||||
|
if (error.response?.status === 301) {
|
||||||
|
// 使用 store mutation 清除用户信息
|
||||||
|
store.commit('logout');
|
||||||
|
|
||||||
|
// 如果还可以重试,则重新发起请求
|
||||||
|
if (config.retryCount === undefined || config.retryCount < MAX_RETRIES) {
|
||||||
|
config.retryCount = (config.retryCount || 1) + 1;
|
||||||
|
console.log(`301 状态码,清除登录信息后重试第 ${config.retryCount} 次`);
|
||||||
|
notification.error({
|
||||||
|
content: '登录状态失效,请重新登录',
|
||||||
|
meta: '请重新登录',
|
||||||
|
duration: 2500,
|
||||||
|
keepAliveOnHover: true
|
||||||
|
})
|
||||||
|
|
||||||
|
// 延迟重试
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY));
|
||||||
|
|
||||||
|
// 重新发起请求
|
||||||
|
return request(config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 检查是否还可以重试
|
// 检查是否还可以重试
|
||||||
if (config.retryCount !== undefined && config.retryCount < MAX_RETRIES) {
|
if (config.retryCount !== undefined && config.retryCount < MAX_RETRIES) {
|
||||||
config.retryCount++;
|
config.retryCount++;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import config from '../../../package.json';
|
import config from '../../../package.json';
|
||||||
import { useDateFormat } from '@vueuse/core';
|
import { useDateFormat } from '@vueuse/core';
|
||||||
|
|
||||||
interface GithubReleaseInfo {
|
interface GithubReleaseInfo {
|
||||||
tag_name: string;
|
tag_name: string;
|
||||||
body: string;
|
body: string;
|
||||||
@@ -36,20 +35,41 @@ export const getLatestReleaseInfo = async (): Promise<GithubReleaseInfo | null>
|
|||||||
try {
|
try {
|
||||||
const token = import.meta.env.VITE_GITHUB_TOKEN;
|
const token = import.meta.env.VITE_GITHUB_TOKEN;
|
||||||
const headers = {};
|
const headers = {};
|
||||||
if (token) {
|
|
||||||
headers['Authorization'] = `token ${token}`;
|
|
||||||
}
|
|
||||||
const response = await axios.get(
|
|
||||||
'https://api.github.com/repos/algerkong/AlgerMusicPlayer/releases/latest',
|
|
||||||
{
|
|
||||||
headers
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (response.data) {
|
const apiUrls = [
|
||||||
return response.data;
|
// 原始地址
|
||||||
|
'https://api.github.com/repos/algerkong/AlgerMusicPlayer/releases/latest',
|
||||||
|
|
||||||
|
// 使用 ghproxy.com 代理
|
||||||
|
'https://www.ghproxy.cn/https://raw.githubusercontent.com/algerkong/AlgerMusicPlayer/dev_electron/package.json',
|
||||||
|
|
||||||
|
// 使用 gitee 镜像(如果有的话)
|
||||||
|
// 'https://gitee.com/api/v5/repos/[用户名]/AlgerMusicPlayer/releases/latest'
|
||||||
|
];
|
||||||
|
if (token) {
|
||||||
|
headers['Authorization'] = `token ${token}`;
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
|
for (const url of apiUrls) {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(url, { headers });
|
||||||
|
|
||||||
|
if (url.includes('package.json')) {
|
||||||
|
// 如果是 package.json,直接读取版本号
|
||||||
|
return {
|
||||||
|
tag_name: response.data.version,
|
||||||
|
body:(await axios.get('https://raw.githubusercontent.com/algerkong/AlgerMusicPlayer/dev_electron/CHANGELOG.md')).data,
|
||||||
|
html_url: 'https://github.com/algerkong/AlgerMusicPlayer/releases/latest',
|
||||||
|
assets: []
|
||||||
|
} as unknown as GithubReleaseInfo;
|
||||||
|
}
|
||||||
|
return response.data;
|
||||||
|
} catch (err) {
|
||||||
|
console.warn(`尝试访问 ${url} 失败:`, err);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error('所有 API 地址均无法访问');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取 GitHub Release 信息失败:', error);
|
console.error('获取 GitHub Release 信息失败:', error);
|
||||||
return null;
|
return null;
|
||||||
@@ -59,7 +79,7 @@ export const getLatestReleaseInfo = async (): Promise<GithubReleaseInfo | null>
|
|||||||
/**
|
/**
|
||||||
* 格式化时间
|
* 格式化时间
|
||||||
*/
|
*/
|
||||||
const formatDate = (dateStr: string): string => {
|
export const formatDate = (dateStr: string): string => {
|
||||||
return useDateFormat(new Date(dateStr), 'YYYY-MM-DD HH:mm').value;
|
return useDateFormat(new Date(dateStr), 'YYYY-MM-DD HH:mm').value;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -69,6 +89,7 @@ const formatDate = (dateStr: string): string => {
|
|||||||
export const checkUpdate = async (currentVersion: string = config.version): Promise<UpdateResult | null> => {
|
export const checkUpdate = async (currentVersion: string = config.version): Promise<UpdateResult | null> => {
|
||||||
try {
|
try {
|
||||||
const releaseInfo = await getLatestReleaseInfo();
|
const releaseInfo = await getLatestReleaseInfo();
|
||||||
|
console.log('releaseInfo',releaseInfo)
|
||||||
if (!releaseInfo) {
|
if (!releaseInfo) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -77,6 +98,8 @@ export const checkUpdate = async (currentVersion: string = config.version): Prom
|
|||||||
if (latestVersion === currentVersion) {
|
if (latestVersion === currentVersion) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
console.log('latestVersion',latestVersion)
|
||||||
|
console.log('currentVersion',currentVersion)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hasUpdate: true,
|
hasUpdate: true,
|
||||||
@@ -84,7 +107,7 @@ export const checkUpdate = async (currentVersion: string = config.version): Prom
|
|||||||
currentVersion,
|
currentVersion,
|
||||||
releaseInfo: {
|
releaseInfo: {
|
||||||
tag_name: latestVersion,
|
tag_name: latestVersion,
|
||||||
body: `## 更新内容\n\n- 版本: ${latestVersion}\n- 发布时间: ${formatDate(releaseInfo.published_at)}\n\n${releaseInfo.body}`,
|
body: `## 更新内容\n\n- 版本: ${latestVersion}\n${releaseInfo.body}`,
|
||||||
html_url: releaseInfo.html_url,
|
html_url: releaseInfo.html_url,
|
||||||
assets: releaseInfo.assets.map(asset => ({
|
assets: releaseInfo.assets.map(asset => ({
|
||||||
browser_download_url: asset.browser_download_url,
|
browser_download_url: asset.browser_download_url,
|
||||||
|
|||||||
@@ -64,10 +64,9 @@ const props = defineProps({
|
|||||||
|
|
||||||
// 获取当前页的收藏歌曲ID
|
// 获取当前页的收藏歌曲ID
|
||||||
const getCurrentPageIds = () => {
|
const getCurrentPageIds = () => {
|
||||||
const reversedList = [...favoriteList.value];
|
|
||||||
const startIndex = (currentPage.value - 1) * pageSize;
|
const startIndex = (currentPage.value - 1) * pageSize;
|
||||||
const endIndex = startIndex + pageSize;
|
const endIndex = startIndex + pageSize;
|
||||||
return reversedList.slice(startIndex, endIndex);
|
return favoriteList.value.slice(startIndex, endIndex);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取收藏歌曲详情
|
// 获取收藏歌曲详情
|
||||||
@@ -120,6 +119,7 @@ const handleScroll = (e: any) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
store.dispatch('initializeFavoriteList');
|
||||||
getFavoriteSongs();
|
getFavoriteSongs();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -112,6 +112,27 @@
|
|||||||
<n-button size="small" type="primary" @click="openAuthor"><i class="ri-github-line"></i>前往github</n-button>
|
<n-button size="small" type="primary" @click="openAuthor"><i class="ri-github-line"></i>前往github</n-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="set-item">
|
||||||
|
<div>
|
||||||
|
<div class="set-item-title">音质设置</div>
|
||||||
|
<div class="set-item-content">选择音乐播放音质(VIP)</div>
|
||||||
|
</div>
|
||||||
|
<n-select
|
||||||
|
v-model:value="setData.musicQuality"
|
||||||
|
:options="[
|
||||||
|
{ label: '标准', value: 'standard' },
|
||||||
|
{ label: '较高', value: 'higher' },
|
||||||
|
{ label: '极高', value: 'exhigh' },
|
||||||
|
{ label: '无损', value: 'lossless' },
|
||||||
|
{ label: 'Hi-Res', value: 'hires' },
|
||||||
|
{ label: '高清环绕声', value: 'jyeffect' },
|
||||||
|
{ label: '沉浸环绕声', value: 'sky' },
|
||||||
|
{ label: '杜比全景声', value: 'dolby' },
|
||||||
|
{ label: '超清母带', value: 'jymaster' }
|
||||||
|
]"
|
||||||
|
style="width: 160px"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div class="set-item" v-if="isElectron">
|
<div class="set-item" v-if="isElectron">
|
||||||
<div>
|
<div>
|
||||||
<div class="set-item-title">关闭行为</div>
|
<div class="set-item-title">关闭行为</div>
|
||||||
@@ -129,6 +150,7 @@
|
|||||||
style="width: 160px"
|
style="width: 160px"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="set-item" v-if="isElectron">
|
<div class="set-item" v-if="isElectron">
|
||||||
<div>
|
<div>
|
||||||
<div class="set-item-title">重启</div>
|
<div class="set-item-title">重启</div>
|
||||||
@@ -168,6 +190,7 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<PlayBottom/>
|
<PlayBottom/>
|
||||||
<n-modal
|
<n-modal
|
||||||
@@ -247,6 +270,10 @@ const setData = computed(() => {
|
|||||||
port: 7890
|
port: 7890
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// 确保音质设置存在
|
||||||
|
if (!data.musicQuality) {
|
||||||
|
data.musicQuality = 'higher';
|
||||||
|
}
|
||||||
return data;
|
return data;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -290,7 +317,7 @@ const checkForUpdates = async (isClick = false) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const openReleasePage = () => {
|
const openReleasePage = () => {
|
||||||
window.open(updateInfo.value.releaseInfo?.html_url || 'https://github.com/algerkong/AlgerMusicPlayer/releases/latest', '_blank');
|
store.commit('setShowUpdateModal', true)
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectDownloadPath = async () => {
|
const selectDownloadPath = async () => {
|
||||||
|
|||||||
@@ -89,7 +89,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref, watch, onBeforeUnmount } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { useStore } from 'vuex';
|
import { useStore } from 'vuex';
|
||||||
|
|
||||||
@@ -112,42 +112,58 @@ const userDetail = ref<IUserDetail>();
|
|||||||
const playList = ref<any[]>([]);
|
const playList = ref<any[]>([]);
|
||||||
const recordList = ref();
|
const recordList = ref();
|
||||||
const infoLoading = ref(false);
|
const infoLoading = ref(false);
|
||||||
|
const mounted = ref(true);
|
||||||
|
const isShowList = ref(false);
|
||||||
|
const list = ref<Playlist>();
|
||||||
|
const listLoading = ref(false);
|
||||||
|
|
||||||
const user = computed(() => store.state.user);
|
const user = computed(() => store.state.user);
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
mounted.value = false;
|
||||||
|
});
|
||||||
|
|
||||||
const loadPage = async () => {
|
const loadPage = async () => {
|
||||||
if (!user.value) {
|
if (!mounted.value || !user.value) return;
|
||||||
router.push('/login');
|
|
||||||
return;
|
try {
|
||||||
|
infoLoading.value = true;
|
||||||
|
|
||||||
|
const { data: userData } = await getUserDetail(user.value.userId);
|
||||||
|
if (!mounted.value) return;
|
||||||
|
userDetail.value = userData;
|
||||||
|
|
||||||
|
const { data: playlistData } = await getUserPlaylist(user.value.userId);
|
||||||
|
if (!mounted.value) return;
|
||||||
|
playList.value = playlistData.playlist;
|
||||||
|
|
||||||
|
const { data: recordData } = await getUserRecord(user.value.userId);
|
||||||
|
if (!mounted.value) return;
|
||||||
|
recordList.value = recordData.allData.map((item: any) => ({
|
||||||
|
...item,
|
||||||
|
...item.song,
|
||||||
|
picUrl: item.song.al.picUrl
|
||||||
|
}));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载用户页面失败:', error);
|
||||||
|
} finally {
|
||||||
|
if (mounted.value) {
|
||||||
|
infoLoading.value = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
infoLoading.value = true;
|
|
||||||
|
|
||||||
const { data: userData } = await getUserDetail(user.value.userId);
|
|
||||||
userDetail.value = userData;
|
|
||||||
|
|
||||||
const { data: playlistData } = await getUserPlaylist(user.value.userId);
|
|
||||||
playList.value = playlistData.playlist;
|
|
||||||
|
|
||||||
const { data: recordData } = await getUserRecord(user.value.userId);
|
|
||||||
recordList.value = recordData.allData.map((item: any) => ({
|
|
||||||
...item,
|
|
||||||
...item.song,
|
|
||||||
picUrl: item.song.al.picUrl
|
|
||||||
}));
|
|
||||||
infoLoading.value = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
onActivated(() => {
|
// 监听用户状态变化
|
||||||
if (!user.value) {
|
watch(() => store.state.user, (newUser) => {
|
||||||
|
if (!mounted.value) return;
|
||||||
|
|
||||||
|
if (!newUser) {
|
||||||
router.push('/login');
|
router.push('/login');
|
||||||
} else {
|
} else {
|
||||||
loadPage();
|
loadPage();
|
||||||
}
|
}
|
||||||
});
|
}, { immediate: true });
|
||||||
|
|
||||||
const isShowList = ref(false);
|
|
||||||
const list = ref<Playlist>();
|
|
||||||
const listLoading = ref(false);
|
|
||||||
// 展示歌单
|
// 展示歌单
|
||||||
const showPlaylist = async (id: number, name: string) => {
|
const showPlaylist = async (id: number, name: string) => {
|
||||||
isShowList.value = true;
|
isShowList.value = true;
|
||||||
|
|||||||
Reference in New Issue
Block a user