mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-05-17 10:27:30 +08:00
feat: 扩展数据层与播放能力
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
import { useLocalStorage } from '@vueuse/core';
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
import type { DjProgram } from '@/types/podcast';
|
||||
|
||||
export const usePodcastHistory = () => {
|
||||
const podcastHistory = useLocalStorage<DjProgram[]>('podcastHistory', []);
|
||||
|
||||
const addPodcast = (program: DjProgram) => {
|
||||
const index = podcastHistory.value.findIndex((item) => item.id === program.id);
|
||||
if (index !== -1) {
|
||||
podcastHistory.value.unshift(podcastHistory.value.splice(index, 1)[0]);
|
||||
} else {
|
||||
podcastHistory.value.unshift(program);
|
||||
}
|
||||
|
||||
if (podcastHistory.value.length > 100) {
|
||||
podcastHistory.value.pop();
|
||||
}
|
||||
};
|
||||
|
||||
const delPodcast = (program: DjProgram) => {
|
||||
const index = podcastHistory.value.findIndex((item) => item.id === program.id);
|
||||
if (index !== -1) {
|
||||
podcastHistory.value.splice(index, 1);
|
||||
}
|
||||
};
|
||||
|
||||
const clearPodcastHistory = () => {
|
||||
podcastHistory.value = [];
|
||||
};
|
||||
|
||||
const podcastList = ref(podcastHistory.value);
|
||||
|
||||
watch(
|
||||
() => podcastHistory.value,
|
||||
() => {
|
||||
podcastList.value = podcastHistory.value;
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
return {
|
||||
podcastHistory,
|
||||
podcastList,
|
||||
addPodcast,
|
||||
delPodcast,
|
||||
clearPodcastHistory
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,66 @@
|
||||
import { useLocalStorage } from '@vueuse/core';
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
export type PodcastRadioHistoryItem = {
|
||||
id: number;
|
||||
name: string;
|
||||
picUrl: string;
|
||||
desc?: string;
|
||||
dj?: {
|
||||
nickname: string;
|
||||
userId: number;
|
||||
};
|
||||
count?: number;
|
||||
lastPlayTime?: number;
|
||||
type?: string;
|
||||
};
|
||||
|
||||
export const usePodcastRadioHistory = () => {
|
||||
const podcastRadioHistory = useLocalStorage<PodcastRadioHistoryItem[]>('podcastRadioHistory', []);
|
||||
|
||||
const addPodcastRadio = (radio: PodcastRadioHistoryItem) => {
|
||||
const index = podcastRadioHistory.value.findIndex((item) => item.id === radio.id);
|
||||
const now = Date.now();
|
||||
|
||||
if (index !== -1) {
|
||||
const existing = podcastRadioHistory.value.splice(index, 1)[0];
|
||||
existing.count = (existing.count || 0) + 1;
|
||||
existing.lastPlayTime = now;
|
||||
podcastRadioHistory.value.unshift(existing);
|
||||
} else {
|
||||
podcastRadioHistory.value.unshift({
|
||||
...radio,
|
||||
count: 1,
|
||||
lastPlayTime: now
|
||||
});
|
||||
}
|
||||
|
||||
if (podcastRadioHistory.value.length > 100) {
|
||||
podcastRadioHistory.value.pop();
|
||||
}
|
||||
};
|
||||
|
||||
const delPodcastRadio = (radio: PodcastRadioHistoryItem) => {
|
||||
const index = podcastRadioHistory.value.findIndex((item) => item.id === radio.id);
|
||||
if (index !== -1) {
|
||||
podcastRadioHistory.value.splice(index, 1);
|
||||
}
|
||||
};
|
||||
|
||||
const podcastRadioList = ref(podcastRadioHistory.value);
|
||||
|
||||
watch(
|
||||
() => podcastRadioHistory.value,
|
||||
() => {
|
||||
podcastRadioList.value = podcastRadioHistory.value;
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
return {
|
||||
podcastRadioHistory,
|
||||
podcastRadioList,
|
||||
addPodcastRadio,
|
||||
delPodcastRadio
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,94 @@
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
const downloadList = ref<any[]>([]);
|
||||
const isInitialized = ref(false);
|
||||
|
||||
export const useDownloadStatus = () => {
|
||||
const router = useRouter();
|
||||
|
||||
const downloadingCount = computed(() => {
|
||||
return downloadList.value.filter((item) => item.status === 'downloading').length;
|
||||
});
|
||||
|
||||
const navigateToDownloads = () => {
|
||||
router.push('/downloads');
|
||||
};
|
||||
|
||||
const initDownloadListeners = () => {
|
||||
if (isInitialized.value) return;
|
||||
|
||||
if (!window.electron?.ipcRenderer) return;
|
||||
|
||||
window.electron.ipcRenderer.on('music-download-progress', (_, data) => {
|
||||
const existingItem = downloadList.value.find((item) => item.filename === data.filename);
|
||||
|
||||
if (data.progress === 100) {
|
||||
data.status = 'completed';
|
||||
}
|
||||
|
||||
if (existingItem) {
|
||||
Object.assign(existingItem, {
|
||||
...data,
|
||||
songInfo: data.songInfo || existingItem.songInfo
|
||||
});
|
||||
|
||||
if (data.status === 'completed') {
|
||||
downloadList.value = downloadList.value.filter((item) => item.filename !== data.filename);
|
||||
}
|
||||
} else {
|
||||
downloadList.value.push({
|
||||
...data,
|
||||
songInfo: data.songInfo
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
window.electron.ipcRenderer.on('music-download-complete', async (_, data) => {
|
||||
if (data.success) {
|
||||
downloadList.value = downloadList.value.filter((item) => item.filename !== data.filename);
|
||||
} else {
|
||||
const existingItem = downloadList.value.find((item) => item.filename === data.filename);
|
||||
if (existingItem) {
|
||||
Object.assign(existingItem, {
|
||||
status: 'error',
|
||||
error: data.error,
|
||||
progress: 0
|
||||
});
|
||||
setTimeout(() => {
|
||||
downloadList.value = downloadList.value.filter(
|
||||
(item) => item.filename !== data.filename
|
||||
);
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
window.electron.ipcRenderer.on('music-download-queued', (_, data) => {
|
||||
const existingItem = downloadList.value.find((item) => item.filename === data.filename);
|
||||
if (!existingItem) {
|
||||
downloadList.value.push({
|
||||
filename: data.filename,
|
||||
progress: 0,
|
||||
loaded: 0,
|
||||
total: 0,
|
||||
path: '',
|
||||
status: 'downloading',
|
||||
songInfo: data.songInfo
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
isInitialized.value = true;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
initDownloadListeners();
|
||||
});
|
||||
|
||||
return {
|
||||
downloadList,
|
||||
downloadingCount,
|
||||
navigateToDownloads
|
||||
};
|
||||
};
|
||||
@@ -2,7 +2,6 @@ import { cloneDeep } from 'lodash';
|
||||
import { createDiscreteApi } from 'naive-ui';
|
||||
|
||||
import i18n from '@/../i18n/renderer';
|
||||
import { getBilibiliAudioUrl } from '@/api/bilibili';
|
||||
import { getMusicLrc, getMusicUrl, getParsingMusicUrl } from '@/api/music';
|
||||
import { playbackRequestManager } from '@/services/playbackRequestManager';
|
||||
import { SongSourceConfigManager } from '@/services/SongSourceConfigManager';
|
||||
@@ -39,28 +38,6 @@ export const getSongUrl = async (
|
||||
return songData.playMusicUrl;
|
||||
}
|
||||
|
||||
if (songData.source === 'bilibili' && songData.bilibiliData) {
|
||||
console.log('加载B站音频URL');
|
||||
if (!songData.playMusicUrl && songData.bilibiliData.bvid && songData.bilibiliData.cid) {
|
||||
try {
|
||||
songData.playMusicUrl = await getBilibiliAudioUrl(
|
||||
songData.bilibiliData.bvid,
|
||||
songData.bilibiliData.cid
|
||||
);
|
||||
// 验证请求
|
||||
if (requestId && !playbackRequestManager.isRequestValid(requestId)) {
|
||||
console.log(`[getSongUrl] 获取B站URL后请求已失效: ${requestId}`);
|
||||
throw new Error('Request cancelled');
|
||||
}
|
||||
return songData.playMusicUrl;
|
||||
} catch (error) {
|
||||
console.error('重启后获取B站音频URL失败:', error);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
return songData.playMusicUrl || '';
|
||||
}
|
||||
|
||||
// ==================== 自定义API最优先 ====================
|
||||
const globalSources = settingsStore.setData.enabledMusicSources || [];
|
||||
const useCustomApiGlobally = globalSources.includes('custom');
|
||||
@@ -108,7 +85,7 @@ export const getSongUrl = async (
|
||||
}
|
||||
|
||||
// 如果有自定义音源设置,直接使用getParsingMusicUrl获取URL
|
||||
if (songConfig && songData.source !== 'bilibili') {
|
||||
if (songConfig) {
|
||||
try {
|
||||
console.log(`使用自定义音源解析歌曲 ID: ${id}`);
|
||||
const res = await getParsingMusicUrl(numericId, cloneDeep(songData));
|
||||
@@ -239,15 +216,6 @@ const parseLyrics = (lyricsString: string): { lyrics: ILyricText[]; times: numbe
|
||||
* 加载歌词(独立函数)
|
||||
*/
|
||||
export const loadLrc = async (id: string | number): Promise<ILyric> => {
|
||||
if (typeof id === 'string' && id.includes('--')) {
|
||||
console.log('B站音频,无需加载歌词');
|
||||
return {
|
||||
lrcTimeArray: [],
|
||||
lrcArray: [],
|
||||
hasWordByWord: false
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const numericId = typeof id === 'string' ? parseInt(id, 10) : id;
|
||||
const { data } = await getMusicLrc(numericId);
|
||||
@@ -346,30 +314,6 @@ export const useSongDetail = () => {
|
||||
throw new Error('Request cancelled');
|
||||
}
|
||||
|
||||
if (playMusic.source === 'bilibili') {
|
||||
try {
|
||||
if (!playMusic.playMusicUrl && playMusic.bilibiliData) {
|
||||
playMusic.playMusicUrl = await getBilibiliAudioUrl(
|
||||
playMusic.bilibiliData.bvid,
|
||||
playMusic.bilibiliData.cid
|
||||
);
|
||||
}
|
||||
|
||||
// 验证请求
|
||||
if (requestId && !playbackRequestManager.isRequestValid(requestId)) {
|
||||
console.log(`[getSongDetail] B站URL获取后请求已失效: ${requestId}`);
|
||||
throw new Error('Request cancelled');
|
||||
}
|
||||
|
||||
playMusic.playLoading = false;
|
||||
return { ...playMusic } as SongResult;
|
||||
} catch (error) {
|
||||
console.error('获取B站音频详情失败:', error);
|
||||
playMusic.playLoading = false;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
if (playMusic.expiredAt && playMusic.expiredAt < Date.now()) {
|
||||
console.info(`歌曲已过期,重新获取: ${playMusic.name}`);
|
||||
playMusic.playMusicUrl = undefined;
|
||||
|
||||
Reference in New Issue
Block a user