| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506 |
- 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<number> = 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;
- }
- }
|