import { VideoItem } from '../../viewmodel/VideoItem'; import { PlayMode } from './PlayerStateModel'; import { LogUtils } from '@ohos/ijkplayer'; import { ArrayUtil, RandomUtil } from '@pura/harmony-utils'; /** * 播放列表模型类 * 管理播放列表和播放导航逻辑 */ export class PlaylistModel { private songs: VideoItem[] = []; private currentIndex: number = 0; private playedIndices: Set = new Set(); // 用于随机播放的历史记录 private playHistory: VideoItem[] = []; // 播放历史记录 constructor(songs: VideoItem[] = [], currentIndex: number = 0) { this.songs = []; for (const song of songs) { this.songs.push(song); } this.currentIndex = Math.max(0, Math.min(currentIndex, songs.length - 1)); LogUtils.getInstance().LOGI(`PlaylistModel: Initialized with ${songs.length} songs, index ${this.currentIndex}`); } /** * 获取歌曲列表副本 */ getSongs(): VideoItem[] { const result: VideoItem[] = []; for (const song of this.songs) { result.push(song); } return result; } /** * 获取当前播放索引 */ getCurrentIndex(): number { return this.currentIndex; } /** * 设置当前播放索引 */ setCurrentIndex(index: number): boolean { if (index >= 0 && index < this.songs.length) { this.currentIndex = index; LogUtils.getInstance().LOGI(`PlaylistModel: Current index set to ${index}`); return true; } LogUtils.getInstance().LOGI(`PlaylistModel: Invalid index ${index}, playlist size: ${this.songs.length}`); return false; } /** * 获取当前播放的歌曲 */ getCurrentSong(): VideoItem | null { if (this.isEmpty() || this.currentIndex < 0 || this.currentIndex >= this.songs.length) { return null; } return this.songs[this.currentIndex]; } /** * 获取总歌曲数量 */ getTotalCount(): number { return this.songs.length; } /** * 检查播放列表是否为空 */ isEmpty(): boolean { return this.songs.length === 0; } /** * 播放列表操作:添加歌曲 */ addSong(song: VideoItem, index?: number): void { if (index !== undefined && index >= 0 && index <= this.songs.length) { this.songs.splice(index, 0, song); // 如果插入位置在当前播放位置之前,需要调整当前索引 if (index <= this.currentIndex) { this.currentIndex++; } } else { this.songs.push(song); } LogUtils.getInstance().LOGI(`PlaylistModel: Song added, total count: ${this.songs.length}`); } /** * 播放列表操作:添加多首歌曲 */ addSongs(songs: VideoItem[], index?: number): void { if (songs.length === 0) return; if (index !== undefined && index >= 0 && index <= this.songs.length) { for (let i = 0; i < songs.length; i++) { this.songs.splice(index + i, 0, songs[i]); } // 如果插入位置在当前播放位置之前,需要调整当前索引 if (index <= this.currentIndex) { this.currentIndex += songs.length; } } else { for (const song of songs) { this.songs.push(song); } } LogUtils.getInstance().LOGI(`PlaylistModel: ${songs.length} songs added, total count: ${this.songs.length}`); } /** * 播放列表操作:移除歌曲 */ removeSong(index: number): VideoItem | null { if (index < 0 || index >= this.songs.length) { LogUtils.getInstance().LOGI(`PlaylistModel: Invalid remove index ${index}`); return null; } const removedSong = this.songs.splice(index, 1)[0]; // 调整当前播放索引 if (index < this.currentIndex) { this.currentIndex--; } else if (index === this.currentIndex) { // 如果删除的是当前播放的歌曲,保持索引不变(播放下一首) // 但如果删除的是最后一首,需要调整到前一首 if (this.currentIndex >= this.songs.length && this.songs.length > 0) { this.currentIndex = this.songs.length - 1; } } LogUtils.getInstance().LOGI(`PlaylistModel: Song removed at index ${index}, total count: ${this.songs.length}`); return removedSong; } /** * 播放列表操作:移动歌曲 */ moveSong(fromIndex: number, toIndex: number): boolean { if (fromIndex < 0 || fromIndex >= this.songs.length || toIndex < 0 || toIndex >= this.songs.length || fromIndex === toIndex) { LogUtils.getInstance().LOGI(`PlaylistModel: Invalid move indices from ${fromIndex} to ${toIndex}`); return false; } const song = this.songs.splice(fromIndex, 1)[0]; this.songs.splice(toIndex, 0, song); // 调整当前播放索引 if (fromIndex === this.currentIndex) { this.currentIndex = toIndex; } else if (fromIndex < this.currentIndex && toIndex >= this.currentIndex) { this.currentIndex--; } else if (fromIndex > this.currentIndex && toIndex <= this.currentIndex) { this.currentIndex++; } LogUtils.getInstance().LOGI(`PlaylistModel: Song moved from ${fromIndex} to ${toIndex}`); return true; } /** * 播放列表操作:清空播放列表 */ clear(): void { this.songs = []; this.currentIndex = 0; this.playedIndices.clear(); this.playHistory = []; LogUtils.getInstance().LOGI('PlaylistModel: Playlist cleared'); } /** * 播放列表操作:替换整个播放列表 */ replaceSongs(songs: VideoItem[], currentIndex: number = 0): void { // 记录调用栈信息以便调试 const stack = new Error().stack || 'No stack available'; const caller = stack.split('\n')[2] || 'Unknown caller'; this.songs = []; for (const song of songs) { this.songs.push(song); } this.currentIndex = Math.max(0, Math.min(currentIndex, songs.length - 1)); this.playedIndices.clear(); this.playHistory = []; // 添加验证日志,包含调用源信息 const currentSong = this.getCurrentSong(); LogUtils.getInstance().LOGI(`PlaylistModel: Playlist replaced with ${songs.length} songs, index ${this.currentIndex}, current song: ${currentSong?.name || 'null'}, caller: ${caller.trim()}`); // 如果播放列表突然变小,记录更详细的信息 if (songs.length <= 20) { LogUtils.getInstance().LOGI(`PlaylistModel: Small playlist detected (${songs.length} songs), caller stack: ${stack.substring(0, 500)}`); LogUtils.getInstance().LOGI(`PlaylistModel: First few songs: ${songs.slice(0, 5).map(s => s.name).join(', ')}`); } // 如果索引无效,记录警告 if (currentIndex >= 0 && currentIndex < songs.length && this.currentIndex !== currentIndex) { LogUtils.getInstance().LOGI(`PlaylistModel: Warning - requested index ${currentIndex} adjusted to ${this.currentIndex}`); } } /** * 播放列表操作:随机打乱播放列表 */ shuffle(): void { if (this.songs.length <= 1) return; // 保存当前播放的歌曲 const currentSong = this.getCurrentSong(); // 打乱播放列表 for (let i = this.songs.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); const temp = this.songs[i]; this.songs[i] = this.songs[j]; this.songs[j] = temp; } // 重新找到当前播放歌曲的位置 if (currentSong) { const newIndex = this.songs.findIndex(song => song.filePath === currentSong.filePath); if (newIndex !== -1) { this.currentIndex = newIndex; } } this.playedIndices.clear(); LogUtils.getInstance().LOGI('PlaylistModel: Playlist shuffled'); } /** * 导航操作:检查是否有下一首 */ hasNext(playMode: PlayMode = PlayMode.SEQUENCE): boolean { if (this.isEmpty()) return false; switch (playMode) { case PlayMode.SINGLE_REPEAT: return true; // 单曲循环总是有下一首(自己) case PlayMode.SEQUENCE: return this.currentIndex < this.songs.length - 1; case PlayMode.NORMAL: return this.currentIndex < this.songs.length - 1; case PlayMode.RANDOM: return this.playedIndices.size < this.songs.length; // 还有未播放的歌曲 default: return false; } } /** * 导航操作:检查是否有上一首 */ hasPrevious(playMode: PlayMode = PlayMode.SEQUENCE): boolean { if (this.isEmpty()) return false; switch (playMode) { case PlayMode.SINGLE_REPEAT: return true; // 单曲循环总是有上一首(自己) case PlayMode.SEQUENCE: return this.currentIndex > 0; case PlayMode.NORMAL: return this.currentIndex > 0; case PlayMode.RANDOM: return this.playHistory.length > 1; // 有播放历史记录 default: return false; } } /** * 导航操作:获取下一首歌曲 */ getNext(playMode: PlayMode = PlayMode.SEQUENCE): VideoItem | null { if (this.isEmpty()) return null; let nextIndex = this.currentIndex; switch (playMode) { case PlayMode.SINGLE_REPEAT: // 单曲循环,返回当前歌曲 break; case PlayMode.SEQUENCE: // 顺序播放,循环到开头 nextIndex = (this.currentIndex + 1) % this.songs.length; break; case PlayMode.NORMAL: // 正常播放,不循环 if (this.currentIndex < this.songs.length - 1) { nextIndex = this.currentIndex + 1; } else { return null; // 已经是最后一首 } break; case PlayMode.RANDOM: // 随机播放 nextIndex = this.getRandomNextIndex(); if (nextIndex === -1) return null; break; } return this.songs[nextIndex]; } /** * 导航操作:获取上一首歌曲 */ getPrevious(playMode: PlayMode = PlayMode.SEQUENCE): VideoItem | null { if (this.isEmpty()) return null; let prevIndex = this.currentIndex; switch (playMode) { case PlayMode.SINGLE_REPEAT: // 单曲循环,返回当前歌曲 break; case PlayMode.SEQUENCE: // 顺序播放,循环到末尾 prevIndex = this.currentIndex === 0 ? this.songs.length - 1 : this.currentIndex - 1; break; case PlayMode.NORMAL: // 正常播放,不循环 if (this.currentIndex > 0) { prevIndex = this.currentIndex - 1; } else { return null; // 已经是第一首 } break; case PlayMode.RANDOM: // 随机播放,从历史记录获取 return this.getRandomPrevious(); } return this.songs[prevIndex]; } /** * 导航操作:移动到下一首 */ moveToNext(playMode: PlayMode = PlayMode.SEQUENCE): boolean { if (this.isEmpty()) return false; let nextIndex = this.currentIndex; // 添加当前歌曲到播放历史(随机模式) const currentSong = this.getCurrentSong(); if (currentSong && playMode === PlayMode.RANDOM) { this.addToPlayHistory(currentSong); this.playedIndices.add(this.currentIndex); } // 直接计算下一个索引,而不依赖getNext方法 switch (playMode) { case PlayMode.SINGLE_REPEAT: // 单曲循环,索引不变 LogUtils.getInstance().LOGI(`PlaylistModel: Single repeat mode, staying at index ${this.currentIndex}`); return true; case PlayMode.SEQUENCE: // 顺序播放,循环到开头 nextIndex = (this.currentIndex + 1) % this.songs.length; break; case PlayMode.NORMAL: // 正常播放,不循环 if (this.currentIndex < this.songs.length - 1) { nextIndex = this.currentIndex + 1; } else { LogUtils.getInstance().LOGI('PlaylistModel: Already at last song in normal mode'); return false; // 已经是最后一首 } break; case PlayMode.RANDOM: // 随机播放 nextIndex = this.getRandomNextIndex(); if (nextIndex === -1) { LogUtils.getInstance().LOGI('PlaylistModel: No available random song'); return false; } break; default: return false; } // 更新索引 if (nextIndex >= 0 && nextIndex < this.songs.length) { const oldIndex = this.currentIndex; this.currentIndex = nextIndex; LogUtils.getInstance().LOGI(`PlaylistModel: Moved to next song from index ${oldIndex} to ${this.currentIndex}`); return true; } return false; } /** * 导航操作:移动到上一首 */ moveToPrevious(playMode: PlayMode = PlayMode.SEQUENCE): boolean { const prevSong = this.getPrevious(playMode); if (!prevSong) return false; // 更新索引 const prevIndex = this.songs.findIndex(song => song.filePath === prevSong.filePath); if (prevIndex !== -1) { this.currentIndex = prevIndex; // 随机播放模式下,从历史记录中移除 if (playMode === PlayMode.RANDOM && this.playHistory.length > 0) { this.playHistory.pop(); // 移除最后一个(当前播放的) } LogUtils.getInstance().LOGI(`PlaylistModel: Moved to previous song at index ${this.currentIndex}`); return true; } return false; } /** * 根据文件路径查找歌曲索引 */ findSongIndex(filePath: string): number { return this.songs.findIndex(song => song.filePath === filePath); } /** * 播放指定索引的歌曲 */ playSongAtIndex(index: number): boolean { if (index >= 0 && index < this.songs.length) { this.currentIndex = index; LogUtils.getInstance().LOGI(`PlaylistModel: Playing song at index ${index}`); return true; } LogUtils.getInstance().LOGI(`PlaylistModel: Invalid play index ${index}`); return false; } /** * 获取随机播放的下一个索引 */ private getRandomNextIndex(): number { const unplayedIndices: number[] = []; for (let i = 0; i < this.songs.length; i++) { if (!this.playedIndices.has(i)) { unplayedIndices.push(i); } } if (unplayedIndices.length === 0) { // 所有歌曲都播放过了,重置并重新开始 this.playedIndices.clear(); this.playHistory = []; for (let i = 0; i < this.songs.length; i++) { if (i !== this.currentIndex) { unplayedIndices.push(i); } } } if (unplayedIndices.length === 0) return -1; const randomIndex = Math.floor(Math.random() * unplayedIndices.length); return unplayedIndices[randomIndex]; } /** * 获取随机播放模式下的上一首 */ private getRandomPrevious(): VideoItem | null { if (this.playHistory.length >= 2) { // 返回历史记录的第二首(第一首是当前播放的) return this.playHistory[this.playHistory.length - 2]; } return null; } /** * 添加到播放历史记录 */ private addToPlayHistory(song: VideoItem): void { this.playHistory.push(song); // 限制历史记录长度,避免内存占用过多 if (this.playHistory.length > 50) { this.playHistory.shift(); } } /** * 获取播放历史记录 */ getPlayHistory(): VideoItem[] { const result: VideoItem[] = []; for (const item of this.playHistory) { result.push(item); } return result; } }