Quellcode durchsuchen

修复懒加载未及时更新封面的问题

chendeben vor 9 Monaten
Ursprung
Commit
b6f0f656ff

+ 5 - 0
entry/src/main/ets/common/constants/EventConstants.ets

@@ -53,4 +53,9 @@ export class EventConstants {
 
   // 播放暂停事件(比如hicar断开后,手机不播放了)
   static readonly EVENT_PLAY_PAUSE: number = 2005;
+
+  /**
+   * WebDAV 元数据同步事件
+   */
+  static readonly EVENT_WEBDAV_METADATA_UPDATED: number = 3001;
 }

+ 147 - 1
entry/src/main/ets/pages/WebDavMainPage.ets

@@ -32,6 +32,13 @@ interface PlaylistEventData {
   // 移除webDavAuthInfo,现在直接使用videoItems中的webdav_account_id
 }
 
+interface WebDavMetadataUpdatePayload {
+  filePath: string;
+  pixelMapPath?: string;
+  name?: string;
+  artist?: string;
+}
+
 const TAG = 'heanup WebDavMainPage';
 
 // WebDAV歌曲数据全局内存存储
@@ -92,6 +99,8 @@ export struct WebDavMainPage {
   @State isShowFileName: boolean = false//是否显示文件名
   @State isLongNameRoLL: boolean = true//长歌名滚动
   @State sortType: number = 0 //默认排序方式
+  @State listRefreshKey: number = 0 // 列表刷新标识
+  private readonly metadataUpdateEvent: emitter.InnerEvent = { eventId: EventConstants.EVENT_WEBDAV_METADATA_UPDATED };
 
   async onSwitchAccount(){
     console.log('onecold 切换账户:', this.selectedAccount.name);
@@ -199,6 +208,7 @@ export struct WebDavMainPage {
 
     // 订阅WebDAV状态变化
     this.webdavManager.subscribe(this.eventHandler);
+    this.subscribeWebDavMetadataUpdates();
   }
 
   // 获取顶部安全区高度
@@ -217,6 +227,7 @@ export struct WebDavMainPage {
   aboutToDisappear(): void {
     // 取消订阅
     this.webdavManager.unsubscribe(this.eventHandler);
+    emitter.off(EventConstants.EVENT_WEBDAV_METADATA_UPDATED);
   }
 
   // 处理WebDAV事件
@@ -249,6 +260,141 @@ export struct WebDavMainPage {
     }
   }
 
+  private subscribeWebDavMetadataUpdates(): void {
+    emitter.on(this.metadataUpdateEvent, (eventData: emitter.EventData) => {
+      const payloads = eventData?.data as WebDavMetadataUpdatePayload[] | undefined;
+      if (!payloads || payloads.length === 0) {
+        Logger.info(TAG, 'WebDav metadata event received but payload empty');
+        return;
+      }
+      Logger.info(TAG, `WebDav metadata event payload count: ${payloads.length}`);
+      this.handleWebDavMetadataUpdates(payloads);
+    });
+  }
+
+  private handleWebDavMetadataUpdates(payloads: WebDavMetadataUpdatePayload[]): void {
+    if (!payloads || payloads.length === 0) {
+      return;
+    }
+    Logger.info(TAG, 'handleWebDavMetadataUpdates start');
+    let hasChanges = false;
+    for (let i = 0; i < payloads.length; i++) {
+      const payload = payloads[i];
+      if (!payload || !payload.filePath) {
+        continue;
+      }
+      Logger.info(TAG, `WebDav metadata detail path=${payload.pixelMapPath ?? 'null'}`);
+      const songUpdated = this.updateSongMetadata(payload);
+      if (songUpdated) {
+        hasChanges = true;
+        Logger.info(TAG, `metadata updated for ${payload.filePath}`);
+      }
+    }
+    if (!hasChanges) {
+      Logger.info(TAG, 'handleWebDavMetadataUpdates no changes detected');
+      return;
+    }
+    const clonedSongs: VideoItem[] = [];
+    for (let i = 0; i < this.songs.length; i++) {
+      clonedSongs.push(this.cloneSong(this.songs[i]));
+    }
+    this.songs = clonedSongs;
+    this.dataSource.pushArrayData(clonedSongs);
+    this.listRefreshKey++;
+    Logger.info(TAG, 'handleWebDavMetadataUpdates trigger refresh');
+  }
+
+  private updateSongMetadata(payload: WebDavMetadataUpdatePayload): boolean {
+    if (!payload.filePath) {
+      return false;
+    }
+    const targetIndex = this.findSongIndex(payload.filePath);
+    if (targetIndex < 0) {
+      return false;
+    }
+    const targetSong = this.songs[targetIndex];
+    let mutated = false;
+    if (payload.pixelMapPath && payload.pixelMapPath.length > 0) {
+      targetSong.pixelMapPath = payload.pixelMapPath;
+      mutated = true;
+    }
+    if (payload.name && payload.name.length > 0) {
+      targetSong.name = payload.name;
+      mutated = true;
+    }
+    if (payload.artist && payload.artist.length > 0) {
+      targetSong.artist = payload.artist;
+      mutated = true;
+    }
+    return mutated;
+  }
+
+  private findSongIndex(filePath: string): number {
+    for (let i = 0; i < this.songs.length; i++) {
+      if (this.songs[i].filePath === filePath) {
+        return i;
+      }
+    }
+    return -1;
+  }
+
+  private cloneSong(item: VideoItem): VideoItem {
+    const clone = new VideoItem(
+      item.name,
+      item.id,
+      item.filePath,
+      item.type,
+      item.videoSize,
+      item.cTime,
+      item.pixelMap,
+      item.size,
+      item.pixelMapPath,
+      item.artist,
+      item.album,
+      item.fileName,
+      item.lastPlayed
+    );
+    clone.duration = item.duration;
+    clone.mimeType = item.mimeType;
+    clone.trackCount = item.trackCount;
+    clone.sampleRate = item.sampleRate;
+    clone.size = item.size;
+    clone.webdav_account_id = item.webdav_account_id;
+    clone.remote_rel_path = item.remote_rel_path;
+    clone.artist = item.artist;
+    clone.album = item.album;
+    clone.lyricContent = item.lyricContent;
+    clone.pixelMapPath = item.pixelMapPath;
+    clone.pixelMap = item.pixelMap;
+    clone.cTime = item.cTime;
+    clone.fileName = item.fileName;
+    clone.md5Str = item.md5Str;
+    clone.bit_rate = item.bit_rate;
+    clone.probe_score = item.probe_score;
+    clone.year = item.year;
+    clone.nb_streams = item.nb_streams;
+    clone.nb_programs = item.nb_programs;
+    clone.genre = item.genre;
+    clone.track = item.track;
+    clone.disc = item.disc;
+    clone.channels = item.channels;
+    clone.channel_layout = item.channel_layout;
+    clone.start_time = item.start_time;
+    clone.ALBUMARTIST = item.ALBUMARTIST;
+    clone.COMPOSER = item.COMPOSER;
+    clone.COMMENT = item.COMMENT;
+    clone.LYRICIST = item.LYRICIST;
+    clone.pyStr = item.pyStr;
+    clone.extra_json = item.extra_json;
+    clone.parentPath = item.parentPath;
+    clone.isFav = item.isFav;
+    clone.playCount = item.playCount;
+    clone.lastPlayed = item.lastPlayed;
+    clone.videoSize = item.videoSize;
+    clone.isFav = item.isFav;
+    return clone;
+  }
+
   // 加载账户列表
   private loadAccounts(): void {
     this.accounts = this.webdavManager.getAllWebDavAccounts();
@@ -951,7 +1097,7 @@ export struct WebDavMainPage {
             .transition(TransitionEffect.asymmetric(TransitionEffect.scale({ x: 1.2, y: 1.2 }).animation({ duration: 600 }),
               TransitionEffect.scale({ x: 0, y: 0 })))
             .clickEffect({ level: ClickEffectLevel.MIDDLE })
-          }, (item: VideoItem) =>  item.filePath)
+          }, (item: VideoItem) =>  item.filePath + '_' + this.listRefreshKey)
         }
 
         .contentStartOffset(this.topSafeHeight + 80)

