修复关系型数据库保存音乐记录错误,播放记录修改为队列式

This commit is contained in:
mtvpls
2026-05-09 10:25:39 +08:00
parent 2480b4d28b
commit a8cacf3e60
6 changed files with 54 additions and 14 deletions
+2
View File
@@ -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) {
+38 -9
View File
@@ -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);
+3 -2
View File
@@ -748,7 +748,8 @@ export class D1Storage implements IStorage {
async listMusicV2History(userName: string): Promise<MusicV2HistoryRecord[]> {
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,
+2
View File
@@ -273,6 +273,8 @@ export class DbManager {
// Music V2 历史记录相关
async listMusicV2History(userName: string): Promise<MusicV2HistoryRecord[]> {
if (typeof (this.storage as any).listMusicV2History === 'function') {
// 按播放队列顺序返回(createdAt ASC),
// 当前播放项由调用方基于 lastPlayedAt 决定。
return (this.storage as any).listMusicV2History(userName);
}
return [];
+3 -2
View File
@@ -1403,7 +1403,8 @@ export class PostgresStorage implements IStorage {
async listMusicV2History(userName: string): Promise<MusicV2HistoryRecord[]> {
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,
+6 -1
View File
@@ -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<void> {