chendeben 1 год назад
Родитель
Сommit
48dcbb5eb8

+ 0 - 244
entry/src/main/ets/common/service/ErrorRecoveryStrategyTest.ets

@@ -1,244 +0,0 @@
-import { ErrorRecoveryStrategy, ErrorContext, ErrorRecoveryAction } from './ErrorRecoveryStrategy';
-import { PlayerError, PlayerErrorType } from './PlayerStateModel';
-import { VideoItem } from '../../viewmodel/VideoItem';
-import { LogUtils } from '@ohos/ijkplayer';
-
-/**
- * 错误恢复策略测试类
- * 用于验证错误恢复机制的正确性
- */
-export class ErrorRecoveryStrategyTest {
-  private errorRecovery: ErrorRecoveryStrategy;
-
-  constructor() {
-    this.errorRecovery = ErrorRecoveryStrategy.getInstance();
-  }
-
-  /**
-   * 运行所有测试
-   */
-  async runAllTests(): Promise<void> {
-    LogUtils.getInstance().LOGI('ErrorRecoveryStrategyTest: Starting all tests');
-
-    try {
-      await this.testFileNotFoundError();
-      await this.testNetworkError();
-      await this.testPlaybackError();
-      await this.testInitializationError();
-      await this.testRetryLogic();
-      await this.testSkipLogic();
-
-      LogUtils.getInstance().LOGI('ErrorRecoveryStrategyTest: All tests completed successfully');
-    } catch (error) {
-      LogUtils.getInstance().LOGI(`ErrorRecoveryStrategyTest: Test failed: ${error}`);
-    }
-  }
-
-  /**
-   * 测试文件不存在错误
-   */
-  private async testFileNotFoundError(): Promise<void> {
-    LogUtils.getInstance().LOGI('ErrorRecoveryStrategyTest: Testing file not found error');
-
-    const error = new PlayerError(PlayerErrorType.FILE_NOT_FOUND, 'Test file not found');
-    const context = this.createTestContext();
-
-    const action = await this.errorRecovery.handleError(error, context);
-    
-    if (action === ErrorRecoveryAction.SKIP_TO_NEXT) {
-      LogUtils.getInstance().LOGI('✅ File not found error test passed');
-    } else {
-      throw new Error(`Expected SKIP_TO_NEXT, got ${action}`);
-    }
-  }
-
-  /**
-   * 测试网络错误
-   */
-  private async testNetworkError(): Promise<void> {
-    LogUtils.getInstance().LOGI('ErrorRecoveryStrategyTest: Testing network error');
-
-    const error = new PlayerError(PlayerErrorType.NETWORK_ERROR, 'Test network error');
-    error.retryCount = 0;
-    
-    const context = this.createTestContext();
-    context.currentSong = this.createNetworkSong();
-
-    const action = await this.errorRecovery.handleError(error, context);
-    
-    if (action === ErrorRecoveryAction.WAIT_AND_RETRY || action === ErrorRecoveryAction.RETRY) {
-      LogUtils.getInstance().LOGI('✅ Network error test passed');
-    } else {
-      throw new Error(`Expected WAIT_AND_RETRY or RETRY, got ${action}`);
-    }
-  }
-
-  /**
-   * 测试播放错误
-   */
-  private async testPlaybackError(): Promise<void> {
-    LogUtils.getInstance().LOGI('ErrorRecoveryStrategyTest: Testing playback error');
-
-    const error = new PlayerError(PlayerErrorType.PLAYBACK_ERROR, 'Test playback error');
-    error.retryCount = 0;
-    
-    const context = this.createTestContext();
-
-    const action = await this.errorRecovery.handleError(error, context);
-    
-    if (action === ErrorRecoveryAction.RETRY) {
-      LogUtils.getInstance().LOGI('✅ Playback error test passed');
-    } else {
-      throw new Error(`Expected RETRY, got ${action}`);
-    }
-  }
-
-  /**
-   * 测试初始化错误
-   */
-  private async testInitializationError(): Promise<void> {
-    LogUtils.getInstance().LOGI('ErrorRecoveryStrategyTest: Testing initialization error');
-
-    const error = new PlayerError(PlayerErrorType.INITIALIZATION_ERROR, 'Test initialization error');
-    error.retryCount = 0;
-    
-    const context = this.createTestContext();
-
-    const action = await this.errorRecovery.handleError(error, context);
-    
-    if (action === ErrorRecoveryAction.WAIT_AND_RETRY) {
-      LogUtils.getInstance().LOGI('✅ Initialization error test passed');
-    } else {
-      throw new Error(`Expected WAIT_AND_RETRY, got ${action}`);
-    }
-  }
-
-  /**
-   * 测试重试逻辑
-   */
-  private async testRetryLogic(): Promise<void> {
-    LogUtils.getInstance().LOGI('ErrorRecoveryStrategyTest: Testing retry logic');
-
-    const error = new PlayerError(PlayerErrorType.PLAYBACK_ERROR, 'Test retry logic');
-    
-    // 测试重试次数限制
-    error.retryCount = 0;
-    if (!this.errorRecovery.shouldRetry(error)) {
-      throw new Error('Should retry when retryCount is 0');
-    }
-    
-    error.retryCount = 3;
-    if (this.errorRecovery.shouldRetry(error)) {
-      throw new Error('Should not retry when retryCount exceeds limit');
-    }
-    
-    // 测试不可恢复错误
-    const nonRecoverableError = new PlayerError(PlayerErrorType.FILE_NOT_FOUND, 'Non-recoverable error');
-    if (this.errorRecovery.shouldRetry(nonRecoverableError)) {
-      throw new Error('Should not retry non-recoverable errors');
-    }
-    
-    // 测试重试延迟
-    const delay1 = this.errorRecovery.getRetryDelay(0);
-    const delay2 = this.errorRecovery.getRetryDelay(1);
-    const delay3 = this.errorRecovery.getRetryDelay(2);
-    
-    if (delay1 >= delay2 || delay2 >= delay3) {
-      throw new Error('Retry delay should increase with retry count');
-    }
-
-    LogUtils.getInstance().LOGI('✅ Retry logic test passed');
-  }
-
-  /**
-   * 测试跳歌逻辑
-   */
-  private async testSkipLogic(): Promise<void> {
-    LogUtils.getInstance().LOGI('ErrorRecoveryStrategyTest: Testing skip logic');
-
-    // 测试有下一首歌的情况
-    const error = new PlayerError(PlayerErrorType.FILE_NOT_FOUND, 'Test skip logic');
-    const context = this.createTestContext();
-    context.currentIndex = 0;
-    context.playlist = [this.createTestSong('song1'), this.createTestSong('song2')];
-
-    const action = await this.errorRecovery.handleError(error, context);
-    
-    if (action !== ErrorRecoveryAction.SKIP_TO_NEXT) {
-      throw new Error(`Expected SKIP_TO_NEXT when next song available, got ${action}`);
-    }
-
-    // 测试没有下一首歌的情况
-    context.currentIndex = 1;
-    context.playlist = [this.createTestSong('song1'), this.createTestSong('song2')];
-
-    const action2 = await this.errorRecovery.handleError(error, context);
-    
-    if (action2 !== ErrorRecoveryAction.STOP_PLAYBACK) {
-      throw new Error(`Expected STOP_PLAYBACK when no next song, got ${action2}`);
-    }
-
-    LogUtils.getInstance().LOGI('✅ Skip logic test passed');
-  }
-
-  /**
-   * 创建测试上下文
-   */
-  private createTestContext(): ErrorContext {
-    return {
-      currentSong: this.createTestSong('test_song'),
-      playlist: [this.createTestSong('song1'), this.createTestSong('song2')],
-      currentIndex: 0,
-      retryCount: 0,
-      isNetworkAvailable: true
-    };
-  }
-
-  /**
-   * 创建测试歌曲
-   */
-  private createTestSong(name: string): VideoItem {
-    return {
-      id: name,
-      name: name,
-      filePath: `/test/path/${name}.mp3`,
-      artist: 'Test Artist',
-      album: 'Test Album',
-      duration: 180000,
-      pixelMapPath: '',
-      size: 0,
-      dateAdded: Date.now(),
-      dateModified: Date.now(),
-      displayName: name,
-      title: name
-    };
-  }
-
-  /**
-   * 创建网络歌曲
-   */
-  private createNetworkSong(): VideoItem {
-    return {
-      id: 'network_song',
-      name: 'Network Song',
-      filePath: 'https://example.com/song.mp3',
-      artist: 'Network Artist',
-      album: 'Network Album',
-      duration: 180000,
-      pixelMapPath: '',
-      size: 0,
-      dateAdded: Date.now(),
-      dateModified: Date.now(),
-      displayName: 'Network Song',
-      title: 'Network Song'
-    };
-  }
-}
-
-/**
- * 运行错误恢复策略测试
- */
-export async function runErrorRecoveryTests(): Promise<void> {
-  const test = new ErrorRecoveryStrategyTest();
-  await test.runAllTests();
-}