+ 21 - 0
entry/src/main/ets/view/LocalMusic.ets

@@ -273,6 +273,13 @@ interface WorkerMetadataPayload {
   error?: string;
 }
 
+interface WebDavMetadataUpdatePayload {
+  filePath: string;
+  pixelMapPath?: string;
+  name?: string;
+  artist?: string;
+}
+
 const metadataExtractionInFlight: Set<string> = new Set();
 
 function scheduleMetadataExtractionFromCache(
@@ -1440,6 +1447,7 @@ export struct LocalMusic {
     collectFromList(remoteManager.webDavSongs);
 
     const updated = new Set<VideoItem>();
+    const webDavUpdates: Map<string, WebDavMetadataUpdatePayload> = new Map();
     for (let i = 0; i < targets.length; i++) {
       const target = targets[i];
       if (!target || updated.has(target)) {
@@ -1447,6 +1455,14 @@ export struct LocalMusic {
       }
       updated.add(target);
       this.mergeVideoItemWithPayload(target, payload);
+      if (target.type === CommonConstants.TYPE_WEBDAV && StrUtil.isNotEmpty(target.filePath)) {
+        webDavUpdates.set(target.filePath, {
+          filePath: target.filePath,
+          pixelMapPath: target.pixelMapPath,
+          name: target.name,
+          artist: target.artist
+        });
+      }
     }
 
     if (this.currentSong && this.currentSong.filePath === filePath) {
@@ -1473,6 +1489,11 @@ export struct LocalMusic {
         Logger.error(TAG, `缓存元数据持久化失败: ${error.message}`);
       });
     }
+
+    if (webDavUpdates.size > 0) {
+      const eventUpdate: emitter.InnerEvent = { eventId: EventConstants.EVENT_WEBDAV_METADATA_UPDATED };
+      emitter.emit(eventUpdate, { data: Array.from(webDavUpdates.values()) });
+    }
   }
 
   private assignStringMetadata(target: VideoItem, key: keyof VideoItem, value?: string | null, allowEmpty = false): void {