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

+ 65 - 19
entry/src/main/ets/common/util/MediaTable.ets

@@ -31,6 +31,16 @@ interface DBColumnsInterface {
   LYRIC_CONTENT: string;
 }
 
+/**
+ * 媒体元数据接口定义
+ */
+export interface MediaMetadata {
+  duration?: string;
+  mimeType?: string;
+  sampleRate?: string;
+  trackCount?: string;
+}
+
 /**
  * 数据库字段常量,避免硬编码
  */
@@ -279,15 +289,12 @@ export default class MediaTable {
         console.log(`${RdbUtils.RDB_TAG}` + 'Query no results!');
         callback([]);
       } else {
-
-
         const result = this.parseResultSetToVideoItems(resultSet);
         callback(result);
       }
     });
   }
 
-
   // 新增方法:根据parentPath查询数据
   public queryByParentPath(path: string, callback: (result: VideoItem[]) => void) {
     try {
@@ -300,14 +307,12 @@ export default class MediaTable {
         const result = this.parseResultSetToVideoItems(resultSet);
         callback(result);
       });
-    }catch (err) {
-      Logger.error(` onecold testtag queryByParentPath: ${err.code}  - ${err.message}`);
-
+    } catch (err) {
+      Logger.error(`查询parentPath失败: ${err.message}`);
+      callback([]);
     }
-    // 1. 构建查询条件
-
   }
-
+  
   // 查询所有艺术家及其歌曲(返回Map结构:artist -> VideoItem[])
   public queryArtistsWithSongs(callback: (result: Map<string, VideoItem[]>) => void) {
     // 1. 查询去重的艺术家列表(非空)
@@ -341,9 +346,6 @@ export default class MediaTable {
     });
   }
 
-
-
-
   // 查询所有专辑及其歌曲(返回Map结构:album -> VideoItem[])
   public queryAlbumsWithSongs(callback: (result: Map<string, VideoItem[]>) => void) {
     // 1. 查询去重的专辑列表(非空)
@@ -377,8 +379,6 @@ export default class MediaTable {
     });
   }
 
