Sfoglia il codice sorgente

支持桌面卡片点击收藏同步到UI

chendeben 1 anno fa
parent
commit
795c9db6fe

+ 256 - 55
entry/src/main/ets/common/service/UnifiedPlayerService.ets

@@ -15,6 +15,7 @@ import { formProvider, formBindingData } from '@kit.FormKit';
 import { fileIo } from '@kit.CoreFileKit';
 import { fileIo } from '@kit.CoreFileKit';
 import { BusinessError } from '@kit.BasicServicesKit';
 import { BusinessError } from '@kit.BasicServicesKit';
 import { http } from '@kit.NetworkKit';
 import { http } from '@kit.NetworkKit';
+import { util } from '@kit.ArkTS';
 import json from '@ohos.util.json';
 import json from '@ohos.util.json';
 import MediaTable from '../util/MediaTable';
 import MediaTable from '../util/MediaTable';
 import { Utility } from '../util/Utility';
 import { Utility } from '../util/Utility';
@@ -79,6 +80,15 @@ export interface WidgetTimeInfo {
   progressPercentage: number;
   progressPercentage: number;
 }
 }
 
 
+/**
+ * 缓存文件信息接口
+ */
+export interface CacheFileInfo {
+  path: string;
+  size: number;
+  mtime: number;
+}
+
 /**
 /**
  * 卡片数据接口
  * 卡片数据接口
  */
  */
