修复关系型数据库保存音乐记录错误,播放记录修改为队列式
This commit is contained in:
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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 [];
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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> {
|
||||
|
||||
Reference in New Issue
Block a user