-
-
   // 解析去重列数据(如artist/album)
   private parseDistinctColumn(resultSet: relationalStore.ResultSet, columnName: string): string[] {
     const uniqueValues = new Set<string>();  // 使用Set特性自动去重
@@ -398,7 +398,7 @@ export default class MediaTable {
     return Array.from(uniqueValues);   // Set转数组
   }
 
-  // 将ResultSet解析为VideoItem数组(复用原有逻辑)
+  // 将ResultSet解析为VideoItem数组
   private parseResultSetToVideoItems(resultSet: relationalStore.ResultSet): VideoItem[] {
     const items: VideoItem[] = [];
 
@@ -462,8 +462,58 @@ export default class MediaTable {
     return item;
   }
 
+  // 根据文件路径查询数据
+  public queryByFilePath(filePath: string, callback: (result: VideoItem[]) => void) {
+    try {
+      const predicates = new relationalStore.RdbPredicates(RdbUtils.MEDIA_TABLE.tableName);
+      predicates.equalTo('filePath', filePath);
 
+      // 执行查询并处理结果
+      this.accountTable.query(predicates, (resultSet: relationalStore.ResultSet) => {
+        // 复用已有的解析逻辑
+        const result = this.parseResultSetToVideoItems(resultSet);
+        callback(result);
+      });
+    } catch (err) {
+      Logger.error(`查询文件路径失败 - filePath: ${filePath}, error: ${err.code} - ${err.message}`);
+      callback([]);
+    }
+  }
 
+  // 更新媒体文件的元数据信息(采样率、MIME类型等)
+  public updateMediaMetadata(filePath: string, metadata: MediaMetadata, callback: (success: boolean) => void) {
+    try {
+      // 构建查询条件
+      const predicates = new relationalStore.RdbPredicates(RdbUtils.MEDIA_TABLE.tableName);
+      predicates.equalTo('filePath', filePath);
+      
+      // 构建更新值
+      const valuesToUpdate: relationalStore.ValuesBucket = {};
+      if (metadata.duration) {
+        valuesToUpdate.duration = metadata.duration;
+      }
+      if (metadata.mimeType) {
+        valuesToUpdate.mimeType = metadata.mimeType;
+      }
+      if (metadata.sampleRate) {
+        valuesToUpdate.sampleRate = metadata.sampleRate;
+      }
+      if (metadata.trackCount) {
+        valuesToUpdate.trackCount = metadata.trackCount;
+      }
+      
+      // 执行更新
+      if (Object.keys(valuesToUpdate).length > 0) {
+        this.accountTable.updateData(predicates, valuesToUpdate, callback);
+      } else {
+        Logger.info('No metadata to update');
+        callback(false);
+      }
+    } catch (err) {
+      Logger.error(`更新媒体元数据失败: ${err.message}`);
+      callback(false);
+    }
+  }
 }
 
 function generateBucket(item: VideoItem): relationalStore.ValuesBucket {
@@ -477,9 +527,6 @@ function generateBucket(item: VideoItem): relationalStore.ValuesBucket {
   obj.parentPath = item.parentPath;
   obj.isFav = item.isFav;
 
-  // if(item.pixelMapToString){
-  //   obj.pixelMapToString = item.pixelMapToString;
-  // }
   if(item.artist){
     obj.artist = item.artist;
   }
@@ -496,7 +543,6 @@ function generateBucket(item: VideoItem): relationalStore.ValuesBucket {
     obj.pixelMapPath = item.pixelMapPath;
   }
 
-
   if(item.duration){
     obj.duration = item.duration;
   }

+ 38 - 4
entry/src/main/ets/common/util/Utility.ets

@@ -125,11 +125,45 @@ export class Utility {
   }
 
   static convertToKHz(sampleRateHz: string|undefined): string {
-    if(StrUtil.isEmpty(sampleRateHz)||sampleRateHz ===undefined)
-      return '0KHz'
+    if(StrUtil.isEmpty(sampleRateHz) || sampleRateHz === undefined || sampleRateHz === "0") {
+      return '未知';
+    }
+
+    try {
+      const sampleRateNum = Number(sampleRateHz);
+      if (isNaN(sampleRateNum) || sampleRateNum <= 0) {
+        return '未知';
+      }
+      const sampleRateKHz = sampleRateNum / 1000;
+      return `${sampleRateKHz.toFixed(1)} KHz`;
+    } catch (err) {
+      console.error(`转换采样率出错: ${err}`);
+      return '未知';
+    }
+  }
 
-    const sampleRateKHz = Number(sampleRateHz) / 1000;
-    return `${sampleRateKHz} KHz`;
+  /**
+   * 格式化媒体格式类型显示
+   * @param mimeType 媒体格式类型字符串
+   * @return 格式化后的显示字符串
+   */
+  static formatMimeType(mimeType: string|undefined): string {
+    if(StrUtil.isEmpty(mimeType) || mimeType === undefined) {
+      return '未知';
+    }
+    
+    // 从MIME类型中提取格式部分,例如 "audio/mp3" -> "MP3"
+    try {
+      const parts = mimeType.split('/');
+      if (parts.length > 1) {
+        return parts[1].toUpperCase();
+      } else {
+        return mimeType.toUpperCase();
+      }
+    } catch (err) {
+      console.error(`格式化媒体类型出错: ${err}`);
+      return '未知';
+    }
   }
 
   //根据字节获取大小

+ 95 - 8
entry/src/main/ets/view/LocalMusic.ets

@@ -73,7 +73,7 @@ import { secondToTime } from '../common/util/CommUtils';
 import { CommonConstants2 } from '../common/util/CommonConstants2';
 import { hilog } from '@kit.PerformanceAnalysisKit';
 import { LazyDataSource } from '../common/util/LazyDataSource';
-import MediaTable from '../common/util/MediaTable';
+import MediaTable, { MediaMetadata } from '../common/util/MediaTable';
 import NetAxiosUtil from '../common/util/NetAxiosUtil';
 import ImageUtils from '../common/util/ImageUtils';
 import { ringtone } from '@kit.RingtoneKit';
@@ -630,17 +630,40 @@ export struct LocalMusic {
 
       this.songList = PreferencesUtil.getSync('LastMusicList', []) as Array<VideoItem>
       this.currentSong = PreferencesUtil.getSync('LastMusicInfo', undefined) as VideoItem
+      
+      // 打印加载的当前歌曲信息,用于调试
+      if (this.currentSong) {
+        console.info(`加载歌曲信息 - 采样率: ${this.currentSong.sampleRate}, MIME类型: ${this.currentSong.mimeType}`);
+      }
+      
       if (ArrayUtil.isEmpty(this.songList)) {
         this.songList = this.getCurFileList()
       } else {
-        this.curIndex = Utility.getIndexFromList(this.songList, this.currentSong.filePath)
+        this.curIndex = Utility.getIndexFromList(this.songList, this.currentSong?.filePath || '')
       }
       if (ArrayUtil.isNotEmpty(this.songList)) {
         this.sonDataSource.pushArrayData(this.songList)
         if (this.currentSong === undefined) {
-
           this.currentSong = this.songList[0]
         }
+        
+        // 如果当前歌曲缺少必要信息,尝试从数据库中重新加载
+        if (this.currentSong && (!this.currentSong.sampleRate || !this.currentSong.mimeType)) {
+          this.table.queryByFilePath(this.currentSong.filePath, (result: VideoItem[]) => {
+            if (result && result.length > 0) {
+              // 更新当前歌曲对象,手动复制属性
+              if (this.currentSong) {
+                const dbItem = result[0];
+                this.currentSong.sampleRate = dbItem.sampleRate;
+                this.currentSong.mimeType = dbItem.mimeType;
+                this.currentSong.duration = dbItem.duration;
+                this.currentSong.trackCount = dbItem.trackCount;
+                console.info(`从数据库更新歌曲属性 - 采样率: ${dbItem.sampleRate}, MIME类型: ${dbItem.mimeType}`);
+              }
+            }
+          });
+        }
+        
         this.videoUrl = this.currentSong.filePath
         this.name = this.currentSong.name
         this.cover = this.currentSong.pixelMapPath
@@ -3582,6 +3605,9 @@ export struct LocalMusic {
 
           if (ArrayUtil.isNotEmpty(this.songList)) {
             this.isShowPlay = true;
+            // 显示播放界面时重新提取音频元数据
+            this.refreshCurrentSongMetadata();
+            
             let lyricPath = this.videoUrl.substring(0, this.videoUrl.lastIndexOf('.')) + '.lrc'
             this.initLyric(lyricPath);
             if (FileUtil.accessSync(this.favPath)) {
@@ -4138,11 +4164,15 @@ export struct LocalMusic {
             .fontSize(14)
             .fontColor(Color.White)
             .margin({ left: 22 })
-          Text(Utility.convertToKHz(this.currentSong.sampleRate))
+          Text(Utility.convertToKHz(this.currentSong?.sampleRate || ''))
             .fontSize(14)
             .margin({ left: 10 })
             .fontColor(Color.White)
             .layoutWeight(1)
+            .onAppear(() => {
+              console.info('音频信息:'+JSON.stringify(this.currentSong))
+              console.info(`音频采样率原始值: ${this.currentSong?.sampleRate}, 类型: ${typeof this.currentSong?.sampleRate}`);
+            })
         }
         .width('100%')
         .margin({ top: 10, bottom: 10 })
@@ -4153,11 +4183,14 @@ export struct LocalMusic {
             .fontSize(14)
             .fontColor(Color.White)
             .margin({ left: 22 })
-          Text(this.currentSong.mimeType)
+          Text(Utility.formatMimeType(this.currentSong?.mimeType || ''))
             .fontSize(14)
             .margin({ left: 10 })
             .fontColor(Color.White)
             .layoutWeight(1)
+            .onAppear(() => {
+              console.info(`音频MIME类型原始值: ${this.currentSong?.mimeType}, 类型: ${typeof this.currentSong?.mimeType}`);
+            })
         }
         .width('100%')
         .margin({ top: 10, bottom: 10 })
@@ -7399,6 +7432,53 @@ export struct LocalMusic {
     this.replayVisible = Visibility.Visible;
   }
 
+  // 从文件重新提取音频元数据
+  private async refreshCurrentSongMetadata() {
+    if (!this.currentSong || StrUtil.isEmpty(this.currentSong.filePath)) {
+      console.error('无法刷新元数据,当前歌曲或文件路径为空');
+      return;
+    }
+    
+    try {
+      // 直接从音频文件重新加载完整的元数据
+      console.info(`开始重新提取音频元数据: ${this.currentSong.filePath}`);
+      const refreshedItem = await Utility.uriGetMusicAssetsFromFile(
+        this.context, 
+        this.currentSong.filePath, 
+        CommonConstants.TYPE_LOCAL, 
+        false
+      );
+      
+      // 只更新元数据相关字段,保留其他字段
+      if (this.currentSong) {
+        this.currentSong.duration = refreshedItem.duration;
+        this.currentSong.mimeType = refreshedItem.mimeType;
+        this.currentSong.sampleRate = refreshedItem.sampleRate;
+        this.currentSong.trackCount = refreshedItem.trackCount;
+        
+        // 更新数据库中的记录以确保下次不需要重新提取
+        // 创建符合MediaMetadata接口的对象
+        const metadataToUpdate: MediaMetadata = {
+          duration: refreshedItem.duration,
+          mimeType: refreshedItem.mimeType,
+          sampleRate: refreshedItem.sampleRate,
+          trackCount: refreshedItem.trackCount
+        };
+        this.table.updateMediaMetadata(this.currentSong.filePath, metadataToUpdate, (success: boolean) => {
+          if (success) {
+            console.info('成功更新音频元数据到数据库');
+          } else {
+            console.error('更新音频元数据到数据库失败');
+          }
+        });
+        
+        console.info(`刷新后的采样率: ${this.currentSong.sampleRate}, MIME类型: ${this.currentSong.mimeType}`);
+      }
+    } catch (err) {
+      console.error(`刷新音频元数据失败: ${err}`);
+    }
+  }
+  
   private async play(url: string) {
     let that = this;
     that.showLoadIng();
@@ -7718,10 +7798,16 @@ export struct LocalMusic {
 
   //保存最后播放的那首歌和已经对应的播放列表
   saveLastPlayList() {
-
-    PreferencesUtil.putSync('LastMusicInfo', this.currentSong)
+    // 确保所有字段都被保存,特别是sampleRate和mimeType
+    if (this.currentSong) {
+      // 打印当前歌曲的采样率和MIME类型值,用于调试
+      console.info(`保存歌曲信息 - 采样率: ${this.currentSong.sampleRate}, MIME类型: ${this.currentSong.mimeType}`);
+      
+      // 将完整对象保存到LastMusicInfo
+      PreferencesUtil.putSync('LastMusicInfo', this.currentSong)
+    }
+    
     PreferencesUtil.putSync('LastMusicList', this.songList)
-
   }
 
   //添加播放历史记录
@@ -8956,3 +9042,4 @@ function cutPopupBuilder(dataBu: BubbleBean) {
 
 }
 
+