diff --git a/src/app/api/music/v2/history/route.ts b/src/app/api/music/v2/history/route.ts index 9170f62..68de61d 100644 --- a/src/app/api/music/v2/history/route.ts +++ b/src/app/api/music/v2/history/route.ts @@ -25,6 +25,8 @@ export async function GET(request: NextRequest) { if (!username) return unauthorized(); try { + // 注意:records 按“播放队列顺序”返回(createdAt ASC), + // 前端再基于 lastPlayedAt 定位当前播放项。 const records = await db.listMusicV2History(username); return NextResponse.json({ success: true, data: { records } }); } catch (error) { diff --git a/src/app/music/page.tsx b/src/app/music/page.tsx index bf47727..15cbb45 100644 --- a/src/app/music/page.tsx +++ b/src/app/music/page.tsx @@ -50,6 +50,7 @@ interface DbRecord { id: string; playProgressSec: number; durationSec: number; + createdAt: number; lastPlayedAt: number; name: string; artist: string; @@ -243,7 +244,13 @@ export default function MusicPage() { setResolvingCount((prev) => Math.max(0, prev - 1)); }; - const saveHistoryRecord = async (record: PlayRecord, song: Song, playTime: number, totalDuration: number) => { + const saveHistoryRecord = async ( + record: PlayRecord, + song: Song, + playTime: number, + totalDuration: number, + lastPlayedAt = Date.now() + ) => { await fetch('/api/music/v2/history', { method: 'POST', headers: { 'Content-Type': 'application/json' }, @@ -260,12 +267,24 @@ export default function MusicPage() { durationText: song.durationText, }, playProgressSec: playTime, - lastPlayedAt: Date.now(), + lastPlayedAt, lastQuality: quality, }), }); }; + const saveHistoryRecordSafely = ( + record: PlayRecord, + song: Song, + playTime = 0, + totalDuration = 0, + lastPlayedAt?: number + ) => { + saveHistoryRecord(record, song, playTime, totalDuration, lastPlayedAt).catch(err => { + console.error('保存播放记录到数据库失败:', err); + }); + }; + // 保存播放状态到 localStorage const savePlayState = () => { if (!currentSong) return; @@ -308,15 +327,17 @@ export default function MusicPage() { const history = await response.json(); const dbRecords = (history.data?.records || []) as DbRecord[]; - const sortedRecords: PlayRecord[] = dbRecords.map((record) => ({ + const queueRecords = dbRecords; + + const sortedRecords: PlayRecord[] = queueRecords.map((record) => ({ platform: record.source, id: record.songId, playTime: record.playProgressSec, duration: record.durationSec || 0, - timestamp: record.lastPlayedAt, + timestamp: record.createdAt || record.lastPlayedAt || 0, })); - const sortedSongs: Song[] = dbRecords.map((record) => ({ + const sortedSongs: Song[] = queueRecords.map((record) => ({ id: record.songId, name: record.name, artist: record.artist, @@ -351,12 +372,17 @@ export default function MusicPage() { if (sortedRecords.length > 0) { const proxyEnabled = getMusicProxyEnabled(); setMusicProxyEnabled(proxyEnabled); - const latestDbRecord = sortedRecords[0]; - const latestDbSong = sortedSongs[0]; + const latestIndex = queueRecords.reduce((bestIndex, record, index) => { + if (bestIndex < 0) return index; + return (record.lastPlayedAt || 0) > (queueRecords[bestIndex].lastPlayedAt || 0) ? index : bestIndex; + }, -1); + const activeIndex = latestIndex >= 0 ? latestIndex : 0; + const latestDbRecord = sortedRecords[activeIndex]; + const latestDbSong = sortedSongs[activeIndex]; // 使用数据库的歌曲信息 setCurrentSong(latestDbSong); - setPlaylistIndex(0); + setPlaylistIndex(activeIndex); setShowPlayer(true); // 从数据库恢复播放进度 @@ -646,6 +672,7 @@ export default function MusicPage() { setPlayRecords((prev) => [...prev, record]); setPlaylist((prev) => [...prev, { ...song, platform }]); + saveHistoryRecordSafely(record, { ...song, platform }, 0, song.duration || 0, 0); setToast({ message: '已加入稍后播放', type: 'success', @@ -941,7 +968,7 @@ export default function MusicPage() { platform: platform, id: song.id, playTime: 0, // 初始播放时间 - duration: 0, // 将在音频加载后更新 + duration: song.duration || 0, // 将在音频加载后更新 timestamp: Date.now(), }; @@ -973,6 +1000,8 @@ export default function MusicPage() { } }); + saveHistoryRecordSafely(record, { ...song, platform }, 0, song.duration || 0); + if (proxyEnabled) { const streamUrl = buildStreamUrl(song, platform, quality); setCurrentSongUrl(streamUrl); diff --git a/src/lib/d1.db.ts b/src/lib/d1.db.ts index 6f00e9a..efc3004 100644 --- a/src/lib/d1.db.ts +++ b/src/lib/d1.db.ts @@ -748,7 +748,8 @@ export class D1Storage implements IStorage { async listMusicV2History(userName: string): Promise { try { const results = await this.db - .prepare('SELECT * FROM music_v2_history WHERE username = ? ORDER BY last_played_at DESC') + // 按队列顺序返回;当前播放项由最大 last_played_at 决定 + .prepare('SELECT * FROM music_v2_history WHERE username = ? ORDER BY created_at ASC, last_played_at ASC') .bind(userName) .all(); @@ -785,7 +786,7 @@ export class D1Storage implements IStorage { username, song_id, source, songmid, name, artist, album, cover, duration_text, duration_sec, play_progress_sec, last_played_at, play_count, last_quality, created_at, updated_at ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(username, song_id) DO UPDATE SET source = excluded.source, songmid = excluded.songmid, diff --git a/src/lib/db.ts b/src/lib/db.ts index d1b9fc6..4f87cdd 100644 --- a/src/lib/db.ts +++ b/src/lib/db.ts @@ -273,6 +273,8 @@ export class DbManager { // Music V2 历史记录相关 async listMusicV2History(userName: string): Promise { if (typeof (this.storage as any).listMusicV2History === 'function') { + // 按播放队列顺序返回(createdAt ASC), + // 当前播放项由调用方基于 lastPlayedAt 决定。 return (this.storage as any).listMusicV2History(userName); } return []; diff --git a/src/lib/postgres.db.ts b/src/lib/postgres.db.ts index 4631287..4399a03 100644 --- a/src/lib/postgres.db.ts +++ b/src/lib/postgres.db.ts @@ -1403,7 +1403,8 @@ export class PostgresStorage implements IStorage { async listMusicV2History(userName: string): Promise { try { const results = await this.db - .prepare('SELECT * FROM music_v2_history WHERE username = $1 ORDER BY last_played_at DESC') + // 按队列顺序返回;当前播放项由最大 last_played_at 决定 + .prepare('SELECT * FROM music_v2_history WHERE username = $1 ORDER BY created_at ASC, last_played_at ASC') .bind(userName) .all(); @@ -1440,7 +1441,7 @@ export class PostgresStorage implements IStorage { username, song_id, source, songmid, name, artist, album, cover, duration_text, duration_sec, play_progress_sec, last_played_at, play_count, last_quality, created_at, updated_at ) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16) ON CONFLICT(username, song_id) DO UPDATE SET source = EXCLUDED.source, songmid = EXCLUDED.songmid, diff --git a/src/lib/redis-base.db.ts b/src/lib/redis-base.db.ts index a4b4316..f8a7b0e 100644 --- a/src/lib/redis-base.db.ts +++ b/src/lib/redis-base.db.ts @@ -807,7 +807,12 @@ export abstract class BaseRedisStorage implements IStorage { return Object.values(rows || {}) .filter(Boolean) .map(value => JSON.parse(value as string) as MusicV2HistoryRecord) - .sort((a, b) => b.lastPlayedAt - a.lastPlayedAt); + // 按队列顺序返回;当前播放项由最大 lastPlayedAt 决定 + .sort((a, b) => { + const createdAtDiff = (a.createdAt || 0) - (b.createdAt || 0); + if (createdAtDiff !== 0) return createdAtDiff; + return (a.lastPlayedAt || 0) - (b.lastPlayedAt || 0); + }); } async upsertMusicV2History(userName: string, record: MusicV2HistoryRecord): Promise {