+ 162 - 58
entry/src/main/ets/common/service/PlaylistModel.ets

@@ -2,6 +2,7 @@ import { VideoItem } from '../../viewmodel/VideoItem';
 import { PlayMode } from './PlayerStateModel';
 import { LogUtils } from '@ohos/ijkplayer';
 import { ArrayUtil, RandomUtil } from '@pura/harmony-utils';
+import MediaTable from '../util/MediaTable';
 
 /**
  * 播放列表模型类
@@ -11,7 +12,8 @@ export class PlaylistModel {
   private songs: VideoItem[] = [];
   private currentIndex: number = 0;
   private playedIndices: Set<number> = new Set(); // 用于随机播放的历史记录
-  private playHistory: VideoItem[] = []; // 播放历史记录
+  private playHistory: VideoItem[] = []; // 播放历史记录(内存缓存)
+  private mediaTable: MediaTable | null = null; // 数据库访问实例
 
   constructor(songs: VideoItem[] = [], currentIndex: number = 0) {
     this.songs = [];
@@ -19,9 +21,22 @@ export class PlaylistModel {
       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}`);
   }
 
+  /**
+   * 初始化MediaTable实例(延迟初始化)
+   */
+  initializeMediaTable(context: Context): void {
+    try {
+      this.mediaTable = new MediaTable(context);
+      LogUtils.getInstance().LOGI('PlaylistModel: MediaTable initialized successfully');
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`PlaylistModel: Failed to initialize MediaTable: ${error.message}`);
+    }
+  }
+
   /**
    * 获取歌曲列表副本
    */
@@ -259,9 +274,32 @@ export class PlaylistModel {
   }
 
   /**
-   * 导航操作:检查是否有上一首
+   * 导航操作:检查是否有上一首(同步版本,基于内存缓存)
+   */
+  hasPreviousSync(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:
+        // 随机模式下:基于内存缓存的播放历史记录
+        const hasValidHistory = this.playHistory.length >= 2;
+        LogUtils.getInstance().LOGI(`PlaylistModel.hasPreviousSync: RANDOM mode, cacheHistoryLength=${this.playHistory.length}, hasValidHistory=${hasValidHistory}`);
+        return hasValidHistory;
+      default:
+        return false;
+    }
+  }
+
+  /**
+   * 导航操作:检查是否有上一首(异步版本,基于数据库)
    */
