Просмотр исходного кода

歌曲统计增加 音质统计图

onecold 11 месяцев назад
Родитель
Сommit
8187a113b3

+ 41 - 1
entry/src/main/ets/common/util/MediaTable.ets

@@ -3,7 +3,7 @@ import { LogUtil, StrUtil } from '@pura/harmony-utils';
 import { VideoItem } from '../../viewmodel/VideoItem';
 import Logger from './Logger';
 import RdbUtils from './RdbUtils';
-import { Utility } from './Utility';
+import { AudioQuality, Utility } from './Utility';
 
 /**
  * 数据库字段常量接口定义
@@ -654,6 +654,46 @@ export default class MediaTable {
   }
 
 
+  public countSongsByQualityOptimized(callback: (result: Record<AudioQuality, number>) => void): void {
+    const predicates = new relationalStore.RdbPredicates(RdbUtils.MEDIA_TABLE.tableName);
+    predicates.in('md5Str',  [AudioQuality.LQ, AudioQuality.SQ, AudioQuality.HQ, AudioQuality.LOSSLESS, AudioQuality.HIRES, AudioQuality.HR]);
+
+    this.accountTable.query(predicates,  (resultSet: relationalStore.ResultSet) => {
+      const result: Record<AudioQuality, number> = {
+        [AudioQuality.LQ]: 0,
+        [AudioQuality.SQ]: 0,
+        [AudioQuality.HQ]: 0,
+        [AudioQuality.LOSSLESS]: 0,
+        [AudioQuality.HIRES]: 0 , // 只保留HR,HIRES的统计将合并到这里
+        [AudioQuality.HR]: 0  // 只保留HR,HIRES的统计将合并到这里
+      };
+
+      if (resultSet.rowCount  > 0) {
+        resultSet.goToFirstRow();
+        do {
+          const quality = resultSet.getString(resultSet.getColumnIndex('md5Str'))  as AudioQuality;
+          if (quality === AudioQuality.LQ ||
+            quality === AudioQuality.SQ ||
+            quality === AudioQuality.HQ ||
+            quality === AudioQuality.LOSSLESS ||
+            quality === AudioQuality.HIRES ||  // HIRES的统计将被合并到HR
+            quality === AudioQuality.HR) {
+
+            // 如果质量是HIRES或HR,都统计到HR中
+            const targetKey = (quality === AudioQuality.HIRES || quality === AudioQuality.HR)
+              ? AudioQuality.HR
+              : quality;
+
+            result[targetKey]++;
+          }
+        } while (resultSet.goToNextRow());
+      }
+
+      resultSet.close();
+      callback(result);
+    });
+  }
+
 
 }
 

+ 6 - 5
entry/src/main/ets/common/util/Utility.ets

@@ -1912,12 +1912,13 @@ function formatBitrateToKbps(bitRate: string, decimalPlaces: number = 0): string
 
 
 // 定义音质等级
-enum AudioQuality {
+export enum AudioQuality {
   LQ = "LQ",             // 低音质
   SQ = "SQ",             // 标准音质
   HQ = "HQ",             // 高音质
   LOSSLESS = "Lossless", // 无损
-  HIRES = "Hi-Res"       // 高解析度
+  HIRES = "Hi-Res",      // 高解析度
+  HR = "HR"       // 高解析度
 }
 
 // 明确定义支持的音频格式类型
@@ -1943,7 +1944,7 @@ const SUPPORTED_FORMATS: SupportedFormats = {
 function determineAudioQuality(
   format: string,
   bitrate: number,
-  sampleRate: number
+  sampleRate: number,
 ): AudioQuality {
   // 统一转为小写便于比较
   const normalizedFormat = format.toLowerCase();
@@ -1952,8 +1953,8 @@ function determineAudioQuality(
   const isLossless = SUPPORTED_FORMATS.LOSSLESS.has(normalizedFormat);
   if (isLossless) {
     // Hi-Res标准:采样率≥96kHz且位深≥24bit
-    if (sampleRate >= 96000 ) {
-      return AudioQuality.HIRES;
+    if (sampleRate >= 48000 ) {
+      return AudioQuality.HR;
     }
     // CD级无损标准:采样率≥44.1kHz且位深≥16bit
     if (sampleRate >= 44100) {

+ 63 - 4
entry/src/main/ets/pages/ChartsCount.ets

@@ -8,7 +8,7 @@ import { changeMusicCover, findLocalCoverImage, getApiLyric, repairAudioMetadata
   searchCover,
   syncLyricToDB} from '../common/util/MusicTagUtils';
 import { util } from '@kit.ArkTS';
-import { FFMpegTags } from '../common/util/Utility';
+import { AudioQuality, FFMpegTags } from '../common/util/Utility';
 import MediaTable from '../common/util/MediaTable';
 import { McPieChart, Options } from '@mcui/mccharts'
 
@@ -26,6 +26,12 @@ export struct ChartsCount {
   @State mediaKuCount: number = 0;
   @State albumCount: number = 0;
   @State artistCount: number = 0;
+
+  @State lqCount: number = 0;
+  @State sqCount: number = 0;
+  @State hqCount: number = 0;
+  @State losslessCount: number = 0;
+  @State hrCount: number = 0;
   @State isDarkMode: boolean = false
   @StorageProp('currentColorMode') @Watch('onColorModeChange') currentMode: number =
     ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT;
@@ -51,6 +57,26 @@ export struct ChartsCount {
     ]
   })
 
+  @State HrOption: Options = new Options({
+    title: {
+      show: true,
+      text: '音质统计',
+      left: 40,
+      top: 20
+    },
+    series:[
+      {
+        data:[
+          {value:this.lqCount, name:'LQ'},
+          {value:this.sqCount, name:'SQ'},
+          {value:this.hqCount, name:'HQ'},
+          {value:this.losslessCount, name:'Lossless'},
+          {value:this.hrCount, name:'Hi-Res'},
+        ]
+      }
+    ]
+  })
+
 
   onColorModeChange() {
     this.isDarkMode = this.currentMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK
@@ -75,6 +101,32 @@ export struct ChartsCount {
 
     })
 
+    this.table.countSongsByQualityOptimized(async (result:Record<AudioQuality, number>) => {
+      this.lqCount = result.LQ
+      this.hqCount = result.HQ
+      this.hrCount = result.HR
+      this.sqCount = result.SQ
+      this.losslessCount = result.Lossless
+      setTimeout(() => {
+        // 使用Option实例对象的setVal方法来实现,修改什么属性就传什么
+        this.HrOption.setVal({
+          animation:true,
+          series:[
+            {
+              data:[
+                {value:this.lqCount, name:'LQ'},
+                {value:this.sqCount, name:'SQ'},
+                {value:this.hqCount, name:'HQ'},
+                {value:this.losslessCount, name:'Lossless'},
+                {value:this.hrCount, name:'Hi-Res'},
+              ]
+            }
+          ]
+        })
+      }, 1000)
+
+    })
+
   }
 
   centerChart(){
@@ -84,6 +136,7 @@ export struct ChartsCount {
     setTimeout(() => {
       // 使用Option实例对象的setVal方法来实现,修改什么属性就传什么
       this.defOption.setVal({
+        animation:true,
         series: [
           {
             data:[
@@ -114,9 +167,15 @@ export struct ChartsCount {
   @Builder
   centerCharts() {
     Row() {
-      McPieChart({
-        options: this.defOption
-      })
+      Swiper() {
+        McPieChart({
+          options: this.defOption
+        })
+        McPieChart({
+          options: this.HrOption
+        })
+      }
+
     }
     .borderRadius(14)
     .backgroundColor($r('app.color.start_window_background'))

+ 1 - 0
entry/src/main/ets/pages/NewIndex.ets

@@ -595,6 +595,7 @@ struct NewIndex {
                   SymbolGlyph((item.img as sysResource).value as Resource)// .size({ width: 22, height: 22 })
                     .fontSize(22)
                     .fontColor([this.themeColor])
+                    .effectStrategy(SymbolEffectStrategy.HIERARCHICAL)
                     .alignSelf(ItemAlign.Center)
                     .margin({ left: 25 })
                 } else {

+ 23 - 23
entry/src/main/ets/view/LocalMusic.ets

@@ -3844,31 +3844,31 @@ export struct LocalMusic {
                 this.addToNextPlay(item);
                 this.longItemFilePath = ''
               })
-            if(Utility.isNoble()){
-              MenuItem({
-                symbolStartIcon: new SymbolGlyphModifier($r('sys.symbol.square_and_pencil')),
-                content: '编辑标签'
+
+            MenuItem({
+              symbolStartIcon: new SymbolGlyphModifier($r('sys.symbol.square_and_pencil')),
+              content: '编辑标签'
+            })
+              .bindSheet($$this.isShowEdit, this.editSheet(item), {
+                height: '99%',
+                dragBar: true,
+                showClose: true,
+                preferType: SheetType.CENTER ,
+                title: { title: '编辑标签' }
+              })
+              .visibility(item.type === CommonConstants.TYPE_IS_DIR ? Visibility.None : Visibility.Visible)
+              .onClick(async() => {
+                this.setEditStrEmpty()
+                this.tempLyricContent = await this.getLyricContent(item);
+                // console.info('onecold 长按this.tempLyricContent' +this.tempLyricContent)
+                if(this.isGridMusic){
+                  this.longItemFilePath = item.filePath
+                }else{
+                  this.isShowEdit = !this.isShowEdit;
+                }
+
               })
-                .bindSheet($$this.isShowEdit, this.editSheet(item), {
-                  height: '99%',
-                  dragBar: true,
-                  showClose: true,
-                  preferType: SheetType.CENTER ,
-                  title: { title: '编辑标签' }
-                })
-                .visibility(item.type === CommonConstants.TYPE_IS_DIR ? Visibility.None : Visibility.Visible)
-                .onClick(async() => {
-                  this.setEditStrEmpty()
-                  this.tempLyricContent = await this.getLyricContent(item);
-                  // console.info('onecold 长按this.tempLyricContent' +this.tempLyricContent)
-                  if(this.isGridMusic){
-                    this.longItemFilePath = item.filePath
-                  }else{
-                    this.isShowEdit = !this.isShowEdit;
-                  }
 
-                })
-            }
 
             MenuItem({
               symbolStartIcon: new SymbolGlyphModifier($r('sys.symbol.checkmark_square_on_square')),