2025-01-16 23:19:16 +08:00
|
|
|
import { musicDB } from '@/hooks/MusicHook';
|
2025-03-19 22:48:28 +08:00
|
|
|
import { useSettingsStore, useUserStore } from '@/store';
|
2025-01-12 20:59:36 +08:00
|
|
|
import type { ILyric } from '@/type/lyric';
|
2025-01-01 02:25:18 +08:00
|
|
|
import { isElectron } from '@/utils';
|
2024-05-16 18:54:30 +08:00
|
|
|
import request from '@/utils/request';
|
|
|
|
|
import requestMusic from '@/utils/request_music';
|
2025-04-22 23:39:08 +08:00
|
|
|
import { cloneDeep } from 'lodash';
|
2025-04-23 00:10:28 +08:00
|
|
|
import { parseFromGDMusic, getQualityMapping } from './gdmusic';
|
2025-01-06 20:54:42 +08:00
|
|
|
|
2025-01-16 23:19:16 +08:00
|
|
|
const { addData, getData, deleteData } = musicDB;
|
|
|
|
|
|
2025-01-06 20:54:42 +08:00
|
|
|
// 获取音乐音质详情
|
|
|
|
|
export const getMusicQualityDetail = (id: number) => {
|
|
|
|
|
return request.get('/song/music/detail', { params: { id } });
|
|
|
|
|
};
|
|
|
|
|
|
2024-05-16 18:54:30 +08:00
|
|
|
// 根据音乐Id获取音乐播放URl
|
2025-01-25 23:53:20 +08:00
|
|
|
export const getMusicUrl = async (id: number, isDownloaded: boolean = false) => {
|
2025-03-19 22:48:28 +08:00
|
|
|
const userStore = useUserStore();
|
|
|
|
|
const settingStore = useSettingsStore();
|
2025-01-25 21:49:22 +08:00
|
|
|
// 判断是否登录
|
2025-01-25 23:53:20 +08:00
|
|
|
try {
|
2025-03-19 22:48:28 +08:00
|
|
|
if (userStore.user && isDownloaded && userStore.user.vipType !== 0) {
|
2025-01-25 23:53:20 +08:00
|
|
|
const url = '/song/download/url/v1';
|
|
|
|
|
const res = await request.get(url, {
|
|
|
|
|
params: {
|
|
|
|
|
id,
|
2025-03-19 22:48:28 +08:00
|
|
|
level: settingStore.setData.musicQuality || 'higher',
|
2025-01-25 23:53:20 +08:00
|
|
|
cookie: `${localStorage.getItem('token')} os=pc;`
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (res.data.data.url) {
|
|
|
|
|
return { data: { data: [{ ...res.data.data }] } };
|
2025-01-25 21:49:22 +08:00
|
|
|
}
|
|
|
|
|
}
|
2025-01-25 23:53:20 +08:00
|
|
|
} catch (error) {
|
|
|
|
|
console.error('error', error);
|
2025-01-06 20:54:42 +08:00
|
|
|
}
|
|
|
|
|
|
2025-01-10 22:49:55 +08:00
|
|
|
return await request.get('/song/url/v1', {
|
|
|
|
|
params: {
|
|
|
|
|
id,
|
2025-03-19 22:48:28 +08:00
|
|
|
level: settingStore.setData.musicQuality || 'higher'
|
2025-01-10 22:49:55 +08:00
|
|
|
}
|
2025-01-06 20:54:42 +08:00
|
|
|
});
|
2024-05-16 18:54:30 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 获取歌曲详情
|
|
|
|
|
export const getMusicDetail = (ids: Array<number>) => {
|
|
|
|
|
return request.get('/song/detail', { params: { ids: ids.join(',') } });
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 根据音乐Id获取音乐歌词
|
2025-01-12 20:59:36 +08:00
|
|
|
export const getMusicLrc = async (id: number) => {
|
2025-01-16 23:19:16 +08:00
|
|
|
const TEN_DAYS_MS = 10 * 24 * 60 * 60 * 1000; // 10天的毫秒数
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// 尝试获取缓存的歌词
|
|
|
|
|
const cachedLyric = await getData('music_lyric', id);
|
|
|
|
|
if (cachedLyric?.createTime && Date.now() - cachedLyric.createTime < TEN_DAYS_MS) {
|
|
|
|
|
return { ...cachedLyric };
|
2025-01-12 20:59:36 +08:00
|
|
|
}
|
|
|
|
|
|
2025-01-16 23:19:16 +08:00
|
|
|
// 获取新的歌词数据
|
|
|
|
|
const res = await request.get<ILyric>('/lyric', { params: { id } });
|
2025-01-12 20:59:36 +08:00
|
|
|
|
2025-01-16 23:19:16 +08:00
|
|
|
// 只有在成功获取新数据后才删除旧缓存并添加新缓存
|
|
|
|
|
if (res?.data) {
|
|
|
|
|
if (cachedLyric) {
|
|
|
|
|
await deleteData('music_lyric', id);
|
|
|
|
|
}
|
|
|
|
|
addData('music_lyric', { id, data: res.data, createTime: Date.now() });
|
|
|
|
|
}
|
2025-01-12 20:59:36 +08:00
|
|
|
|
2025-01-16 23:19:16 +08:00
|
|
|
return res;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('获取歌词失败:', error);
|
|
|
|
|
throw error; // 向上抛出错误,让调用者处理
|
|
|
|
|
}
|
2024-05-16 18:54:30 +08:00
|
|
|
};
|
|
|
|
|
|
2025-04-23 00:10:28 +08:00
|
|
|
export const getParsingMusicUrl = async (id: number, data: any) => {
|
|
|
|
|
const settingStore = useSettingsStore();
|
2025-04-22 23:39:08 +08:00
|
|
|
|
2025-04-23 00:10:28 +08:00
|
|
|
// 如果禁用了音乐解析功能,则直接返回空结果
|
|
|
|
|
if (!settingStore.setData.enableMusicUnblock) {
|
|
|
|
|
return Promise.resolve({ data: { code: 404, message: '音乐解析功能已禁用' } });
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-11 15:09:56 +08:00
|
|
|
// 获取音源设置,优先使用歌曲自定义音源
|
|
|
|
|
const songId = String(id);
|
|
|
|
|
const savedSource = localStorage.getItem(`song_source_${songId}`);
|
|
|
|
|
let enabledSources: any[] = [];
|
|
|
|
|
|
|
|
|
|
// 如果有歌曲自定义音源,使用自定义音源
|
|
|
|
|
if (savedSource) {
|
|
|
|
|
try {
|
|
|
|
|
enabledSources = JSON.parse(savedSource);
|
|
|
|
|
console.log(`使用歌曲 ${id} 自定义音源:`, enabledSources);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error('解析自定义音源失败, 使用全局设置', e);
|
|
|
|
|
enabledSources = settingStore.setData.enabledMusicSources || [];
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// 没有自定义音源,使用全局音源设置
|
|
|
|
|
enabledSources = settingStore.setData.enabledMusicSources || [];
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-23 00:10:28 +08:00
|
|
|
// 检查是否选择了GD音乐台解析
|
|
|
|
|
if (enabledSources.includes('gdmusic')) {
|
|
|
|
|
// 获取音质设置并转换为GD音乐台格式
|
|
|
|
|
try {
|
|
|
|
|
const quality = getQualityMapping(settingStore.setData.musicQuality || 'higher');
|
|
|
|
|
|
|
|
|
|
// 调用封装的GD音乐台解析服务
|
|
|
|
|
const gdResult = await parseFromGDMusic(id, data, quality);
|
|
|
|
|
if (gdResult) {
|
|
|
|
|
return gdResult;
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('GD音乐台解析失败:', error);
|
2025-04-22 23:39:08 +08:00
|
|
|
}
|
2025-04-23 00:10:28 +08:00
|
|
|
|
|
|
|
|
console.log('GD音乐台所有音源均解析失败,尝试使用unblockMusic');
|
2025-01-01 02:25:18 +08:00
|
|
|
}
|
2025-04-23 00:10:28 +08:00
|
|
|
|
|
|
|
|
// 如果GD音乐台解析失败或者未启用,尝试使用unblockMusic
|
|
|
|
|
if (isElectron) {
|
|
|
|
|
const filteredSources = enabledSources.filter(source => source !== 'gdmusic');
|
|
|
|
|
return window.api.unblockMusic(id, cloneDeep(data), cloneDeep(filteredSources));
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-16 18:54:30 +08:00
|
|
|
return requestMusic.get<any>('/music', { params: { id } });
|
|
|
|
|
};
|
2025-01-04 16:58:08 +08:00
|
|
|
|
|
|
|
|
// 收藏歌曲
|
|
|
|
|
export const likeSong = (id: number, like: boolean = true) => {
|
|
|
|
|
return request.get('/like', { params: { id, like } });
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 获取用户喜欢的音乐列表
|
2025-01-25 23:53:20 +08:00
|
|
|
export const getLikedList = (uid: number) => {
|
|
|
|
|
return request.get('/likelist', {
|
2025-03-19 21:25:32 +08:00
|
|
|
params: { uid, noLogin: true }
|
2025-01-25 23:53:20 +08:00
|
|
|
});
|
2025-01-04 16:58:08 +08:00
|
|
|
};
|
2025-01-22 23:37:50 +08:00
|
|
|
|
|
|
|
|
// 创建歌单
|
|
|
|
|
export const createPlaylist = (params: { name: string; privacy: number }) => {
|
|
|
|
|
return request.post('/playlist/create', params);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 添加或删除歌单歌曲
|
|
|
|
|
export const updatePlaylistTracks = (params: {
|
|
|
|
|
op: 'add' | 'del';
|
|
|
|
|
pid: number;
|
|
|
|
|
tracks: string;
|
|
|
|
|
}) => {
|
2025-05-09 19:44:31 +08:00
|
|
|
return request.post('/playlist/tracks', params);
|
2025-01-22 23:37:50 +08:00
|
|
|
};
|
2025-05-07 22:36:52 +08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 根据类型获取列表数据
|
|
|
|
|
* @param type 列表类型 album/playlist
|
|
|
|
|
* @param id 列表ID
|
|
|
|
|
*/
|
|
|
|
|
export function getMusicListByType(type: string, id: string) {
|
|
|
|
|
if (type === 'album') {
|
|
|
|
|
return getAlbumDetail(id);
|
|
|
|
|
} else if (type === 'playlist') {
|
|
|
|
|
return getPlaylistDetail(id);
|
|
|
|
|
}
|
|
|
|
|
return Promise.reject(new Error('未知列表类型'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取专辑详情
|
|
|
|
|
* @param id 专辑ID
|
|
|
|
|
*/
|
|
|
|
|
export function getAlbumDetail(id: string) {
|
|
|
|
|
return request({
|
|
|
|
|
url: '/album',
|
|
|
|
|
method: 'get',
|
|
|
|
|
params: {
|
|
|
|
|
id
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取歌单详情
|
|
|
|
|
* @param id 歌单ID
|
|
|
|
|
*/
|
|
|
|
|
export function getPlaylistDetail(id: string) {
|
|
|
|
|
return request({
|
|
|
|
|
url: '/playlist/detail',
|
|
|
|
|
method: 'get',
|
|
|
|
|
params: {
|
|
|
|
|
id
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|