-  hasPrevious(playMode: PlayMode = PlayMode.SEQUENCE): boolean {
+  async hasPrevious(playMode: PlayMode = PlayMode.SEQUENCE): Promise<boolean> {
     if (this.isEmpty()) return false;
     
     switch (playMode) {
@@ -277,13 +315,11 @@ export class PlaylistModel {
         LogUtils.getInstance().LOGI(`PlaylistModel.hasPrevious: NORMAL mode, currentIndex=${this.currentIndex}, result=${normalResult}`);
         return normalResult;
       case PlayMode.RANDOM:
-        // 随机模式下:有播放历史记录,或者当前播放的不是第一首(作为备选)
-        const historyLength = this.playHistory.length;
-        const hasHistory = historyLength > 1;
-        const hasBackup = historyLength === 1 && this.songs.length > 1;
-        const randomResult = hasHistory || hasBackup;
-        LogUtils.getInstance().LOGI(`PlaylistModel.hasPrevious: RANDOM mode, historyLength=${historyLength}, hasHistory=${hasHistory}, hasBackup=${hasBackup}, result=${randomResult}`);
-        return randomResult;
+        // 随机模式下:从数据库检查播放历史记录
+        const dbHistory = await this.loadPlayHistoryFromDatabase();
+        const hasValidHistory = dbHistory.length >= 2;
+        LogUtils.getInstance().LOGI(`PlaylistModel.hasPrevious: RANDOM mode, dbHistoryLength=${dbHistory.length}, hasValidHistory=${hasValidHistory}`);
+        return hasValidHistory;
       default:
         LogUtils.getInstance().LOGI(`PlaylistModel.hasPrevious: Unknown mode, returning false`);
         return false;
@@ -326,7 +362,7 @@ export class PlaylistModel {
   /**
    * 导航操作:获取上一首歌曲
    */
-  getPrevious(playMode: PlayMode = PlayMode.SEQUENCE): VideoItem | null {
+  async getPrevious(playMode: PlayMode = PlayMode.SEQUENCE): Promise<VideoItem | null> {
     if (this.isEmpty()) return null;
     
     let prevIndex = this.currentIndex;
@@ -349,7 +385,7 @@ export class PlaylistModel {
         break;
       case PlayMode.RANDOM:
         // 随机播放,从历史记录获取
-        return this.getRandomPrevious();
+        return await this.getRandomPrevious();
     }
     
     return this.songs[prevIndex];
@@ -368,6 +404,9 @@ export class PlaylistModel {
     if (currentSong && playMode === PlayMode.RANDOM) {
       this.addToPlayHistory(currentSong);
       this.playedIndices.add(this.currentIndex);
+      
+      // 同时保存到数据库播放历史
+      this.saveToPlayHistory(currentSong);
     }
     
     // 直接计算下一个索引,而不依赖getNext方法
@@ -414,8 +453,8 @@ export class PlaylistModel {
  /**
    * 导航操作:移动到上一首
    */
-  moveToPrevious(playMode: PlayMode = PlayMode.SEQUENCE): boolean {
-    const prevSong = this.getPrevious(playMode);
+  async moveToPrevious(playMode: PlayMode = PlayMode.SEQUENCE): Promise<boolean> {
+    const prevSong = await this.getPrevious(playMode);
     if (!prevSong) return false;
     
     // 更新索引
@@ -423,9 +462,11 @@ export class PlaylistModel {
     if (prevIndex !== -1) {
       this.currentIndex = prevIndex;
       
-      // 随机播放模式下,从历史记录中移除
-      if (playMode === PlayMode.RANDOM && this.playHistory.length > 0) {
-        this.playHistory.pop(); // 移除最后一个(当前播放的)
+      // 随机播放模式下,从数据库播放历史中处理
+      if (playMode === PlayMode.RANDOM) {
+        // 这里不需要从内存中移除,因为我们直接从数据库读取最新状态
+        // 数据库的播放历史会在下次播放时自动更新
+        LogUtils.getInstance().LOGI('PlaylistModel: Random mode previous - relying on database history');
       }
       
       LogUtils.getInstance().LOGI(`PlaylistModel: Moved to previous song at index ${this.currentIndex}`);
@@ -486,38 +527,30 @@ export class PlaylistModel {
   /**
    * 获取随机播放模式下的上一首
    */
-  private getRandomPrevious(): VideoItem | null {
-    LogUtils.getInstance().LOGI(`PlaylistModel.getRandomPrevious: playHistory.length=${this.playHistory.length}, songs.length=${this.songs.length}, currentIndex=${this.currentIndex}`);
-    
-    // 如果有足够的播放历史记录,从历史记录获取
-    if (this.playHistory.length >= 2) {
-      // 返回历史记录的第二首(第一首是当前播放的)
-      const prevSong = this.playHistory[this.playHistory.length - 2];
-      LogUtils.getInstance().LOGI(`PlaylistModel.getRandomPrevious: 从播放历史获取上一首: ${prevSong.name}`);
-      return prevSong;
-    }
-    
-    // 如果历史记录不足,但有多首歌曲,随机选择一首作为"上一首"
-    if (this.songs.length > 1) {
-      LogUtils.getInstance().LOGI('PlaylistModel.getRandomPrevious: 随机模式播放历史不足,随机选择上一首');
-      
-      // 排除当前播放的歌曲,从其他歌曲中随机选择
-      const availableIndices: number[] = [];
-      for (let i = 0; i < this.songs.length; i++) {
-        if (i !== this.currentIndex) {
-          availableIndices.push(i);
-        }
-      }
+  private async getRandomPrevious(): Promise<VideoItem | null> {
+    // 从数据库加载最新的播放历史
+    const dbHistory = await this.loadPlayHistoryFromDatabase();
+    LogUtils.getInstance().LOGI(`PlaylistModel.getRandomPrevious: dbHistory.length=${dbHistory.length}, songs.length=${this.songs.length}, currentIndex=${this.currentIndex}`);
+    
+    // 随机播放模式下,上一首必须严格从播放历史记录中获取
+    if (dbHistory.length >= 2) {
+      // 返回历史记录的倒数第二首(倒数第一首应该是当前播放的)
+      const prevSong = dbHistory[dbHistory.length - 2];
+      LogUtils.getInstance().LOGI(`PlaylistModel.getRandomPrevious: 从数据库播放历史获取上一首: ${prevSong.name}`);
       
-      if (availableIndices.length > 0) {
-        const randomIndex = availableIndices[Math.floor(Math.random() * availableIndices.length)];
-        const randomSong = this.songs[randomIndex];
-        LogUtils.getInstance().LOGI(`PlaylistModel.getRandomPrevious: 随机选择歌曲索引 ${randomIndex}: ${randomSong.name}`);
-        return randomSong;
+      // 在当前播放列表中查找这首歌曲
+      const songIndex = this.songs.findIndex(song => song.filePath === prevSong.filePath);
+      if (songIndex !== -1) {
+        return this.songs[songIndex];
+      } else {
+        LogUtils.getInstance().LOGI(`PlaylistModel.getRandomPrevious: 上一首歌曲不在当前播放列表中: ${prevSong.name}`);
+        return null;
       }
     }
     
-    LogUtils.getInstance().LOGI('PlaylistModel.getRandomPrevious: 无可用的上一首歌曲');
+    // 如果播放历史记录不足,则没有真正的"上一首"
+    // 在随机播放模式下,不应该随机选择一首歌曲作为上一首
+    LogUtils.getInstance().LOGI('PlaylistModel.getRandomPrevious: 数据库播放历史记录不足,无法提供真正的上一首歌曲');
     return null;
   }
 
@@ -532,31 +565,91 @@ export class PlaylistModel {
     }
   }
 
+  /**
+   * 保存歌曲到数据库播放历史
+   */
+  private saveToPlayHistory(song: VideoItem): void {
+    if (!this.mediaTable || !song || !song.filePath) {
+      LogUtils.getInstance().LOGI('PlaylistModel.saveToPlayHistory: Invalid parameters');
+      return;
+    }
+
+    // 生成时间戳字符串
+    const now = new Date();
+    const timeString = now.getFullYear() + 
+      String(now.getMonth() + 1).padStart(2, '0') + 
+      String(now.getDate()).padStart(2, '0') + 
+      String(now.getHours()).padStart(2, '0') + 
+      String(now.getMinutes()).padStart(2, '0') + 
+      String(now.getSeconds()).padStart(2, '0');
+
+    try {
+      this.mediaTable.updateLastPlayedStrByFilePath(
+        song.filePath,
+        timeString,
+        (success: boolean, error?: string) => {
+          if (success) {
+            LogUtils.getInstance().LOGI(`PlaylistModel.saveToPlayHistory: Successfully saved ${song.name} to play history`);
+          } else {
+            LogUtils.getInstance().LOGI(`PlaylistModel.saveToPlayHistory: Failed to save ${song.name}: ${error || 'Unknown error'}`);
+          }
+        }
+      );
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`PlaylistModel.saveToPlayHistory: Exception: ${error.message}`);
+    }
+  }
+
+  /**
+   * 从数据库加载播放历史记录
+   */
+  loadPlayHistoryFromDatabase(): Promise<VideoItem[]> {
+    return new Promise((resolve) => {
+      if (!this.mediaTable) {
+        LogUtils.getInstance().LOGI('PlaylistModel.loadPlayHistoryFromDatabase: MediaTable not initialized');
+        resolve([]);
+        return;
+      }
+
+      try {
+        this.mediaTable.queryRecentPlayedRecords(50, (result: VideoItem[]) => {
+          LogUtils.getInstance().LOGI(`PlaylistModel.loadPlayHistoryFromDatabase: Loaded ${result.length} records`);
+          resolve(result);
+        });
+      } catch (error) {
+        LogUtils.getInstance().LOGI(`PlaylistModel.loadPlayHistoryFromDatabase: Exception: ${error.message}`);
+        resolve([]);
+      }
+    });
+  }
+
   /**
    * 确保当前歌曲在播放历史中(用于随机播放模式)
    */
-  ensureCurrentSongInHistory(): void {
+  async ensureCurrentSongInHistory(): Promise<void> {
     const currentSong = this.getCurrentSong();
     if (!currentSong) {
       LogUtils.getInstance().LOGI('PlaylistModel.ensureCurrentSongInHistory: 当前没有播放歌曲');
       return;
     }
 
-    if (this.playHistory.length === 0) {
-      // 如果播放历史为空,添加当前歌曲
-      this.addToPlayHistory(currentSong);
-      LogUtils.getInstance().LOGI(`PlaylistModel.ensureCurrentSongInHistory: 初始化播放历史,添加当前歌曲: ${currentSong.name}`);
+    // 从数据库加载最新的播放历史
+    const dbHistory = await this.loadPlayHistoryFromDatabase();
+    
+    // 检查当前歌曲是否已经在数据库播放历史中
+    const isInDbHistory = dbHistory.some(song => song.filePath === currentSong.filePath);
+    
+    if (!isInDbHistory) {
+      // 如果不在数据库历史中,则保存当前歌曲
+      this.saveToPlayHistory(currentSong);
+      LogUtils.getInstance().LOGI(`PlaylistModel.ensureCurrentSongInHistory: 保存当前歌曲到数据库播放历史: ${currentSong.name}`);
     } else {
-      // 检查最后一首是否是当前歌曲,如果不是则添加
-      const lastSong = this.playHistory[this.playHistory.length - 1];
-      if (lastSong.filePath !== currentSong.filePath) {
-        this.addToPlayHistory(currentSong);
-        LogUtils.getInstance().LOGI(`PlaylistModel.ensureCurrentSongInHistory: 更新播放历史,添加当前歌曲: ${currentSong.name}`);
-      } else {
-        LogUtils.getInstance().LOGI(`PlaylistModel.ensureCurrentSongInHistory: 当前歌曲已在播放历史中: ${currentSong.name}`);
-      }
+      LogUtils.getInstance().LOGI(`PlaylistModel.ensureCurrentSongInHistory: 当前歌曲已在数据库播放历史中: ${currentSong.name}`);
     }
 
+    // 更新内存中的播放历史缓存
+    this.playHistory = dbHistory.slice(); // 创建副本
+    
     LogUtils.getInstance().LOGI(`PlaylistModel.ensureCurrentSongInHistory: 播放历史长度: ${this.playHistory.length}`);
   }
 
@@ -570,4 +663,15 @@ export class PlaylistModel {
     }
     return result;
   }
+
+  /**
+   * 获取播放历史调试信息
+   */
+  getPlayHistoryDebugInfo(): string {
+    const currentSong = this.getCurrentSong();
+    const currentSongName = currentSong ? currentSong.name : 'None';
+    const historyNames = this.playHistory.map(song => song.name).join(' -> ');
+    
+    return `Current: ${currentSongName}, History(${this.playHistory.length}): [${historyNames}], CurrentIndex: ${this.currentIndex}`;
+  }
 }

+ 29 - 8
entry/src/main/ets/common/service/UnifiedPlayerService.ets

@@ -308,6 +308,9 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
       this.playerManager.setStateCallback(this);
       this.widgetUpdateService.setAppContext(context);
 
+      // 初始化PlaylistModel的MediaTable
+      this.playlistModel.initializeMediaTable(context);
+
       // 设置同步监听器
       this.playlistSync.addSyncListener(this);
       this.stateSync.subscribeToStateChanges(this);
@@ -557,7 +560,7 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
     // 在随机播放模式下,确保播放历史被正确维护
     const playMode = this.stateModel.getState().playMode;
     if (playMode === PlayMode.RANDOM) {
-      this.playlistModel.ensureCurrentSongInHistory();
+      await this.playlistModel.ensureCurrentSongInHistory();
     }
 
     // 设置播放源和配置
@@ -602,7 +605,7 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
     // 在随机播放模式下,确保播放历史被正确维护
     const playMode = this.stateModel.getState().playMode;
     if (playMode === PlayMode.RANDOM) {
-      this.playlistModel.ensureCurrentSongInHistory();
+      await this.playlistModel.ensureCurrentSongInHistory();
     }
 
     // 设置播放源和配置
@@ -790,14 +793,14 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
 
       const playMode = this.stateModel.getState().playMode;
 
-      if (!this.playlistModel.hasPrevious(playMode)) {
+      if (!(await this.playlistModel.hasPrevious(playMode))) {
         this.isManualSongChange = false;
         return;
       }
 
       // 先获取当前歌曲信息用于日志
 
-      const moved = this.playlistModel.moveToPrevious(playMode);
+      const moved = await this.playlistModel.moveToPrevious(playMode);
       if (!moved) {
         this.isManualSongChange = false;
         return;
@@ -850,6 +853,13 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
 
       // 静默停止当前播放并开始新歌曲(不触发状态变化通知)
       await this.stopSilently();
+
+      // 在随机播放模式下,确保当前歌曲被添加到播放历史
+      const playMode = this.stateModel.getState().playMode;
+      if (playMode === PlayMode.RANDOM) {
+        await this.playlistModel.ensureCurrentSongInHistory();
+      }
+
       await this.startPlayOrResumePlay();
 
       // 更新状态模型中的播放列表状态
@@ -2257,7 +2267,7 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
   /**
    * 更新状态模型中的播放列表状态
    */
-  private updatePlaylistStateInModel(): void {
+  private async updatePlaylistStateInModel(): Promise<void> {
     try {
       const currentIndex = this.playlistModel.getCurrentIndex();
       const totalCount = this.playlistModel.getTotalCount();
@@ -2265,11 +2275,15 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
 
       // 在随机播放模式下,确保当前歌曲在播放历史中
       if (playMode === PlayMode.RANDOM) {
-        this.playlistModel.ensureCurrentSongInHistory();
+        await this.playlistModel.ensureCurrentSongInHistory();
+        
+        // 输出播放历史调试信息
+        const debugInfo = this.playlistModel.getPlayHistoryDebugInfo();
+        LogUtils.getInstance().LOGI(`UnifiedPlayerService: Random mode play history - ${debugInfo}`);
       }
 
       const hasNext = this.playlistModel.hasNext(playMode);
-      const hasPrevious = this.playlistModel.hasPrevious(playMode);
+      const hasPrevious = await this.playlistModel.hasPrevious(playMode);
 
       this.stateModel.updatePlaylistState(hasNext, hasPrevious, totalCount);
 
@@ -2310,6 +2324,13 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
     // 这个回调只应该在新歌曲开始播放时被调用(通过onPrepared触发)
     // 不应该在暂停恢复时被调用
 
+    // 在随机播放模式下,确保当前歌曲在播放历史中
+    const playMode = this.stateModel.getState().playMode;
+    if (playMode === PlayMode.RANDOM) {
+      this.playlistModel.ensureCurrentSongInHistory();
+      LogUtils.getInstance().LOGI('UnifiedPlayerService: Ensured current song in play history for random mode');
+    }
+
     // 立即更新播放状态
     this.stateModel.updatePlayingState(true);
 
@@ -2521,7 +2542,7 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
       },
       playlist: {
         hasNext: this.playlistModel.hasNext(playMode),
-        hasPrevious: this.playlistModel.hasPrevious(playMode),
+        hasPrevious: this.playlistModel.hasPreviousSync(playMode),
         currentIndex: currentIndex,
         totalCount: totalCount
       },

+ 13 - 130
entry/src/main/ets/view/LocalMusic.ets

@@ -437,13 +437,8 @@ export struct LocalMusic {
 
       // 等待数据恢复完成后再获取播放列表
       LogUtils.getInstance().LOGI('LocalMusic: Waiting for UnifiedPlayerService data restoration...');
-      const dataRestored: boolean = await this.unifiedPlayerService.waitForDataRestoration(5000);
+      await this.unifiedPlayerService.waitForDataRestoration(5000);
 
-      if (!dataRestored) {
-        LogUtils.getInstance().LOGI('LocalMusic: Data restoration timeout, but proceeding with initialization');
-      } else {
-        LogUtils.getInstance().LOGI('LocalMusic: Data restoration completed successfully');
-      }
 
       // 从UnifiedPlayerService恢复播放列表和状态
       const restoredPlaylist = this.unifiedPlayerService.getPlaylist();
@@ -456,11 +451,6 @@ export struct LocalMusic {
         this.curIndex = restoredIndex;
         this.currentSong = restoredSong || undefined;
 
-        // 同步到AppStorage
-        AppStorage.setOrCreate('songList', this.songList);
-        AppStorage.setOrCreate('currIndex', this.curIndex);
-        AppStorage.setOrCreate('currentSong', this.currentSong);
-
         // 更新UI数据源
         this.sonDataSource.pushArrayData(this.songList);
 
@@ -544,18 +534,11 @@ export struct LocalMusic {
         }
 
         onSongChanged(song: VideoItem): void {
-          console.log(`Heanup onSongChanged - 开始处理歌曲切换: ${song.name}`);
-          console.log(`Heanup onSongChanged - 切换前 oldSeconds: ${this.localMusic.oldSeconds}, currentTime: ${this.localMusic.currentTime}`);
-
           // 立即重置时间显示状态,防止新歌曲时间显示被上一首歌曲的时间"卡住"
           this.localMusic.oldSeconds = 0;
           this.localMusic.currentTime = "00:00";
           this.localMusic.lastSongPath = song.filePath; // 更新当前歌曲路径
           this.localMusic.justSwitched = true; // 标记歌曲刚刚切换
-
-
-          console.log(`Heanup onSongChanged - 重置后 oldSeconds: ${this.localMusic.oldSeconds}, currentTime: ${this.localMusic.currentTime}`);
-
           // 同步当前歌曲信息
           this.localMusic.currentSong = song;
           this.localMusic.videoUrl = song.filePath;
@@ -566,17 +549,8 @@ export struct LocalMusic {
           // 更新当前索引
           const currentIndex: number = this.localMusic.unifiedPlayerService.getCurrentIndex();
           this.localMusic.curIndex = currentIndex;
-
-          // 同步到AppStorage,确保卡片能获取到最新状态
-          AppStorage.setOrCreate('currentSong', song);
-          AppStorage.setOrCreate('currIndex', currentIndex);
-          AppStorage.setOrCreate('songList', this.localMusic.songList);
-
           // 更新最近播放时间
           this.localMusic.updateLastPlayTimeStr(song.filePath);
-
-          console.log(`Heanup onSongChanged - 歌曲切换完成: ${song.name} at index ${currentIndex}`);
-          LogUtils.getInstance().LOGI(`LocalMusic: Song synchronized - ${song.name} at index ${currentIndex} - oldSeconds=${this.localMusic.oldSeconds},currentTime=${this.localMusic.currentTime}`);
         }
 
         onProgressChanged(progress: PlayProgress): void {
@@ -588,8 +562,6 @@ export struct LocalMusic {
         }
 
         onError(error: PlayerError): void {
-          LogUtils.getInstance().LOGI(`UnifiedPlayerService error in LocalMusic: ${error.message}`);
-          ToastUtil.showToast(`播放错误: ${error.message}`);
           this.localMusic.handlePlaybackError();
         }
       }
@@ -664,10 +636,6 @@ export struct LocalMusic {
         }
       }
 
-      // 同步播放列表和当前索引到AppStorage,确保卡片能访问
-      AppStorage.setOrCreate('songList', this.songList);
-      AppStorage.setOrCreate('currIndex', this.curIndex);
-
       if (ArrayUtil.isNotEmpty(this.songList)) {
         this.isFirstStartPlay = true
         this.sonDataSource.pushArrayData(this.songList)
@@ -679,11 +647,6 @@ export struct LocalMusic {
         this.name = this.currentSong.name
         this.cover = this.currentSong.pixelMapPath
         this.artist = this.currentSong.artist
-
-        // 同步当前歌曲到AppStorage
-        AppStorage.setOrCreate('currentSong', this.currentSong);
-
-        LogUtils.getInstance().LOGI(`LocalMusic: Playlist restored - ${this.songList.length} songs, current: ${this.currentSong.name}`);
       }
     });
   }
@@ -1378,15 +1341,11 @@ export struct LocalMusic {
         // 避免在文件列表更新时破坏用户的播放列表
         if (ArrayUtil.isEmpty(this.songList) && ArrayUtil.isNotEmpty(globalVideoList)) {
           this.songList = globalVideoList;
-          AppStorage.setOrCreate('songList', this.songList);
           this.sonDataSource.pushArrayData(this.songList);
 
           // 同步到统一播放器服务进行持久化
           this.syncPlaylistToService();
 
-          LogUtils.getInstance().LOGI(`LocalMusic: updateListData - Created initial playlist with ${this.songList.length} songs`);
-        } else {
-          LogUtils.getInstance().LOGI(`LocalMusic: updateListData - Preserving existing playlist with ${this.songList.length} songs, current directory has ${globalVideoList.length} songs`);
         }
       }
 
@@ -4782,7 +4741,6 @@ export struct LocalMusic {
         break;
       case CommonConstants.TYPE_IS_CSJAD:
         return
-        break;
       case CommonConstants.TYPE_LOCAL:
         // 移除自动停止逻辑,让UnifiedPlayerService处理播放器状态管理
         // if (this.CONTROL_PlayStatus !== PlayStatus.INIT) {
@@ -4794,7 +4752,6 @@ export struct LocalMusic {
           if (index !== undefined) {
             this.curIndex = index
           }
-          LogUtils.getInstance().LOGI(`LocalMusic: doPlay from playlist - song: ${item.name}, index: ${index}`);
         } else {
           // 点击文件列表中的歌曲,需要判断是否要创建新的播放列表
           let globalVideoList = Utility.getGlobalList(this.videoLocalList, CommonConstants.TYPE_LOCAL) as VideoItem[];
@@ -4807,20 +4764,13 @@ export struct LocalMusic {
             // 如果当前播放列表已经包含这首歌,使用现有播放列表
             this.curIndex = currentSongIndex;
             this.currentSong = this.songList[this.curIndex];
-            LogUtils.getInstance().LOGI(`LocalMusic: doPlay - Found song in existing playlist at index ${this.curIndex}, keeping playlist with ${this.songList.length} songs`);
           } else {
             // 如果当前播放列表不包含这首歌,或者没有播放列表,则创建新的
             this.songList = globalVideoList;
             this.sonDataSource.pushArrayData(this.songList);
             this.currentSong = globalVideoList[this.curIndex];
-            LogUtils.getInstance().LOGI(`LocalMusic: doPlay - Created new playlist with ${this.songList.length} songs, current song: ${this.currentSong.name}`);
           }
         }
-
-        AppStorage.setOrCreate('currentSong',this.currentSong) ;
-        AppStorage.setOrCreate('songList', this.songList);
-        AppStorage.setOrCreate('currIndex', this.curIndex);
-
         this.videoUrl = this.currentSong.filePath
         this.name = this.currentSong.name
         this.cover = this.currentSong.pixelMapPath
@@ -4832,14 +4782,8 @@ export struct LocalMusic {
         this.lastSongPath = this.currentSong.filePath;
         this.justSwitched = true; // 标记歌曲刚刚切换
 
-        console.log(`Heanup doPlay - 重置时间显示状态: oldSeconds=${this.oldSeconds}, currentTime=${this.currentTime}`);
-
         // 同步播放列表到UnifiedPlayerService
         this.syncPlaylistToService();
-
-        LogUtil.info('this.currentSong.duration =' + this.currentSong.duration)
-        LogUtil.info('this.currentSong.sampleRate =' + this.currentSong.sampleRate)
-        LogUtil.info('this.currentSongmimeType =' + this.currentSong.mimeType)
         this.startPlayOrResumePlay()
         break;
 
@@ -5963,14 +5907,7 @@ export struct LocalMusic {
 
       // 更新当前索引
       this.curIndex = Utility.getIndexFromList(this.songList, this.videoUrl);
-
-      // 同步到AppStorage
-      AppStorage.setOrCreate('songList', this.songList);
-      AppStorage.setOrCreate('currIndex', this.curIndex);
-
-      LogUtils.getInstance().LOGI(`LocalMusic: Moved song from ${index} to ${newIndex} via UnifiedPlayerService`);
     } catch (error) {
-      LogUtils.getInstance().LOGI(`LocalMusic itemMoveSon error: ${error}`);
 
       // 错误处理:回退到原有逻辑
       let tmp = this.songList.splice(index, 1);
@@ -9987,7 +9924,6 @@ export struct LocalMusic {
       this.startPipLyric()
       this.mDestroyPage = false;
       this.animationState = AnimationStatus.Running
-      LogUtils.getInstance().LOGI("startPlayOrResumePlay start this.CONTROL_PlayStatus:" + this.CONTROL_PlayStatus)
 
       // 智能同步播放列表到UnifiedPlayerService
       if (ArrayUtil.isNotEmpty(this.songList)) {
@@ -9998,7 +9934,6 @@ export struct LocalMusic {
         if (ArrayUtil.isEmpty(servicePlaylist)) {
           // 如果服务没有播放列表,使用LocalMusic的播放列表
           this.unifiedPlayerService.setPlaylist(this.songList, this.curIndex);
-          LogUtils.getInstance().LOGI(`LocalMusic: Set playlist to UnifiedPlayerService - ${this.songList.length} songs, index ${this.curIndex}`);
         } else {
           // 如果服务已有播放列表,同步服务的状态到LocalMusic
           const serviceSong = this.unifiedPlayerService.getCurrentSong();
@@ -10013,13 +9948,6 @@ export struct LocalMusic {
             this.name = serviceSong.name;
             this.artist = serviceSong.artist;
             this.cover = serviceSong.pixelMapPath;
-            
-            // 同步到AppStorage
-            AppStorage.setOrCreate('songList', this.songList);
-            AppStorage.setOrCreate('currIndex', this.curIndex);
-            AppStorage.setOrCreate('currentSong', this.currentSong);
-            
-            LogUtils.getInstance().LOGI(`LocalMusic: Synced from UnifiedPlayerService - ${this.songList.length} songs, index ${this.curIndex}, song: ${serviceSong.name}`);
           }
         }
       }
@@ -10117,16 +10045,10 @@ export struct LocalMusic {
         this.artist = currentSong.artist;
         this.cover = currentSong.pixelMapPath;
 
-        // 同步到AppStorage
-        AppStorage.setOrCreate('songList', this.songList);
-        AppStorage.setOrCreate('currIndex', this.curIndex);
-        AppStorage.setOrCreate('currentSong', currentSong);
 
       }
 
-      LogUtils.getInstance().LOGI(`LocalMusic: playSongAtIndex ${index} completed via UnifiedPlayerService`);
     } catch (error) {
-      LogUtils.getInstance().LOGI(`LocalMusic playSongAtIndex error: ${error}`);
       ToastUtil.showToast(`播放歌曲失败: ${error}`);
 
       // 错误处理:回退到原有逻辑
@@ -10143,7 +10065,11 @@ export struct LocalMusic {
         const caller = stack.split('\n')[2] || 'Unknown caller';
 
         this.unifiedPlayerService.setPlaylist(this.songList, this.curIndex);
-        LogUtils.getInstance().LOGI(`LocalMusic: Playlist synced to UnifiedPlayerService - ${this.songList.length} songs, caller: ${caller.trim()}`);
+        
+        // 同步播放模式到UnifiedPlayerService
+        this.unifiedPlayerService.setPlayMode(this.playType);
+        
+        LogUtils.getInstance().LOGI(`LocalMusic: Playlist and play mode synced to UnifiedPlayerService - ${this.songList.length} songs, mode: ${this.playType}, caller: ${caller.trim()}`);
 
         // 如果同步的是小播放列表,记录更多信息
         if (this.songList.length <= 20) {
@@ -10171,16 +10097,10 @@ export struct LocalMusic {
         // 更新当前索引
         this.curIndex = this.unifiedPlayerService.getCurrentIndex();
 
-        // 同步到AppStorage
-        AppStorage.setOrCreate('songList', this.songList);
-        AppStorage.setOrCreate('currIndex', this.curIndex);
-
         ToastUtil.showToast(`已移除 ${removedSong.name}`);
 
-        LogUtils.getInstance().LOGI(`LocalMusic: Removed song at index ${index} via UnifiedPlayerService - ${removedSong.name}`);
       }
     } catch (error) {
-      LogUtils.getInstance().LOGI(`LocalMusic removeFromPlaylistViaService error: ${error}`);
 
       // 错误处理:回退到原有逻辑
       if (index >= 0 && index < this.songList.length) {
@@ -11540,14 +11460,9 @@ export struct LocalMusic {
       this.songList = [...this.songList]; // 触发状态更新
       this.sonDataSource.pushArrayData(this.songList);
 
-      // 同步到AppStorage
-      AppStorage.setOrCreate('songList', this.songList);
-
       ToastUtil.showToast('已添加至下一首播放')
 
-      LogUtils.getInstance().LOGI(`LocalMusic: Added song to next play via UnifiedPlayerService - ${song.name}`);
     } catch (error) {
-      LogUtils.getInstance().LOGI(`LocalMusic addToNextPlay error: ${error}`);
 
       // 错误处理:回退到原有逻辑
       const insertPos = this.curIndex + 1;
@@ -11565,11 +11480,8 @@ export struct LocalMusic {
     }
 
     try {
-      if (this.playType == 3) { //3:随机播放
-        this.randomPlay()
-        return;
-      }
-
+      // 移除了随机播放的特殊处理,统一使用UnifiedPlayerService
+      // 这样可以确保所有播放模式的状态都保持一致
       if (ArrayUtil.isNotEmpty(this.songList)) {
         // 如果正在投播,需要特殊处理
         if (this.isCurrentlyCasting()) {
@@ -11577,8 +11489,9 @@ export struct LocalMusic {
           return;
         }
 
-        // 使用UnifiedPlayerService播放下一首
+        // 使用UnifiedPlayerService播放下一首,支持所有播放模式(包括随机播放)
         await this.unifiedPlayerService.playNext();
+        
         // 智能同步播放列表到UnifiedPlayerService
         const servicePlaylist = this.unifiedPlayerService.getPlaylist();
         const serviceIndex = this.unifiedPlayerService.getCurrentIndex();
@@ -11586,7 +11499,6 @@ export struct LocalMusic {
         if (ArrayUtil.isEmpty(servicePlaylist)) {
           // 如果服务没有播放列表,使用LocalMusic的播放列表
           this.unifiedPlayerService.setPlaylist(this.songList, this.curIndex);
-          LogUtils.getInstance().LOGI(`LocalMusic playNext: Set playlist to UnifiedPlayerService - ${this.songList.length} songs, index ${this.curIndex}`);
         } else {
           // 如果服务已有播放列表,检查是否需要同步
           const serviceSong = this.unifiedPlayerService.getCurrentSong();
@@ -11596,17 +11508,9 @@ export struct LocalMusic {
             this.curIndex = serviceIndex;
             this.currentSong = serviceSong;
             this.sonDataSource.pushArrayData(this.songList);
-
-            // 同步到AppStorage
-            AppStorage.setOrCreate('songList', this.songList);
-            AppStorage.setOrCreate('currIndex', this.curIndex);
-            AppStorage.setOrCreate('currentSong', this.currentSong);
-            
-            LogUtils.getInstance().LOGI(`LocalMusic playNext: Synced from UnifiedPlayerService - ${this.songList.length} songs, index ${this.curIndex}, song: ${serviceSong.name}`);
           }
         }
 
-
         // 更新本地状态以保持UI同步
         const currentIndex = this.unifiedPlayerService.getCurrentIndex();
         const currentSong = this.unifiedPlayerService.getCurrentSong();
@@ -11624,15 +11528,12 @@ export struct LocalMusic {
           this.currentTime = "00:00";
           this.lastSongPath = currentSong.filePath;
           this.justSwitched = true; // 标记歌曲刚刚切换
-          console.log(`Heanup playNext - 重置时间显示状态: oldSeconds=${this.oldSeconds}, currentTime=${this.currentTime}`);
 
           this.changeImageAnimation();
         }
 
-        LogUtils.getInstance().LOGI("LocalMusic: playNext completed via UnifiedPlayerService");
       }
     } catch (error) {
-      LogUtils.getInstance().LOGI(`LocalMusic playNext error: ${error}`);
       ToastUtil.showToast(`切换下一首失败: ${error}`);
 
       // 错误处理:回退到原有逻辑
@@ -11651,9 +11552,6 @@ export struct LocalMusic {
         this.curIndex++;
       }
 
-      AppStorage.setOrCreate('songList', this.songList);
-      AppStorage.setOrCreate('currIndex', this.curIndex);
-
       this.CONTROL_PlayStatus = PlayStatus.INIT;
       this.stop();
       this.currentSong = this.songList[this.curIndex]
@@ -11781,11 +11679,8 @@ export struct LocalMusic {
     }
 
     try {
-      if (this.playType == 3) { //3:随机播放的上一首应该应该播放历史记录的第二首
-        this.randomModePlayFromHistory()
-        return;
-      }
-
+      // 移除了随机播放的特殊处理,统一使用UnifiedPlayerService
+      // 这样可以确保所有播放模式的状态都保持一致
       if (ArrayUtil.isNotEmpty(this.songList)) {
         // 如果正在投播,需要特殊处理
         if (this.isCurrentlyCasting()) {
@@ -11793,14 +11688,13 @@ export struct LocalMusic {
           return;
         }
 
-        // 使用UnifiedPlayerService播放上一首
+        // 使用UnifiedPlayerService播放上一首,支持所有播放模式(包括随机播放)
         await this.unifiedPlayerService.playPrevious();
 
         // 智能同步播放列表到UnifiedPlayerService
         const servicePlaylist = this.unifiedPlayerService.getPlaylist();
         const serviceIndex = this.unifiedPlayerService.getCurrentIndex();
 
-
         // 更新本地状态以保持UI同步
         const currentIndex = this.unifiedPlayerService.getCurrentIndex();
         const currentSong = this.unifiedPlayerService.getCurrentSong();
@@ -11818,20 +11712,12 @@ export struct LocalMusic {
           this.currentTime = "00:00";
           this.lastSongPath = currentSong.filePath;
           this.justSwitched = true; // 标记歌曲刚刚切换
-          console.log(`Heanup playPrevious - 重置时间显示状态: oldSeconds=${this.oldSeconds}, currentTime=${this.currentTime}`);
-
-          // 同步到AppStorage,确保卡片能获取到最新状态
-          AppStorage.setOrCreate('songList', this.songList);
-          AppStorage.setOrCreate('currIndex', this.curIndex);
-          AppStorage.setOrCreate('currentSong', currentSong);
 
           this.changeImageAnimation();
         }
       }
 
-      LogUtils.getInstance().LOGI("LocalMusic: playPrevious completed via UnifiedPlayerService");
     } catch (error) {
-      LogUtils.getInstance().LOGI(`LocalMusic playPrevious error: ${error}`);
       ToastUtil.showToast(`切换上一首失败: ${error}`);
 
       // 错误处理:回退到原有逻辑
@@ -11849,9 +11735,6 @@ export struct LocalMusic {
       this.curIndex--;
     }
 
-    AppStorage.setOrCreate('songList', this.songList);
-    AppStorage.setOrCreate('currIndex', this.curIndex);
-
     this.CONTROL_PlayStatus = PlayStatus.INIT;
     this.stop();
     this.currentSong = this.songList[this.curIndex]