@@ -302,6 +312,13 @@ export interface IPlayerService {
    * 强制刷新收藏状态(用于收藏/取消收藏操作后)
    * 强制刷新收藏状态(用于收藏/取消收藏操作后)
    */
    */
   refreshFavoriteStatus(): Promise<void>;
   refreshFavoriteStatus(): Promise<void>;
+
+
+  /**
+   * 获取收藏列表
+   * @returns 收藏列表
+   */
+  getFav(): Array<VideoItem>;
 }
 }
 
 
 /**
 /**
@@ -380,6 +397,11 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
   private autoPlayDebounceMs: number = 1000; // 自动播放防抖间隔(毫秒)
   private autoPlayDebounceMs: number = 1000; // 自动播放防抖间隔(毫秒)
   private isManualSongChange: boolean = false; // 新增:是否正在进行手动歌曲切换
   private isManualSongChange: boolean = false; // 新增:是否正在进行手动歌曲切换
 
 
+  // 图片缓存相关属性
+  private imageCacheDir: string = ''; // 图片缓存目录
+  private readonly CACHE_EXPIRY_DAYS: number = 7; // 缓存有效期:7天
+  private readonly MAX_CACHE_SIZE_MB: number = 50; // 最大缓存大小:50MB
+
   private constructor() {
   private constructor() {
     this.playerManager = PlayerManager.getInstance();
     this.playerManager = PlayerManager.getInstance();
     this.stateModel = new PlayerStateModel();
     this.stateModel = new PlayerStateModel();
@@ -407,6 +429,9 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
       console.log("Heanup2 UnifiedPlayerService: 开始快速初始化服务");
       console.log("Heanup2 UnifiedPlayerService: 开始快速初始化服务");
       this.context = context;
       this.context = context;
 
 
+      // 初始化图片缓存目录
+      await this.initImageCacheDirectory();
+
       // 快速初始化核心组件
       // 快速初始化核心组件
       this.playerManager.setStateCallback(this);
       this.playerManager.setStateCallback(this);
 
 
@@ -580,7 +605,7 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
     // 同步更新所有桌面卡片状态
     // 同步更新所有桌面卡片状态
     this.updateAllForms();
     this.updateAllForms();
   }
   }
-  public toggleFavorite() {
+  public async toggleFavorite(): Promise<void> {
 
 
     let isFav = 0
     let isFav = 0
     let item=this.getCurrentSong() as VideoItem;
     let item=this.getCurrentSong() as VideoItem;
@@ -589,13 +614,22 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
     } else {
     } else {
       isFav = 1
       isFav = 1
     }
     }
-    this.getTable().updateIsFavByFilePath(item.filePath, isFav, async (result: boolean) => {
-      if (result) {
-        // 刷新UnifiedPlayerService的收藏状态,这会自动更新AVSession
-        console.log("Heanup2  UnifiedPlayerService toggleFavorite: 收藏状态切换");
-        await this.refreshFavoriteStatus();
-      }
-    })
+
+    return new Promise<void>((resolve) => {
+      this.getTable().updateIsFavByFilePath(item.filePath, isFav, async (result: boolean) => {
+        if (result) {
+          // 刷新UnifiedPlayerService的收藏状态,这会自动更新AVSession
+          console.log("Heanup2  UnifiedPlayerService toggleFavorite: 收藏状态切换");
+          await this.refreshFavoriteStatus();
+
+          // 立即更新桌面卡片状态,确保收藏图标正确显示
+          await this.updateAllForms(true);
+
+          console.log("Heanup2  UnifiedPlayerService toggleFavorite: 收藏状态和卡片状态更新完成");
+        }
+        resolve();
+      })
+    });
   }
   }
 
 
   /**
   /**
@@ -1077,7 +1111,11 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
       // 清空缓存,强制重新加载
       // 清空缓存,强制重新加载
       this.favList = [];
       this.favList = [];
       await this.updateFavoriteList();
       await this.updateFavoriteList();
-      LogUtils.getInstance().LOGI('UnifiedPlayerService: Favorite status refreshed');
+
+      // 触发状态变化通知,确保LocalMusic UI能收到收藏状态变化
+      this.stateModel.forceNotifyStateChanged();
+
+      LogUtils.getInstance().LOGI('UnifiedPlayerService: Favorite status refreshed and state change notified');
     } catch (error) {
     } catch (error) {
       LogUtils.getInstance().LOGI(`UnifiedPlayerService: Failed to refresh favorite status: ${error}`);
       LogUtils.getInstance().LOGI(`UnifiedPlayerService: Failed to refresh favorite status: ${error}`);
     }
     }
@@ -2771,44 +2809,43 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
 
 
           // 判断是否为网络图片
           // 判断是否为网络图片
           if (formData.pixelMapPath.startsWith('http://') || formData.pixelMapPath.startsWith('https://')) {
           if (formData.pixelMapPath.startsWith('http://') || formData.pixelMapPath.startsWith('https://')) {
-            // 处理网络图片:下载到临时文件
-            LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Downloading network image ${formData.pixelMapPath}`);
-
-            const tempDir = this.context?.getApplicationContext().tempDir;
-            if (!tempDir) {
-              LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: No temp directory available for network image`);
-            } else {
-              const tempFileName = imgName + '.tmp';
-              const tempFilePath = tempDir + '/' + tempFileName;
-
-              // 创建HTTP请求下载图片
-              const httpRequest = http.createHttp();
-              try {
-                const response = await httpRequest.request(formData.pixelMapPath, {
-                  method: http.RequestMethod.GET,
-                  connectTimeout: 5000, // 5秒超时,避免卡片更新被阻塞
-                  readTimeout: 5000
-                });
-
-                if (response.responseCode === http.ResponseCode.OK && response.result) {
-                  // 将下载的图片数据写入临时文件
-                  const tempFile = fileIo.openSync(tempFilePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
+            // 处理网络图片:使用缓存机制
+            LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Processing network image ${formData.pixelMapPath}`);
+
+            if (this.imageCacheDir) {
+              const cacheFileName = this.generateCacheFileName(formData.pixelMapPath);
+              const cacheFilePath = this.imageCacheDir + '/' + cacheFileName;
+
+              // 检查缓存是否存在且有效
+              if (await this.isCacheValid(cacheFilePath)) {
+                // 使用缓存文件
+                LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Using cached image: ${cacheFilePath}`);
+                try {
+                  const file = fileIo.openSync(cacheFilePath, fileIo.OpenMode.READ_ONLY);
+                  imgMap[imgName] = file.fd;
+                  LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Opened cached image with fd ${file.fd}, imgName: ${imgName}`);
+                } catch (error) {
+                  LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Failed to open cached image: ${error}`);
+                }
+              } else {
+                // 下载到缓存
+                LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Downloading image to cache: ${cacheFilePath}`);
+                const downloadSuccess = await this.downloadImageToCache(formData.pixelMapPath, cacheFilePath);
 
 
+                if (downloadSuccess) {
                   try {
                   try {
-                    await fileIo.write(tempFile.fd, response.result as ArrayBuffer);
-                    imgMap[imgName] = tempFile.fd;
-
-                    LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Downloaded and opened network image ${formData.pixelMapPath} to ${tempFilePath} with fd ${tempFile.fd}, imgName: ${imgName}`);
-                  } catch (writeError) {
-                    fileIo.closeSync(tempFile);
-                    // throw  writeError;
+                    const file = fileIo.openSync(cacheFilePath, fileIo.OpenMode.READ_ONLY);
+                    imgMap[imgName] = file.fd;
+                    LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Opened downloaded image with fd ${file.fd}, imgName: ${imgName}`);
+                  } catch (error) {
+                    LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Failed to open downloaded image: ${error}`);
                   }
                   }
                 } else {
                 } else {
-                  LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Failed to download network image ${formData.pixelMapPath}: HTTP ${response.responseCode}`);
+                  LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Failed to download network image ${formData.pixelMapPath}`);
                 }
                 }
-              } finally {
-                httpRequest.destroy();
               }
               }
+            } else {
+              LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Image cache directory not available`);
             }
             }
           } else {
           } else {
             // 处理本地图片文件
             // 处理本地图片文件
@@ -2922,21 +2959,8 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
           const fd = imgMap[imgKey];
           const fd = imgMap[imgKey];
           if (typeof fd === 'number') {
           if (typeof fd === 'number') {
             // 关闭文件描述符
             // 关闭文件描述符
-            fileIo.closeSync( fd);
+            fileIo.closeSync(fd);
             LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Closed image file descriptor ${fd} for ${imgKey}`);
             LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Closed image file descriptor ${fd} for ${imgKey}`);
-
-            // 如果是网络图片的临时文件,尝试删除
-            if (tempDir && imgKey.startsWith('songCover_')) {
-              try {
-                const tempFilePath = tempDir + '/' + imgKey + '.tmp';
-                if (fileIo.accessSync(tempFilePath)) {
-                  fileIo.unlinkSync(tempFilePath);
-                  LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Deleted temp file ${tempFilePath}`);
-                }
-              } catch (deleteError) {
-                LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Failed to delete temp file for ${imgKey}: ${deleteError}`);
-              }
-            }
           }
           }
         }
         }
       } catch (error) {
       } catch (error) {
@@ -3266,5 +3290,182 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
 
 
   // ==================== 辅助方法 ====================
   // ==================== 辅助方法 ====================
 
 
+  /**
+   * 初始化图片缓存目录
+   */
+  private async initImageCacheDirectory(): Promise<void> {
+    try {
+      if (this.context) {
+        const cacheDir = this.context.getApplicationContext().cacheDir;
+        this.imageCacheDir = cacheDir + '/cover_images';
+
+        // 创建缓存目录
+        if (!fileIo.accessSync(this.imageCacheDir)) {
+          fileIo.mkdirSync(this.imageCacheDir);
+          LogUtils.getInstance().LOGI(`UnifiedPlayerService: Created image cache directory: ${this.imageCacheDir}`);
+        }
+
+        // 清理过期缓存
+        await this.cleanExpiredCache();
+      }
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Failed to initialize image cache directory: ${error}`);
+    }
+  }
+
+  /**
+   * 生成图片URL的哈希值作为缓存文件名
+   */
+  private generateCacheFileName(url: string): string {
+    try {
+      const textEncoder = new util.TextEncoder();
+      const data = textEncoder.encodeInto(url);
+
+      // 使用URL的简单哈希算法
+      let hash = 0;
+      for (let i = 0; i < data.byteLength; i++) {
+        const char = data[i];
+        hash = ((hash << 5) - hash) + char;
+        hash = hash & hash; // 转换为32位整数
+      }
+
+      return Math.abs(hash).toString(16) + '.jpg';
+    } catch (error) {
+      // 如果哈希生成失败,使用URL的简单替换方案
+      return url.replace(/[^a-zA-Z0-9]/g, '_').substring(0, 50) + '.jpg';
+    }
+  }
+
+  /**
+   * 检查缓存文件是否存在且未过期
+   */
+  private async isCacheValid(cacheFilePath: string): Promise<boolean> {
+    try {
+      if (!fileIo.accessSync(cacheFilePath)) {
+        return false;
+      }
+
+      const stat = fileIo.statSync(cacheFilePath);
+      const fileAge = Date.now() - stat.mtime;
+      const maxAge = this.CACHE_EXPIRY_DAYS * 24 * 60 * 60 * 1000; // 转换为毫秒
+
+      return fileAge < maxAge;
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Failed to check cache validity: ${error}`);
+      return false;
+    }
+  }
+
+  /**
+   * 下载网络图片到缓存
+   */
+  private async downloadImageToCache(url: string, cacheFilePath: string): Promise<boolean> {
+    try {
+      const httpRequest = http.createHttp();
+      try {
+        const response = await httpRequest.request(url, {
+          method: http.RequestMethod.GET,
+          connectTimeout: 10000, // 10秒超时
+          readTimeout: 10000
+        });
+
+        if (response.responseCode === http.ResponseCode.OK && response.result) {
+          const tempFile = fileIo.openSync(cacheFilePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
+
+          try {
+            await fileIo.write(tempFile.fd, response.result as ArrayBuffer);
+            fileIo.closeSync(tempFile.fd);
+
+            LogUtils.getInstance().LOGI(`UnifiedPlayerService: Downloaded image to cache: ${cacheFilePath}`);
+            return true;
+          } catch (writeError) {
+            fileIo.closeSync(tempFile.fd);
+            LogUtils.getInstance().LOGI(`UnifiedPlayerService: Write error: ${writeError}`);
+            return false;
+          }
+        } else {
+          LogUtils.getInstance().LOGI(`UnifiedPlayerService: Failed to download image ${url}: HTTP ${response.responseCode}`);
+          return false;
+        }
+      } finally {
+        httpRequest.destroy();
+      }
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Error downloading image to cache: ${error}`);
+      return false;
+    }
+  }
+
+  /**
+   * 清理过期缓存
+   */
+  private async cleanExpiredCache(): Promise<void> {
+    try {
+      if (!this.imageCacheDir || !fileIo.accessSync(this.imageCacheDir)) {
+        return;
+      }
+
+      const files = fileIo.listFileSync(this.imageCacheDir);
+      const maxAge = this.CACHE_EXPIRY_DAYS * 24 * 60 * 60 * 1000;
+      let totalSize = 0;
+      const fileInfos: Array<CacheFileInfo> = [];
+
+      // 收集文件信息
+      for (const file of files) {
+        const filePath = this.imageCacheDir + '/' + file;
+        try {
+          const stat = fileIo.statSync(filePath);
+          totalSize += stat.size;
+          const fileInfo: CacheFileInfo = {
+            path: filePath,
+            size: stat.size,
+            mtime: stat.mtime
+          };
+          fileInfos.push(fileInfo);
+        } catch (error) {
+          // 忽略无法读取的文件
+        }
+      }
+
+      // 删除过期文件
+      const now = Date.now();
+      for (const fileInfo of fileInfos) {
+        if (now - fileInfo.mtime > maxAge) {
+          try {
+            fileIo.unlinkSync(fileInfo.path);
+            totalSize -= fileInfo.size;
+            LogUtils.getInstance().LOGI(`UnifiedPlayerService: Deleted expired cache file: ${fileInfo.path}`);
+          } catch (error) {
+            LogUtils.getInstance().LOGI(`UnifiedPlayerService: Failed to delete expired cache file: ${error}`);
+          }
+        }
+      }
+
+      // 如果缓存大小超限,删除最旧的文件
+      const maxSizeBytes = this.MAX_CACHE_SIZE_MB * 1024 * 1024;
+      if (totalSize > maxSizeBytes) {
+        const sortedFiles = fileInfos
+          .filter(f => fileIo.accessSync(f.path)) // 只保留仍存在的文件
+          .sort((a, b) => a.mtime - b.mtime); // 按修改时间排序,最旧的在前
+
+        for (const fileInfo of sortedFiles) {
+          if (totalSize <= maxSizeBytes) break;
+
+          try {
+            fileIo.unlinkSync(fileInfo.path);
+            totalSize -= fileInfo.size;
+            LogUtils.getInstance().LOGI(`UnifiedPlayerService: Deleted cache file due to size limit: ${fileInfo.path}`);
+          } catch (error) {
+            LogUtils.getInstance().LOGI(`UnifiedPlayerService: Failed to delete cache file: ${error}`);
+          }
+        }
+      }
+
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Cache cleanup completed, total size: ${(totalSize / 1024 / 1024).toFixed(2)}MB`);
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Failed to clean expired cache: ${error}`);
+    }
+  }
+
 
 
 }
 }

+ 1 - 2
entry/src/main/ets/entryability/EntryAbility.ets

@@ -496,9 +496,8 @@ export default class EntryAbility extends UIAbility {
             this.callee.on("toggleFavorite",(data:rpc.MessageSequence)=>{
             this.callee.on("toggleFavorite",(data:rpc.MessageSequence)=>{
                 const params: Record<string, Object> = JSON.parse(data.readString()) as Record<string, Object>;
                 const params: Record<string, Object> = JSON.parse(data.readString()) as Record<string, Object>;
                 hilog.info(0x0000, 'Heanup2', `toggleFavorite handler`);
                 hilog.info(0x0000, 'Heanup2', `toggleFavorite handler`);
-                // 异步发送上一首事件到主应用(包含服务就绪检查)
                 this.sendWidgetControlEvent('toggleFavorite', params).catch((error: Error) => {
                 this.sendWidgetControlEvent('toggleFavorite', params).catch((error: Error) => {
-                    hilog.error(0x0000, 'Heanup2', `❌ prevSong async error: ${error}`);
+                    hilog.error(0x0000, 'Heanup2', `❌ toggleFavorite async error: ${error}`);
                 });
                 });
                 return new MyParcelable(-5, 'toggleFavorite');
                 return new MyParcelable(-5, 'toggleFavorite');
             })
             })

+ 49 - 11
entry/src/main/ets/view/LocalMusic.ets

@@ -555,7 +555,7 @@ export struct LocalMusic {
   public onPlayerStateChanged(state: PlayerState): void {
   public onPlayerStateChanged(state: PlayerState): void {
     try {
     try {
       LogUtils.getInstance().LOGI(`LocalMusic: Received state change from UnifiedPlayerService - isPlaying: ${state.isPlaying}, isPaused: ${state.isPaused}, currentIndex: ${state.currentIndex}`);
       LogUtils.getInstance().LOGI(`LocalMusic: Received state change from UnifiedPlayerService - isPlaying: ${state.isPlaying}, isPaused: ${state.isPaused}, currentIndex: ${state.currentIndex}`);
-      
+
       // 同步播放状态到UI
       // 同步播放状态到UI
       if (state.isPlaying !== undefined) {
       if (state.isPlaying !== undefined) {
         // 根据播放状态更新UI播放按钮状态
         // 根据播放状态更新UI播放按钮状态
@@ -578,6 +578,9 @@ export struct LocalMusic {
         this.curIndex = state.currentIndex;
         this.curIndex = state.currentIndex;
       }
       }
 
 
+      // 同步收藏状态(每次状态变化时都检查,确保UI收藏状态是最新的)
+      this.syncFavoriteStateFromService();
+
       LogUtils.getInstance().LOGI('LocalMusic: UI state synchronized with UnifiedPlayerService');
       LogUtils.getInstance().LOGI('LocalMusic: UI state synchronized with UnifiedPlayerService');
     } catch (error) {
     } catch (error) {
       LogUtils.getInstance().LOGI(`LocalMusic: Error handling state change: ${error}`);
       LogUtils.getInstance().LOGI(`LocalMusic: Error handling state change: ${error}`);
@@ -591,14 +594,17 @@ export struct LocalMusic {
   public onPlayerSongChanged(song: VideoItem): void {
   public onPlayerSongChanged(song: VideoItem): void {
     try {
     try {
       LogUtils.getInstance().LOGI(`LocalMusic: Received song change from UnifiedPlayerService - ${song.name}`);
       LogUtils.getInstance().LOGI(`LocalMusic: Received song change from UnifiedPlayerService - ${song.name}`);
-      
+
       // 同步当前歌曲信息到UI
       // 同步当前歌曲信息到UI
       this.currentSong = song;
       this.currentSong = song;
       this.videoUrl = song.filePath;
       this.videoUrl = song.filePath;
       this.name = song.name;
       this.name = song.name;
       this.artist = song.artist || this.UNKONWN;
       this.artist = song.artist || this.UNKONWN;
       this.cover = song.pixelMapPath;
       this.cover = song.pixelMapPath;
-      
+
+      // 同步收藏状态到UI
+      this.syncFavoriteStateFromService();
+
       // 重置时间显示状态
       // 重置时间显示状态
       this.oldSeconds = 0;
       this.oldSeconds = 0;
       this.currentTime = "00:00";
       this.currentTime = "00:00";
@@ -622,7 +628,7 @@ export struct LocalMusic {
   public onPlayerError(error: PlayerError): void {
   public onPlayerError(error: PlayerError): void {
     try {
     try {
       LogUtils.getInstance().LOGI(`LocalMusic: Received error from UnifiedPlayerService - ${error.type}: ${error.message}`);
       LogUtils.getInstance().LOGI(`LocalMusic: Received error from UnifiedPlayerService - ${error.type}: ${error.message}`);
-      
+
       // 根据错误类型显示不同的提示
       // 根据错误类型显示不同的提示
       switch (error.type) {
       switch (error.type) {
         case PlayerErrorType.FILE_NOT_FOUND:
         case PlayerErrorType.FILE_NOT_FOUND:
@@ -638,13 +644,45 @@ export struct LocalMusic {
           ToastUtil.showToast(`播放器错误: ${error.message}`);
           ToastUtil.showToast(`播放器错误: ${error.message}`);
           break;
           break;
       }
       }
-      
+
       LogUtils.getInstance().LOGI('LocalMusic: Error handled and user notified');
       LogUtils.getInstance().LOGI('LocalMusic: Error handled and user notified');
     } catch (error) {
     } catch (error) {
       LogUtils.getInstance().LOGI(`LocalMusic: Error handling player error: ${error}`);
       LogUtils.getInstance().LOGI(`LocalMusic: Error handling player error: ${error}`);
     }
     }
   }
   }
 
 
+  /**
+   * 从UnifiedPlayerService同步收藏状态到LocalMusic UI
+   */
+  private async syncFavoriteStateFromService(): Promise<void> {
+    try {
+      if (this.currentSong && this.unifiedPlayerService) {
+        // 获取UnifiedPlayerService中的收藏状态
+        const favList = this.unifiedPlayerService.getFav();
+        const isFavorite = Utility.getIsFav(favList, this.currentSong);
+
+        // 更新LocalMusic的收藏状态UI
+        // 先更新收藏列表和其他UI
+        this.deleteCache(this.currentPath)
+        this.getFavList(false)
+        if (this.modeType === 0 && !this.isFavMusic) {
+          LogUtil.info('onecold doFav currentPath =' + this.currentPath)
+          this.getSortedFiles(this.currentPath)
+        }
+        workerInstance.postMessage({ code: 2, data: this.context });
+        workerInstance.postMessage({ code: 3, data: this.context });
+        workerInstance.postMessage({ code: 4, data: this.context });
+
+        // 刷新UnifiedPlayerService的收藏状态,这会自动更新AVSession
+        // await this.unifiedPlayerService.refreshFavoriteStatus();
+
+        LogUtils.getInstance().LOGI(`LocalMusic: 收藏状态已同步 - ${this.currentSong.name}: ${isFavorite ? '已收藏' : '未收藏'}`);
+      }
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`LocalMusic: 同步收藏状态失败: ${error}`);
+    }
+  }
+
   // ==================== 组件生命周期 ====================
   // ==================== 组件生命周期 ====================
 
 
   // 组件生命周期
   // 组件生命周期
@@ -759,9 +797,9 @@ export struct LocalMusic {
         let viewHeight = px2vp(size.height);
         let viewHeight = px2vp(size.height);
         if(this.isPhoneLan()){
         if(this.isPhoneLan()){
           this.is_auto_hide_progress = false
           this.is_auto_hide_progress = false
-        if(this.isHiCar()){
-          return
-        }
+          if(this.isHiCar()){
+            return
+          }
           setTimeout(() => {
           setTimeout(() => {
             this.is_auto_hide_progress = true
             this.is_auto_hide_progress = true
           }, 6000)
           }, 6000)
@@ -4009,8 +4047,8 @@ export struct LocalMusic {
             })
             })
             .draggable(false)
             .draggable(false)
             .opacity(this.opacityItem)// 绑定透明度
             .opacity(this.opacityItem)// 绑定透明度
-            // .transition(TransitionEffect.move(TransitionEdge.BOTTOM)
-            //   .animation({ duration: 500, curve: Curve.Ease }))
+              // .transition(TransitionEffect.move(TransitionEdge.BOTTOM)
+              //   .animation({ duration: 500, curve: Curve.Ease }))
             .animation({
             .animation({
               duration: 666,
               duration: 666,
               curve: 'ease-in-out' // 可选动画曲线
               curve: 'ease-in-out' // 可选动画曲线
@@ -4231,7 +4269,7 @@ export struct LocalMusic {
   MenuBuilder(item: VideoItem, index: number, filePath: string) {
   MenuBuilder(item: VideoItem, index: number, filePath: string) {
     if(
     if(
       ((this.modeType===2||this.modeType==3)&&!this.isCanBack)
       ((this.modeType===2||this.modeType==3)&&!this.isCanBack)
-      ||(item.name === LocalMusic.STR_LOCK_VIDEO || item.name === LocalMusic.STR_FAC_VIDEO ||
+        ||(item.name === LocalMusic.STR_LOCK_VIDEO || item.name === LocalMusic.STR_FAC_VIDEO ||
         item.name === LocalMusic.STR_HISTORY_MUSIC)
         item.name === LocalMusic.STR_HISTORY_MUSIC)
     ){
     ){
       //如果是专辑和艺术家的首页,不能长按
       //如果是专辑和艺术家的首页,不能长按