Quellcode durchsuchen

Merge remote-tracking branch 'origin/master' into feature/cdb/微信登录+用户中心

# Conflicts:
#	entry/src/main/ets/entryability/EntryAbility.ets
#	entry/src/main/ets/pages/MainIndex.ets
#	entry/src/main/ets/pages/NewIndex.ets
#	entry/src/main/ets/view/LocalMusic.ets
chendeben vor 1 Jahr
Ursprung
Commit
93f51c8772

+ 1 - 1
entry/src/main/ets/common/constants/CommonConstants.ets

@@ -20,7 +20,7 @@ import { VideoSpeed } from '../../viewmodel/VideoSpeed';
  */
 export class CommonConstants {
 
-  static readonly OPEN_DATE: string = '2025-06-08';
+  static readonly OPEN_DATE: string = '2025-06-10';
 
   static readonly ICP_NO: string = '闽ICP备18015191号-16A';
 

+ 0 - 1
entry/src/main/ets/common/util/ImageUtils.ets

@@ -24,7 +24,6 @@ import { photoAccessHelper } from '@kit.MediaLibraryKit';
 import fs from '@ohos.file.fs';
 import { FileUtil, MD5, PreferencesUtil } from '@pura/harmony-utils';
 import MediaTable from './MediaTable';
-import { FileUtils } from '@ohos/imageknife';
 
 const TAG = 'ImageUtils';
 

+ 1 - 0
entry/src/main/ets/common/util/LazyDataSource.ets

@@ -125,4 +125,5 @@ export class LazyDataSource<T> extends BasicDataSource<T> {
     this.dataArray.push(...newData);
     this.notifyDataReload();
   }
+
 }

+ 141 - 0
entry/src/main/ets/common/util/LyricUtil.ets

@@ -0,0 +1,141 @@
+import fs from '@ohos.file.fs';
+import common from '@ohos.app.ability.common';
+import fileIo from '@ohos.file.fs';
+import { LyricWord } from '@seagazer/cclyric/src/main/ets/bean/LyricWord';
+
+// 定义接口来描述返回值的类型
+interface ParseResult {
+  timeline: number;
+  words: LyricWord[];
+}
+
+class LyricUtil {
+
+  // 检测方括号格式的逐字歌词 [00:00.000]文[00:01.000]字
+  private isSquareBracketWordByWordLyric(line: string): boolean {
+    return /\[\d{2}:\d{2}\.\d{2,3}\]\S/.test(line);
+  }
+
+  // 解析方括号格式的逐字歌词行
+  private parseSquareBracketWordLine(line: string, offset: number): ParseResult {
+    const words: LyricWord[] = [];
+    let firstTimeline = -1;
+
+    // 正则匹配:[00:00.000]中文字
+    const regex = /\[(\d{2}:\d{2}\.\d{2,3})\]([^\[]*)/g;
+    // 显式指定 match 的类型
+    let match: RegExpExecArray | null;
+
+    while ((match = regex.exec(line))!==  null) {
+      const timeStr = match[1];   // 时间部分 00:00.000
+      const word = match[2].trim(); // 歌词文本
+
+      if (!word) continue; // 跳过空词
+
+      const timeline = this.parseTimeline2(timeStr)  - offset;
+      if (firstTimeline < 0) firstTimeline = timeline;
+
+      words.push(new  LyricWord(word, timeline, 0));
+    }
+
+    // 计算每个词的持续时间
+    for (let i = 0; i < words.length  - 1; i++) {
+      words[i].duration = words[i + 1].startTime - words[i].startTime;
+    }
+    if (words.length  > 0 && words[words.length - 1].duration === 0) {
+      words[words.length - 1].duration = 200; // 默认200ms
+    }
+
+    return { timeline: firstTimeline, words };
+  }
+
+  /******************** 时间解析增强 ********************/
+  private parseTimeline2(timeString: string): number {
+    // 增强支持毫秒/厘秒解析
+    const parts = timeString.split(':');
+    const minutes = parseInt(parts[0], 10);
+
+    const secondParts = parts[1].split('.');
+    const seconds = parseInt(secondParts[0], 10);
+    const fraction = parseInt(secondParts[1], 10);
+
+    // 根据小数位长度判断时间精度
+    const milliseconds = secondParts[1].length === 2 ?
+      fraction * 10 : // 厘秒转毫秒 (01 -> 10ms)
+      fraction;       // 毫秒直接使用
+
+    return minutes * 60000 + seconds * 1000 + milliseconds;
+  }
+
+  // 判断是否是逐字歌词行
+  private isWordByWordLyric(line: string): boolean {
+    const hasBracketTimestamp = /\(\d{2}:\d{2}\.\d{2,3}\)\S/.test(line);
+    const hasAngleTimestamp = /<\d{2}:\d{2}\.\d{2,3}>/.test(line);
+    return hasBracketTimestamp || hasAngleTimestamp;
+  }
+  /**
+   * 将整个逐字歌词内容转换为最简单的LRC格式
+   * @param lyricContent 整个歌词内容(字符串)
+   * @returns 转换后的LRC格式字符串
+   */
+  public convertLyricToSimpleLrc(lyricContent: string): string {
+    let lyrics = lyricContent.split('\n').map(line => line.trim());
+    const result: string[] = [];
+    const ignoredTags = ['ti', 'ar', 'al', 'by', 'offset', 'hash', 'sign', 'qq', 'total', 'Outro', 'tool'];
+
+    for (let i = 0; i < lyrics.length; i++) {
+      const line = lyrics[i].trim();
+
+      // 跳过空行和特定标签行
+      if (!line) continue;
+      if (ignoredTags.some(tag => line.startsWith(`[${tag}]`))) continue;
+
+      // 处理逐字歌词行
+      if (this.isSquareBracketWordByWordLyric(line) || this.isWordByWordLyric(line)) {
+        let firstTimestamp = "";
+        let fullText = "";
+
+        // 处理尖括号格式:<00:00.000>文<00:01.000>字
+         if (this.isWordByWordLyric(line)) {
+          const regex = /<(\d{2}:\d{2}\.\d{2,3})>([^<]*)/g;
+          let match: RegExpExecArray | null;
+
+          while ((match = regex.exec(line)) !== null) {
+            const timestamp = match[1];
+            const word = match[2].trim();
+
+            if (!firstTimestamp) firstTimestamp = timestamp;
+            fullText += word;
+          }
+        }else
+        // 处理方括号格式:[00:00.000]文[00:01.000]字
+        if (this.isSquareBracketWordByWordLyric(line)) {
+          const regex = /\[(\d{2}:\d{2}\.\d{2,3})\]([^\[]*)/g;
+          let match: RegExpExecArray | null;
+
+          while ((match = regex.exec(line)) !== null) {
+            const timestamp = match[1];
+            const word = match[2].trim();
+
+            if (!firstTimestamp) firstTimestamp = timestamp;
+            fullText += word;
+          }
+        }
+
+        // 添加到结果中
+        if (firstTimestamp && fullText) {
+          result.push(`[${firstTimestamp}]${fullText}`);
+        }
+      }
+      // 保留普通LRC行
+      else {
+        result.push(line);
+      }
+    }
+
+    // 将结果数组连接成单一字符串
+    return result.join('\n');
+  }
+}
+
+export default new LyricUtil();

+ 7 - 0
entry/src/main/ets/common/util/Utility.ets

@@ -952,6 +952,13 @@ export class Utility {
 
   }
 
+  static getMusisBg2(index:number):Resource {
+    const adjustedIndex = index % 10;
+    LogUtil.info('getMusisBg adjustedIndex = '+adjustedIndex)
+    return CommonConstants.musicBgList[adjustedIndex]
+
+  }
+
 
 
 

+ 6 - 1
entry/src/main/ets/controller/AvSessionController.ets

@@ -23,6 +23,7 @@ import { ImageUtil, PreferencesUtil } from '@pura/harmony-utils';
 import { image } from '@kit.ImageKit';
 import { SettingPage } from '../pages/SettingPage';
 import { Utility } from '../common/util/Utility';
+import LyricUtil from '../common/util/LyricUtil';
 
 const TAG = 'onecold AvSessionController';
 
@@ -147,6 +148,10 @@ export class AvSessionController {
       } else {
         imagePixMap = value;
       }
+      let lyric = ''
+      if(lyricContent)
+        lyric = LyricUtil.convertLyricToSimpleLrc(lyricContent)
+
       hilog.info(0x0000, TAG, 'onecold SetAVMetadata successfully curSource.pixelMapPath '+curSource.pixelMapPath);
       let metadata: avSession.AVMetadata = {
         assetId: `${curSource.filePath}`,
@@ -155,7 +160,7 @@ export class AvSessionController {
         artist: curSource.artist,
         mediaImage: imagePixMap,
         duration: duration,
-        lyric:lyricContent,
+        lyric:lyric,
       };
 
       if (this.avSession) {

+ 0 - 615
entry/src/main/ets/controller/VideoController.ets

@@ -1,615 +0,0 @@
-/*
- * Copyright (c) 2023 Huawei Device Co., Ltd.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import { media } from '@kit.MediaKit';
-import { promptAction } from '@kit.ArkUI';
-import { window } from '@kit.ArkUI';
-import { resourceManager } from '@kit.LocalizationKit';
-import Logger from '../common/util/Logger';
-import DateFormatUtil from '../common/util/DateFormatUtil';
-import { CommonConstants, AvplayerStatus, Events, SliderMode } from '../common/constants/CommonConstants';
-import { PlayConstants } from '../common/constants/PlayConstants';
-import { GlobalContext } from '../common/util/GlobalContext';
-import { VideoItem } from '../viewmodel/VideoItem';
-import { PlayerModel } from '../common/model/PlayerModel';
-import { BackgroundUtil } from '../common/util/BackgroundUtil';
-import { common, wantAgent } from '@kit.AbilityKit';
-import { avSession } from '@kit.AVSessionKit';
-import { BusinessError } from '@kit.BasicServicesKit';
-import { Utility } from '../common/util/Utility';
-
-const TAG = 'VideoController';
-@Observed
-export class VideoController {
-  private context: common.UIAbilityContext | undefined  = AppStorage.get('context');
-  // private context: common.UIAbilityContext | undefined = undefined;
-  public playerModel: PlayerModel;
-  private avPlayer: media.AVPlayer | null = null;
-  private duration: number = 0;
-  private status: number = -1;
-  private loop: boolean = false;
-  private index: number = 0;
-  private url?: string='';
-  private name:string='';
-  private iUrl: string = '';
-  private surfaceId: string = '';
-  private session?: avSession.AVSession;
-  private isLandscape:boolean = false
-  private globalVideoList:Array<VideoItem> = []
-  private seekTime: number = PlayConstants.PROGRESS_SEEK_TIME;
-  private positionX: number = PlayConstants.POSITION_X;
-  private positionY: number = PlayConstants.POSITION_Y;
-  public onPlayCompleted?: (name:string) => void
-
-  private screenWidth: number =0
-  private screenHeight: number =0
-  private statusBarHeight: number =0
-  private isYesFull: boolean = false
-  private callBack: Function = () => {
-  };
-
-  constructor() {
-    this.playerModel = new PlayerModel();
-    this.createAVPlayer();
-    window.getLastWindow(getContext(this))
-      .then((windowClass: window.Window) => {
-        let area = windowClass.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM);
-        this.screenWidth = px2fp(windowClass.getWindowProperties().windowRect.width);
-        this.screenHeight = px2fp(windowClass.getWindowProperties().windowRect.height);
-        this.statusBarHeight = px2fp(area.topRect.height);
-      })
-      .catch((error: Error) => {
-        Logger.error('[ScreenUtil] Failed to obtain the window size. Cause: ' + JSON.stringify(error));
-      })
-
-  }
-
-  public getcurrentName():string {
-    return this.name
-
-  }
-  /**
-   * Creates a videoPlayer object.
-   */
-  async createAVPlayer() {
-    let avPlayer: media.AVPlayer = await media.createAVPlayer();
-    this.avPlayer = avPlayer;
-    this.bindState();
-
-
-  }
-
-
-  async createSession() {
-    if (!this.context) {
-      return;
-    }
-    this.session = await avSession.createAVSession(this.context, 'SESSION_NAME', 'audio');
-    this.session.activate();
-    Logger.info(TAG, `session create done : sessionId : ${this.session.sessionId}`);
-    this.setAVMetadata();
-    let wantAgentInfo: wantAgent.WantAgentInfo = {
-      wants: [
-        {
-          bundleName: this.context.abilityInfo.bundleName,
-          abilityName: this.context.abilityInfo.name
-        }
-      ],
-      operationType: wantAgent.OperationType.START_ABILITIES,
-      requestCode: 0,
-      wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
-    }
-    wantAgent.getWantAgent(wantAgentInfo).then((agent) => {
-      if (this.session) {
-        this.session.setLaunchAbility(agent);
-      }
-    })
-    this.setListenerForMesFromController();
-  }
-
-  async setAVMetadata() {
-    let id = this.index;
-    try {
-      if (this.context) {
-
-        let metadata: avSession.AVMetadata = {
-          assetId: `${id}`,
-          title: this.name,
-          artist: '',
-          duration: this.duration
-        };
-        if (this.session) {
-          this.session.setAVMetadata(metadata).then(() => {
-            Logger.info(TAG, 'SetAVMetadata successfully');
-          }).catch((err: BusinessError) => {
-            Logger.error(TAG, `SetAVMetadata BusinessError: code: ${err.code}, message: ${err.message}`);
-          });
-        }
-      }
-    } catch (error) {
-      Logger.error(TAG, `SetAVMetadata try: code: ${(error as BusinessError).code},
-       message: ${(error as BusinessError).message}`);
-    }
-  }
-
-  async setListenerForMesFromController() {
-    if (!this.session) {
-      return;
-    }
-    this.session.on('play', this.playCall);
-    this.session.on('pause', this.pauseCall);
-    this.session.on('playNext', this.playNextCall);
-    this.session.on('playPrevious', this.playPreviousCall);
-  }
-  private playCall: () =>void = () => {
-    Logger.info(TAG, `on play , do play task`);
-    if (this.avPlayer !== null) {
-      this.avPlayer.play();
-    }
-  };
-  private pauseCall: () =>void = () => {
-    Logger.info(TAG, `on pause , do pause task`);
-    this.pause();
-  };
-  private playNextCall: () =>void = () => {
-    Logger.info(TAG, `on playNext , do playNext task`);
-    this.nextVideo()
-  };
-  private playPreviousCall: () =>void = () => {
-    Logger.info(TAG, `on playPrevious , do playPrevious task`);
-    this.previousVideo()
-  };
-  async unregisterSessionListener() {
-    if (!this.session) {
-      return;
-    }
-    this.session.off('play');
-    this.session.off('pause');
-    this.session.off('playNext');
-    this.session.off('playPrevious');
-  }
-
-  setIsLandscape(isLand:boolean){
-    this.isLandscape = isLand
-  }
-
-  /**
-   * AVPlayer binding event.
-   */
-  async bindState() {
-    if (this.avPlayer === null) {
-      return;
-    }
-    this.avPlayer.on(Events.STATE_CHANGE, async (state: media.AVPlayerState) => {
-      let avplayerStatus: string = state;
-      if (this.avPlayer === null) {
-        return;
-      }
-      switch (avplayerStatus) {
-        case AvplayerStatus.IDLE:
-          this.resetProgress();
-
-          this.avPlayer.url = this.url;
-
-          break;
-        case AvplayerStatus.INITIALIZED:
-          this.avPlayer.surfaceId = this.surfaceId;
-          this.avPlayer.prepare();
-          break;
-        case AvplayerStatus.PREPARED:
-          this.avPlayer.videoScaleType = 0;
-          this.setVideoSize();
-          this.avPlayer.play();
-          this.duration = this.avPlayer.duration;
-          // if(Utility.isMusicByExtension(this.name)){
-          //   this.createSession();
-          // }
-          break;
-        case AvplayerStatus.PLAYING:
-          this.avPlayer.setVolume(this.playerModel.volume);
-          this.setBright();
-          this.status = CommonConstants.STATUS_START;
-          this.watchStatus();
-          // BackgroundUtil.startContinuousTask(this.context);
-          break;
-        case AvplayerStatus.PAUSED://暂停
-          this.status = CommonConstants.STATUS_PAUSE;
-          this.watchStatus();
-          break;
-        case AvplayerStatus.COMPLETED:///播放完成
-          this.playerModel.playSpeed = PlayConstants.PLAY_SPEED;
-          this.duration = PlayConstants.PLAYER_DURATION;
-          if (!this.loop) {
-            let curIndex = this.index + PlayConstants.PLAYER_NEXT;
-            // let globalVideoList = GlobalContext.getContext().getObject('globalVideoList') as VideoItem[];
-            this.index = (curIndex === this.globalVideoList.length) ?
-            PlayConstants.PLAYER_FIRST : curIndex;
-
-            this.url = this.globalVideoList[this.index].src;
-            this.name = this.globalVideoList[this.index].name
-            this.onPlayCompleted?.(this.name)//播放完成的接口回调,在播放界面的title更新下一首的音乐或者视频名称
-          }
-          this.avPlayer.reset();
-          break;
-        case AvplayerStatus.RELEASED:
-          this.avPlayer.release();
-          this.status = CommonConstants.STATUS_STOP;
-          BackgroundUtil.stopContinuousTask(this.context);
-          this.watchStatus();
-          Logger.info('[PlayVideoModel] state released called');
-
-          break;
-        default:
-          Logger.info('[PlayVideoModel] unKnown state: ' + state);
-          break;
-      }
-    });
-    this.avPlayer.on(Events.TIME_UPDATE, (time: number) => {
-      this.initProgress(time);
-    });
-    this.avPlayer.on(Events.ERROR, () => {
-      this.playError();
-    })
-
-    // get video height and width
-    this.avPlayer.on('videoSizeChange', (width: number, height: number) => {
-      Logger.info('videoSizeChange called,and width is:' + width + ', height is :' + height);
-      this.callBack(height / width);
-    })
-  }
-
-  /**
-   * This method is triggered when the video playback page is displayed on the video list page.
-   */
-  async firstPlay(index: number, url:string, iUrl: string, surfaceId: string,globalVideoList:VideoItem[], callBack?: Function) {
-    this.index = index;
-    this.url = url;
-    this.iUrl = iUrl;
-    this.surfaceId = surfaceId;
-    this.globalVideoList = globalVideoList;
-
-
-
-    this.callBack = this.callBack
-    if (this.avPlayer === null) {
-      await this.createAVPlayer();
-    }
-    if (this.avPlayer !== null) {
-
-      this.avPlayer.url = this.url;
-      this.name = this.globalVideoList[index].name
-
-    }
-
-  }
-
-  /**
-   * Release the video player.
-   */
-  release() {
-    if (this.avPlayer !== null) {
-      this.avPlayer.release();
-    }
-  }
-
-  /**
-   * Pause Playing.
-   */
-  pause() {
-    if (this.avPlayer !== null) {
-      this.avPlayer.pause();
-    }
-  }
-
-  /**
-   * Playback mode. The options are as follows: true: playing a single video; false: playing a cyclic video.
-   */
-  setLoop() {
-    this.loop = !this.loop;
-  }
-
-  /**
-   * Set the playback speed.
-   *
-   * @param playSpeed Current playback speed.
-   */
-  setSpeed(playSpeed: number) {
-    if (this.avPlayer === null) {
-      return;
-    }
-    if (CommonConstants.OPERATE_STATE.indexOf(this.avPlayer.state) === -1) {
-      return;
-    }
-    this.playerModel.playSpeed = playSpeed;
-    this.avPlayer.setSpeed(this.playerModel.playSpeed);
-  }
-
-  /**
-   * Previous video.
-   */
-  previousVideo() {
-    if (this.avPlayer === null) {
-      return;
-    }
-    if (CommonConstants.OPERATE_STATE.indexOf(this.avPlayer.state) === -1) {
-      return;
-    }
-    this.playerModel.playSpeed = PlayConstants.PLAY_SPEED;
-    // let globalVideoList = GlobalContext.getContext().getObject('globalVideoList') as VideoItem[];
-    let curIndex = this.index - PlayConstants.CONTROL_NEXT;
-    this.index = (curIndex === -PlayConstants.CONTROL_NEXT) ?
-      (this.globalVideoList.length - PlayConstants.CONTROL_NEXT) : curIndex;
-
-    this.url = this.globalVideoList[this.index].src;
-    this.name = this.globalVideoList[this.index].name
-
-    this.avPlayer.reset();
-  }
-
-  /**
-   * Next video.
-   */
-  nextVideo() {
-    if (this.avPlayer === null) {
-      return;
-    }
-    if (CommonConstants.OPERATE_STATE.indexOf(this.avPlayer.state) === -1) {
-      return;
-    }
-    this.playerModel.playSpeed = PlayConstants.PLAY_SPEED;
-    // let globalVideoList = GlobalContext.getContext().getObject('globalVideoList') as VideoItem[];
-    let curIndex = this.index + PlayConstants.CONTROL_NEXT;
-
-    this.index = (curIndex === this.globalVideoList.length) ? PlayConstants.CONTROL_FIRST : curIndex;
-
-    this.url = this.globalVideoList[this.index].src;
-    this.name = this.globalVideoList[this.index].name
-
-    this.avPlayer.reset();
-  }
-
-  /**
-   * Switching Between Video Play and Pause.
-   */
-  switchPlayOrPause() {
-    if (this.avPlayer === null) {
-      return;
-    }
-    if (this.status === CommonConstants.STATUS_START) {
-      this.avPlayer.pause();
-    } else {
-      this.avPlayer.play();
-    }
-  }
-
-  /**
-   * Slide the progress bar to set the playback progress.
-   *
-   * @param value Value of the slider component.
-   * @param mode Slider component change event.
-   */
-  setSeekTime(value: number, mode: SliderChangeMode) {
-    if (mode === Number(SliderMode.MOVING)) {
-      this.playerModel.progressVal = value;
-      this.playerModel.currentTime = DateFormatUtil.secondToTime(Math.floor(value * this.duration /
-      CommonConstants.ONE_HUNDRED / CommonConstants.A_THOUSAND));
-    }
-    if (mode === Number(SliderMode.END) || mode === Number(SliderMode.CLICK)) {
-      this.seekTime = value * this.duration / CommonConstants.ONE_HUNDRED;
-      if (this.avPlayer !== null) {
-        this.avPlayer.seek(this.seekTime, media.SeekMode.SEEK_PREV_SYNC);
-      }
-    }
-  }
-
-
-  /**
-   * Setting the brightness.
-   */
-  setBright() {
-    let windowClass = GlobalContext.getContext().getObject('windowClass') as window.Window;
-    windowClass.setWindowBrightness(this.playerModel.bright);
-  }
-
-  /**
-   * Obtains the current video playing status.
-   */
-  getStatus() {
-    return this.status;
-  }
-
-  /**
-   * Initialization progress bar.
-   *
-   * @param time Current video playback time.
-   */
-  initProgress(time: number) {
-    let nowSeconds = Math.floor(time / CommonConstants.A_THOUSAND);
-    let totalSeconds = Math.floor(this.duration / CommonConstants.A_THOUSAND);
-    this.playerModel.currentTime = DateFormatUtil.secondToTime(nowSeconds);
-    this.playerModel.totalTime = DateFormatUtil.secondToTime(totalSeconds);
-    this.playerModel.progressVal = Math.floor(nowSeconds * CommonConstants.ONE_HUNDRED / totalSeconds);
-  }
-
-  /**
-   * Reset progress bar data.
-   */
-  resetProgress() {
-    this.seekTime = PlayConstants.PROGRESS_SEEK_TIME;
-    this.playerModel.currentTime = PlayConstants.PROGRESS_CURRENT_TIME;
-    this.playerModel.progressVal = PlayConstants.PROGRESS_PROGRESS_VAL;
-  }
-
-  /**
-   * Volume gesture method onActionStart.
-   *
-   * @param event Gesture event.
-   */
-  onVolumeActionStart(event?: GestureEvent) {
-    if (!event) {
-      return;
-    }
-    this.positionX = event.offsetX;
-  }
-
-  /**
-   * Bright gesture method onActionStart.
-   *
-   * @param event Gesture event.
-   */
-  onBrightActionStart(event?: GestureEvent) {
-    if (!event) {
-      return;
-    }
-    this.positionY = event.offsetY;
-  }
-
-  /**
-   * Gesture method onActionUpdate.
-   *
-   * @param event Gesture event.
-   */
-  onVolumeActionUpdate(event?: GestureEvent) {
-    if (!event) {
-      return;
-    }
-    if (this.avPlayer === null) {
-      return;
-    }
-    if (CommonConstants.OPERATE_STATE.indexOf(this.avPlayer.state) === -1) {
-      return;
-    }
-    if (this.playerModel.brightShow === false) {
-      this.playerModel.volumeShow = true;
-      let screenWidth = GlobalContext.getContext().getObject('screenWidth') as number;
-      let changeVolume = (event.offsetX - this.positionX) / screenWidth;
-      let volume: number = this.playerModel.volume;
-      let currentVolume = volume + changeVolume;
-      let volumeMinFlag = currentVolume <= PlayConstants.MIN_VALUE;
-      let volumeMaxFlag = currentVolume > PlayConstants.MAX_VALUE;
-      this.playerModel.volume = volumeMinFlag ? PlayConstants.MIN_VALUE :
-        (volumeMaxFlag ? PlayConstants.MAX_VALUE : currentVolume);
-      this.avPlayer.setVolume(this.playerModel.volume);
-      this.positionX = event.offsetX;
-    }
-  }
-
-  /**
-   * Gesture method onActionUpdate.
-   *
-   * @param event Gesture event.
-   */
-  onBrightActionUpdate(event?: GestureEvent) {
-    if (!event) {
-      return;
-    }
-    if (this.playerModel.volumeShow === false) {
-      this.playerModel.brightShow = true;
-      let screenHeight = GlobalContext.getContext().getObject('screenHeight') as number;
-      let changeBright = (this.positionY - event.offsetY) / screenHeight;
-      let bright: number = this.playerModel.bright;
-      let currentBright = bright + changeBright;
-      let brightMinFlag = currentBright <= PlayConstants.MIN_VALUE;
-      let brightMaxFlag = currentBright > PlayConstants.MAX_VALUE;
-      this.playerModel.bright = brightMinFlag ? PlayConstants.MIN_VALUE :
-        (brightMaxFlag ? PlayConstants.MAX_VALUE : currentBright);
-      Logger.info('onecold this.bright = ' + this.playerModel.bright)
-      this.setBright();
-      this.positionY = event.offsetY;
-    }
-  }
-
-  /**
-   * Gesture method onActionEnd.
-   */
-  onActionEnd() {
-    setTimeout(() => {
-      this.playerModel.volumeShow = false;
-      this.playerModel.brightShow = false;
-      this.positionX = PlayConstants.POSITION_X;
-      this.positionY = PlayConstants.POSITION_Y;
-    }, PlayConstants.DISAPPEAR_TIME);
-  }
-
-  /**
-   * Sets whether the screen is a constant based on the playback status.
-   */
-  watchStatus() {
-    let windowClass = GlobalContext.getContext().getObject('windowClass') as window.Window;
-    if (this.status === CommonConstants.STATUS_START) {
-      windowClass.setWindowKeepScreenOn(true);
-    } else {
-      windowClass.setWindowKeepScreenOn(false);
-    }
-  }
-
-  /**
-   * Sets the playback page size based on the video size.
-   */
-  setVideoSize() {
-    if (this.avPlayer === null) {
-      return;
-    }
-
-    let VideoWidth = this.avPlayer.width;
-    let VideoHeight = this.avPlayer.height;
-    let scale = VideoHeight/VideoWidth//视频的长高比例
-
-    let screenScale = this.screenHeight/ this.screenWidth//屏幕的长高比例
-    let screenScale2 = (this.screenHeight-this.statusBarHeight)/ this.screenWidth//屏幕的长高比例:竖屏模式下用这个screenScale2 有去掉状态栏高度
-
-
-    if(VideoHeight > VideoWidth){//竖屏视频
-
-      if(this.isLandscape){
-        this.playerModel.videoWidth = (1/(screenScale*scale))*100+'%';
-        // this.videoWidth = '26.5%';
-        this.playerModel.videoHeight = CommonConstants.FULL_PERCENT;;
-      }else{
-        this.playerModel.videoWidth = CommonConstants.FULL_PERCENT;
-        this.playerModel.videoHeight = CommonConstants.FULL_PERCENT;
-      }
-
-    }else{//横屏视频
-      if(this.isLandscape){
-        if(this.isYesFull){
-          this.playerModel.videoWidth = '100%';
-          this.playerModel.videoHeight = '100%';
-        }else{
-          // this.videoWidth = '85.8%';
-          this.playerModel.videoWidth = (1/(screenScale*scale))*100+'%';
-          this.playerModel.videoHeight = '100%';
-        }
-
-      }else{
-        this.playerModel.videoWidth = '100%';
-        // this.videoHeight = '27.5%';
-        this.playerModel.videoHeight = (scale/screenScale2)*100+'%';
-      }
-    }
-
-
-  }
-
-  /**
-   * An error is reported during network video playback.
-   */
-  playError() {
-    promptAction.showToast({
-      duration: PlayConstants.PLAY_ERROR_TIME,
-      message: $r('app.string.link_check_address_internet')
-    });
-  }
-}

+ 31 - 7
entry/src/main/ets/entryability/EntryAbility.ets

@@ -20,6 +20,7 @@ import { Utility } from '../common/util/Utility';
 import { SpiderMan } from '@simplepeng/spider-man';
 import { WXApi, WXEventHandler } from '../common/util/WXApiWrap';
 import { IBestInit } from '@ibestservices/ibest-ui';
+import { systemShare } from '@kit.ShareKit';
 
 /**
  * 主Ability类,继承自UIAbility
@@ -58,25 +59,27 @@ export default class EntryAbility extends UIAbility {
         AppStorage.setOrCreate('context', this.context);
         hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
 
-        if (!canIUse('SystemCapability.FileManagement.AppFileService.FolderAuthorization')) {
-            console.error('this api is not supported on this device');
-            return;
-        }
+        // if (!canIUse('SystemCapability.FileManagement.AppFileService.FolderAuthorization')) {
+        //     console.error('this api is not supported on this device');
+        //     return;
+        // }
         let timeout = 5000
         if(Utility.isNoble())
-            timeout = 2000
-        setTimeout(()=>{
+            timeout = 3000
+        setTimeout(async ()=>{
             this.loadDoWant(want)
+            // await this.handleParam(want)
         },timeout)
 
         this.handleWeChatCallIfNeed(want)
 
     }
 
-    onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
+    async onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): Promise<void> {
         hilog.info(0x0000, 'testTag', `onNewWant, want=${JSON.stringify(want)}`);
         super.onNewWant(want, launchParam);
         this.loadDoWant(want)
+        // await this.handleParam(want)
         this.handleWeChatCallIfNeed(want)
 
     }
@@ -107,6 +110,27 @@ export default class EntryAbility extends UIAbility {
 
     }
 
+    // 华为分享拉起接收
+    // 1. 改造 handleParam 为异步函数,让其返回 Promise
+    async handleParam(want: Want) {
+        try {
+            // 通过 await 等待异步操作完成
+            const data = await systemShare.getSharedData(want);
+            const records = data.getRecords();
+            let uri = want.uri;
+            for (const record of records) {
+                if (record.uri) {
+                    uri = record.uri;
+
+                    break;
+                }
+            }
+        } catch (error) {
+            const businessError = error as BusinessError;
+            console.error(`Failed: Code ${businessError.code}, ${businessError.message}`);
+        }
+    }
+
     onDestroy() {
         hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
     }

+ 1 - 1
entry/src/main/ets/pages/AboutPage.ets

@@ -60,7 +60,7 @@ export struct AboutPage{
   isPhoneLan() {
     if (DeviceUtil.getDeviceType() === resourceManager.DeviceType.DEVICE_TYPE_PHONE
       && this.currentBreakpoint !== BreakpointTypeEnum.SM) {
-      if (DisplayUtil.getFoldStatus() === 0 || DisplayUtil.getFoldStatus() === 2) {
+      if (DisplayUtil.getFoldStatus() === 0 ) {
         return true
       }
     }

+ 2 - 0
entry/src/main/ets/pages/MainIndex.ets

@@ -1,4 +1,6 @@
 import ScreenUtil from '../common/util/ScreenUtil'
+
+import { StreamContent } from '../view/StreamContent'
 import { window } from '@kit.ArkUI'
 import { common } from '@kit.AbilityKit'
 import { AvSessionController } from '../controller/AvSessionController'

+ 2 - 3
entry/src/main/ets/pages/NewIndex.ets

@@ -19,7 +19,6 @@ import { CSJUtil } from '../common/util/CSJUtil';
 import { LocalMusic } from '../view/LocalMusic';
 import { StreamContent } from '../view/StreamContent';
 import { AvSessionController } from '../controller/AvSessionController';
-import { ImageKnife } from '@ohos/imageknife';
 import { BreakpointSystem, BreakpointTypeEnum } from '../common/util/BreakpointSystem';
 import dataStorage from '@ohos.data.storage';
 import ConfigurationConstant from '@ohos.app.ability.ConfigurationConstant';
@@ -173,7 +172,7 @@ struct NewIndex{
     ScreenUtil.setScreenSize();
     this.bundleName =   AppUtil.getBundleName()
     this.versionName =  AppUtil.getVersionName();
-    await ImageKnife.getInstance().initFileCache(this.context, 256, 256 * 1024 * 1024)
+  // await ImageKnife.getInstance().initFileCache(this.context, 256, 256 * 1024 * 1024)
     this.isShowSponsorship = Utility.isOpenTime()
 
   }
@@ -627,7 +626,7 @@ struct NewIndex{
   isPhoneLan() {
     if (DeviceUtil.getDeviceType() === resourceManager.DeviceType.DEVICE_TYPE_PHONE
       && this.currentBreakpoint !== BreakpointTypeEnum.SM) {
-      if (DisplayUtil.getFoldStatus() === 0 || DisplayUtil.getFoldStatus() === 2) {
+      if (DisplayUtil.getFoldStatus() === 0 ) {
         return true
       }
     }

+ 1 - 1
entry/src/main/ets/pages/ScanFilePage.ets

@@ -128,7 +128,7 @@ export struct ScanFilePage{
   isPhoneLan() {
     if (DeviceUtil.getDeviceType() === resourceManager.DeviceType.DEVICE_TYPE_PHONE
       && this.currentBreakpoint !== BreakpointTypeEnum.SM) {
-      if (DisplayUtil.getFoldStatus() === 0 || DisplayUtil.getFoldStatus() === 2) {
+      if (DisplayUtil.getFoldStatus() === 0 ) {
         return true
       }
     }

+ 128 - 8
entry/src/main/ets/pages/SettingPage.ets

@@ -31,8 +31,13 @@ export struct SettingPage {
   @State isShowHistory:boolean = true //是否显示最近播放
   @State isCustomizeBg: boolean = false //自定义背景界面
   @State isCustomizeBgSheet: boolean = false //自定义背景界面
+  @State blurValue: number = 0 //背景模糊
+  @State bgBrightness: number = 0 //背景亮度
+
   @State isGridMusic: boolean = false //是否网格布局
   @State isScrollHide: boolean = false //是否滚动隐藏
+  @State isSameTimePlay: boolean = false //是否和其他app同时播放
+  @State isSavePlayMode: boolean = true
   @State customizeBgPath: string | undefined = '';
   context = getContext(this);
 
@@ -61,6 +66,9 @@ export struct SettingPage {
   static readonly IS_GRID_MUSIC: string = 'is_grid_music';
   static readonly IS_CUSTOMIZE_BG_PATH: string = 'is_customize_bg_path';
   static readonly IS_SCROLL_HIDE: string = 'isScrollHide';
+  static readonly IS_SAMETIME_PLAY: string = 'isSameTimePlay';
+  static readonly CUSTOMIZE_BG_BLUR: string = 'customize_bg_blur';
+  static readonly BG_BRIGHTNESS: string = 'bg_brightness';
 
   /** 当前断点类型(如大屏/小屏) */
   @StorageProp('currentBreakpoint') currentBreakpoint: string = BreakpointTypeEnum.MD;
@@ -153,7 +161,10 @@ export struct SettingPage {
     this.customizeBgPath  = PreferencesUtil.getStringSync(SettingPage.IS_CUSTOMIZE_BG_PATH, '')
     this.isGridMusic = PreferencesUtil.getBooleanSync(SettingPage.IS_GRID_MUSIC, false)
     this.isScrollHide = PreferencesUtil.getBooleanSync(SettingPage.IS_SCROLL_HIDE, false)
-
+    this.isSameTimePlay = PreferencesUtil.getBooleanSync(SettingPage.IS_SAMETIME_PLAY, false)
+    this.isSavePlayMode = PreferencesUtil.getBooleanSync(SettingPage.iS_SAVE_PLAY_MODE, true)
+    this.blurValue = PreferencesUtil.getNumberSync(SettingPage.CUSTOMIZE_BG_BLUR, 0)
+    this.bgBrightness = PreferencesUtil.getNumberSync(SettingPage.BG_BRIGHTNESS, 0)
     // 只用 themeMode 控制主题
     this.themeMode = PreferencesUtil.getNumberSync(SettingPage.THEME_MODE, 0)
     this.applyThemeMode(this.themeMode)
@@ -189,7 +200,7 @@ export struct SettingPage {
   isPhoneLan() {
     if (DeviceUtil.getDeviceType() === resourceManager.DeviceType.DEVICE_TYPE_PHONE
       && this.currentBreakpoint !== BreakpointTypeEnum.SM) {
-      if (DisplayUtil.getFoldStatus() === 0 || DisplayUtil.getFoldStatus() === 2) {
+      if (DisplayUtil.getFoldStatus() === 0 ) {
         return true
       }
     }
@@ -466,6 +477,50 @@ export struct SettingPage {
                 })
             }
             .height(55)
+            Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
+              .visibility(Visibility.None)
+            // 默认排序模式
+            Row() {
+              Text('保存播放模式')
+                .margin({ left: 18 })
+                .fontSize(15)
+                .fontColor(Color.Gray)
+                .fontWeight(480)
+                .layoutWeight(1)
+              Toggle({ type: ToggleType.Switch, isOn: this.isSavePlayMode })
+                .selectedColor($r('app.color.tab_item_bg'))
+                .switchPointColor(Color.White)
+                .margin({ right: 18 })
+                .onChange((checked: boolean) => {
+                  this.isSavePlayMode = checked;
+                  PreferencesUtil.put(SettingPage.iS_SAVE_PLAY_MODE, this.isSavePlayMode)
+                })
+                .width(50)
+                .height(30);
+            }
+            .height(55)
+            Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
+              .visibility(Visibility.None)
+            Row() {
+              Text('与其他应用同时播放')
+                .margin({ left: 18 })
+                .fontSize(15)
+                .fontColor(Color.Gray)
+                .fontWeight(480)
+                .layoutWeight(1)
+              Toggle({ type: ToggleType.Switch, isOn: this.isSameTimePlay })
+                .selectedColor($r('app.color.tab_item_bg'))
+                .switchPointColor(Color.White)
+                .margin({ right: 18 })
+                .onChange((checked: boolean) => {
+                  this.isSameTimePlay = checked;
+                  PreferencesUtil.put(SettingPage.IS_SAMETIME_PLAY, this.isSameTimePlay)
+                })
+                .width(50)
+                .height(30);
+            }
+            .height(55)
+            .visibility(Visibility.None)
             Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
             // 播放背景随音乐封面
             Row() {
@@ -638,12 +693,14 @@ export struct SettingPage {
   CustomizeBg() {
     Column() {
       Image( this.customizeBgPath)
-        .height('52%')
+        .height('42%')
         .alt($r('app.color.white'))
         .objectFit( ImageFit.Contain)
         .borderRadius(20)
         .clip(true)
-        .margin({left:30,right:30,bottom:30 })
+        .blur(this.blurValue)
+        .brightness(this.bgBrightness+0.8)
+        .margin({left:30,right:30,bottom:20 })
 
       Row() {
 
@@ -671,11 +728,11 @@ export struct SettingPage {
       }
       .width('100%')
       .height(58)
-      .margin({ left: 20,bottom:30 })
+      .margin({ bottom:20 })
 
       Column() {
         Row() {
-          Text('自定义背景')
+          Text('自定义背景:')
             .margin({ left: 18 })
             .fontSize(15)
             .fontColor($r('app.color.text_color'))
@@ -695,12 +752,75 @@ export struct SettingPage {
             .height(30);
         }
         .height(55)
+
       }
       .backgroundColor($r('app.color.settings_background_main'))
-      .borderRadius(20)
-      .margin({ left: 30, right: 30, top: 0, bottom: 30 })
+      .borderRadius(15)
+      .margin({ left: 30, right: 30, top: 0, bottom: 20 })
       .padding(0)
 
+      Column() {
+        Row() {
+          Text('背景模糊:')
+            .margin({ left: 18 })
+            .fontSize(15)
+            .fontColor($r('app.color.text_color'))
+            .fontWeight(480)
+          Slider({
+            value: this.blurValue,
+            min: 0,
+            max: 100,
+            step: 1,
+            style: SliderStyle.OutSet
+          })
+            .blockColor(Color.Red)
+            .trackColor($r('app.color.speed_text_color'))
+            .selectedColor($r('app.color.index_background'))
+            .trackThickness(8)
+            .onChange((value: number) => {
+              this.blurValue = value;
+              PreferencesUtil.put(SettingPage.CUSTOMIZE_BG_BLUR, this.blurValue)
+              this.sendChangeEvent()
+            })
+            .layoutWeight(1)
+        }
+        .height(55)
+      }
+      .backgroundColor($r('app.color.settings_background_main'))
+      .borderRadius(15)
+      .margin({ left: 30, right: 30, top: 0, bottom: 20 })
+      .padding(0)
+      Column() {
+        Row() {
+          Text('背景亮度:')
+            .margin({ left: 18 })
+            .fontSize(15)
+            .fontColor($r('app.color.text_color'))
+            .fontWeight(480)
+          Slider({
+            value: this.bgBrightness,
+            min: -0.4,
+            max: 0.4,
+            step: 0.1,
+            style: SliderStyle.OutSet
+          })
+            .blockColor(Color.Red)
+            .trackColor($r('app.color.speed_text_color'))
+            .selectedColor($r('app.color.index_background'))
+            .trackThickness(8)
+            .onChange((value: number) => {
+              this.bgBrightness = value;
+              PreferencesUtil.put(SettingPage.BG_BRIGHTNESS, this.bgBrightness)
+              this.sendChangeEvent()
+            })
+            .layoutWeight(1)
+        }
+        .height(55)
+      }
+      .backgroundColor($r('app.color.settings_background_main'))
+      .borderRadius(15)
+      .margin({ left: 30, right: 30, top: 0, bottom: 20 })
+      .padding(0)
 
     }
     .margin({ bottom: 30 })

+ 1 - 1
entry/src/main/ets/pages/VipPage.ets

@@ -124,7 +124,7 @@ export  struct  VipPage{
   isPhoneLan() {
     if (DeviceUtil.getDeviceType() === resourceManager.DeviceType.DEVICE_TYPE_PHONE
       && this.currentBreakpoint !== BreakpointTypeEnum.SM) {
-      if (DisplayUtil.getFoldStatus() === 0 || DisplayUtil.getFoldStatus() === 2) {
+      if (DisplayUtil.getFoldStatus() === 0 ) {
         return true
       }
     }

+ 1 - 1
entry/src/main/ets/pages/WebIndex.ets

@@ -67,7 +67,7 @@ struct  WebIndex{
   isPhoneLan() {
     if (DeviceUtil.getDeviceType() === resourceManager.DeviceType.DEVICE_TYPE_PHONE
       && this.currentBreakpoint !== BreakpointTypeEnum.SM) {
-      if (DisplayUtil.getFoldStatus() === 0 || DisplayUtil.getFoldStatus() === 2) {
+      if (DisplayUtil.getFoldStatus() === 0 ) {
         return true
       }
     }

+ 326 - 110
entry/src/main/ets/view/LocalMusic.ets

@@ -1,5 +1,6 @@
 import TitleBar from './TitleBar'
-import { Animator, curves, display, PromptAction, promptAction, router, SymbolGlyphModifier, window } from '@kit.ArkUI';
+import { Animator,
+  curves, display, PromptAction, promptAction, router, SymbolGlyphModifier, window } from '@kit.ArkUI';
 import { VideoItem } from '../viewmodel/VideoItem';
 import {
   AppUtil,
@@ -73,7 +74,6 @@ import { CommonConstants2 } from '../common/util/CommonConstants2';
 import { hilog } from '@kit.PerformanceAnalysisKit';
 import { LazyDataSource } from '../common/util/LazyDataSource';
 import MediaTable from '../common/util/MediaTable';
-import { ImageKnifeComponent } from '@ohos/imageknife';
 import NetAxiosUtil from '../common/util/NetAxiosUtil';
 import ImageUtils from '../common/util/ImageUtils';
 import { ringtone } from '@kit.RingtoneKit';
@@ -86,6 +86,7 @@ import { HSBColorPicker, HSBColorPickerLayout } from '@keke/color-picker'
 import { DEBUG } from 'BuildProfile';
 import { LrcParser } from '@sgaolei/lrc_parser';
 import { IBestIcon } from "@ibestservices/ibest-ui";
+import app, { AppResponse } from '@system.app';
 
 const TAG = 'LocalMusic';
 
@@ -130,7 +131,7 @@ interface GeneratedObjectLiteralInterface_1 {
   // DRM资源,需要配置支持的DRM类型, 以chinaDRM为例。
   drmScheme: string;
 }
-
+const ITEM_HEIGHT: number = 58; // 列表项高度
 //功能强大的音乐播放器
 @Preview
 @Component
@@ -172,10 +173,21 @@ export struct LocalMusic {
   @State isShowHistory:boolean = true //是否显示最近播放
   @State isCustomizeBg: boolean = false //自定义背景界面
   @State isGridMusic: boolean = false //是否网格布局
+  @State isScrollHide: boolean = false //是否滚动隐藏
+  @State isSameTimePlay: boolean = false //是否和其他app同时播放
   @State customizeBgPath: string | undefined = '';
   @State isDarkMode: boolean = false
   @State lyricTextWeight: number = 400
   @State currentSwiperIndex: number = 0
+  @State blurValue: number = 0 //背景模糊
+  @State bgBrightness: number = 0 //背景亮度
+  private listScroller: ListScroller = new ListScroller()
+  private listArea: Area = {
+    width: 0,
+    height: 0,
+    position: {},
+    globalPosition: {}
+  }
   @StorageProp('currentColorMode') @Watch('onColorModeChange') currentMode: number =
     ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT;
 
@@ -363,21 +375,7 @@ export struct LocalMusic {
 
   // 组件生命周期
   aboutToAppear() {
-    this.sortType = PreferencesUtil.getNumberSync(SettingPage.SORT_TYPE, 4)
-    this.isCustomizeBg  = PreferencesUtil.getBooleanSync(SettingPage.IS_CUSTOMIZE_BG, false)
-    this.customizeBgPath  = PreferencesUtil.getStringSync(SettingPage.IS_CUSTOMIZE_BG_PATH, '')
-    this.isGridMusic = PreferencesUtil.getBooleanSync(SettingPage.IS_GRID_MUSIC, false)
-    if(this.isCustomizeBg){
-      this.titleBarModel.setRightTitleStateNormalStyleColor(Color.Transparent)
-      this.titleBarModel.setTitleBarBackground(Color.Transparent)
-      this.titleBarModel.setTitleBarBottomLineColor(Color.Transparent)
-      this.titleBarModel.setLeftTitleStateNormalStyleColor(Color.Transparent)
-
-    }else{
-      this.titleBarModel.setTitleBarBackground($r('app.color.title_bar_bg'))
-      this.titleBarModel.setTitleBarBottomLineColor($r('app.color.title_bar_bg'))
-      // this.titleBarModel  .setRightTitleBackground($r('app.color.title_bar_bg'))
-    }
+    this.initSetting()
 
     Utility.getAppName(getContext(this)).then((appName: string) => {
       this.appName = appName
@@ -385,11 +383,6 @@ export struct LocalMusic {
     this.packName = AppUtil.getBundleName()
     this.loadCacheFromStorage(); // 加载缓存
 
-    this.isSavePlayMode = PreferencesUtil.getBooleanSync(SettingPage.iS_SAVE_PLAY_MODE, true)
-    if (this.isSavePlayMode) {
-      this.playType = PreferencesUtil.getNumberSync('musicPlayType', 0)
-    }
-
     this.historyList = PreferencesUtil.getSync(LocalMusic.HISTORY_MUSIC, this.historyList) as Array<VideoItem>
 
     this.mkDownLoadDir()
@@ -426,7 +419,8 @@ export struct LocalMusic {
     });
 
     let event: Callback<InterruptEvent> = (event) => {
-      LogUtils.getInstance().LOGI(`event: ${JSON.stringify(event)}`);
+      LogUtils.getInstance().LOGI(`onecold 与其他应用音频冲突 被截断点event: ${JSON.stringify(event)}`);
+      this.savePlaybackPosition()
       if (event.hintType === InterruptHintType.INTERRUPT_HINT_PAUSE) {
         this.pause();
       } else if (event.hintType === InterruptHintType.INTERRUPT_HINT_RESUME) {
@@ -479,11 +473,20 @@ export struct LocalMusic {
     context.getApplicationContext().setColorMode(colorMode)
   }
 
-  doChangeSetting(){
+
+  initSetting(){
     this.sortType = PreferencesUtil.getNumberSync(SettingPage.SORT_TYPE, 4)
     this.isCustomizeBg  = PreferencesUtil.getBooleanSync(SettingPage.IS_CUSTOMIZE_BG, false)
     this.customizeBgPath  = PreferencesUtil.getStringSync(SettingPage.IS_CUSTOMIZE_BG_PATH, '')
     this.isGridMusic = PreferencesUtil.getBooleanSync(SettingPage.IS_GRID_MUSIC, false)
+    this.isScrollHide = PreferencesUtil.getBooleanSync(SettingPage.IS_SCROLL_HIDE, false)
+    this.isSameTimePlay = PreferencesUtil.getBooleanSync(SettingPage.IS_SAMETIME_PLAY, false)
+    this.isSavePlayMode = PreferencesUtil.getBooleanSync(SettingPage.iS_SAVE_PLAY_MODE, true)
+    this.blurValue = PreferencesUtil.getNumberSync(SettingPage.CUSTOMIZE_BG_BLUR, 0)
+    this.bgBrightness = PreferencesUtil.getNumberSync(SettingPage.BG_BRIGHTNESS, 0)
+    if (this.isSavePlayMode) {
+      this.playType = PreferencesUtil.getNumberSync('musicPlayType', 0)
+    }
     if(this.isCustomizeBg){
       this.titleBarModel.setRightTitleStateNormalStyleColor(Color.Transparent)
       this.titleBarModel.setTitleBarBackground(Color.Transparent)
@@ -495,7 +498,10 @@ export struct LocalMusic {
       this.titleBarModel.setRightTitleStateNormalStyleColor($r('app.color.title_bar_bg'))
       this.titleBarModel.setLeftTitleStateNormalStyleColor($r('app.color.title_bar_bg'))
     }
+  }
 
+  doChangeSetting(){
+    this.initSetting()
     this.doUpdateData()
   }
 
@@ -503,21 +509,16 @@ export struct LocalMusic {
     if (this.currentWidthBreakpoint !== WidthBreakpoint.WIDTH_SM ||
       (this.currentHeightBreakpoint !== HeightBreakpoint.HEIGHT_MD &&
         this.currentHeightBreakpoint !== HeightBreakpoint.HEIGHT_SM)) {
-      this.hideDone = false;
-      this.getUIContext().animateTo({
-        duration: 300
-      }, () => {
-        this.bottomBarHeight = 55 + 0;
-        this.topBarHeight = 50 + 0;
-        this.barOpacity = 1;
-        this.currentYOffset = 0;
-        this.isHiding = false;
-      });
+      this.setBarHeightNormal()
+
 
     }
   }
 
   onPageShow() {
+    app.setImageCacheCount(100);
+    // 设置解码前图片数据内存缓存上限为100MB (100MB=100*1024*1024B=104857600B)
+    app.setImageRawDataCacheSize(104857600);
     Logger.info('onecold onPageShow currentBreakpoint= ' + this.currentBreakpoint)
   }
 
@@ -1759,9 +1760,11 @@ export struct LocalMusic {
           Column() {
             this.tabTitle()
             this.listViewTitle()
-            this.getGridView()
-            this.getListView()
-
+            if(this.isGridMusic){
+              this.getGridView()
+            }else {
+              this.getListView()
+            }
           }
           .layoutWeight(1)
           .height('100%')
@@ -1876,13 +1879,15 @@ export struct LocalMusic {
         }
         .hitTestBehavior(HitTestMode.Transparent)
         .position({ bottom: 0 }) // 将 Row 固定在底部
-        .opacity(this.barOpacity)
+        .opacity(this.barBottomOpacity)
       }
       .width('100%')
       .height('100%')
       .backgroundImage(this.isCustomizeBg?this.customizeBgPath:$r('app.color.bottom_control_background'))
       .backgroundImageSize(this.isCoverOpacity()?{width:'100%'}:{ height: '100%'})
       .backgroundImagePosition(Alignment.Center)
+      .backdropBlur(this.blurValue)
+      .backgroundBrightness({rate:this.isCustomizeBg?0.1:0,lightUpDegree:this.bgBrightness})
       .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM])
 
     }
@@ -2195,7 +2200,7 @@ export struct LocalMusic {
 
 
     }
-    .height(58)
+    .height(ITEM_HEIGHT)
     .width('100%')
     .visibility(this.isShowDir(item.name)?Visibility.Visible:Visibility.None)
     .opacity(this.opacityItem) // 绑定透明度
@@ -2312,7 +2317,7 @@ export struct LocalMusic {
 
     }
     .width('100%')
-    .height(58)
+    .height(ITEM_HEIGHT)
     .justifyContent(FlexAlign.SpaceBetween)
     .stateStyles({
       pressed: { opacity: 0.6 } // 按压反馈
@@ -2533,6 +2538,7 @@ export struct LocalMusic {
           }
         })
         .onClick(() => {
+          // ToastUtil.showToast('当前的手机的折叠状态 ='+DisplayUtil.getFoldStatus())
           if (this.modeType === 0) {
             if (ArrayUtil.isNotEmpty(this.getCurFileList())) {
               this.doPlay(this.getCurFileList()[0])
@@ -2810,10 +2816,13 @@ export struct LocalMusic {
     this.itemMove(index, index + 1)
   }
 
+  private scroller: Scroller = new Scroller();
+  @State startIndex:number = 0
+  @State endIndex:number = 0
   @Builder
   getGridView(){
 
-    Grid() {
+    Grid(this.scroller) {
       LazyForEach(this.dataSource, (item: VideoItem, index: number) => {
         GridItem() {
           Stack({ alignContent: Alignment.Center }) {
@@ -2861,6 +2870,13 @@ export struct LocalMusic {
                     this.left(index);
                   }
                 })
+
+
+                // if (this.offsetY > this.FIX_VP_Y * 0.7) {
+                //   this.scroller.scrollToIndex(index + 10, true,ScrollAlign.CENTER);
+                // }
+
+
               })
               .onActionEnd(() => {
                 this.getUIContext().animateTo({ curve: curves.interpolatingSpring(0, 1, 400, 38) }, () => {
@@ -2887,15 +2903,20 @@ export struct LocalMusic {
     .width('100%')
     .height('100%')
     .editMode(true)
-    .margin({ bottom: this.isCoverOpacity() ? 50 : 165 })
+    .margin({ bottom: this.isCoverOpacity() ? 80 : 175 })
     .layoutWeight(1)
     .scrollBar(BarState.Off)
     .supportAnimation(true)
-    .cachedCount(20)
+    // .cachedCount(5)
     .columnsTemplate('1fr '.repeat(this.currentWidthBreakpoint === WidthBreakpoint.WIDTH_SM ? 2 : 4))
     .rowsGap(12)
     .visibility(this.isGridMusic?Visibility.Visible:Visibility.None)
     .enableScrollInteraction(true)
+    // 滚轴滑动,记录下滑动时的起始位置和终点位置
+    .onScrollIndex((start: number, end: number) => {
+      this.startIndex = start
+      this.endIndex = end
+    })
     .onScrollFrameBegin((offset: number) => {
       //滚动小屏幕 比如puraX外屏和手机横屏可以隐藏bottomBarHeight topBarHeight
       if(this.isPhoneLan()){
@@ -2903,7 +2924,11 @@ export struct LocalMusic {
       }else if (this.currentWidthBreakpoint !== WidthBreakpoint.WIDTH_SM ||
         (this.currentHeightBreakpoint !== HeightBreakpoint.HEIGHT_MD &&
           this.currentHeightBreakpoint !== HeightBreakpoint.HEIGHT_SM)) {
-        this.setBarHeightNormal()
+        if(this.isScrollHide){
+          this.setBarHeightHide2(offset)
+        }else{
+          this.setBarHeightNormal()
+        }
       }else{
         this.setBarHeightHide(offset)
       }
@@ -2921,7 +2946,7 @@ export struct LocalMusic {
     Stack() {
 
       Column() {
-        Image(StrUtil.isEmpty(item.pixelMapPath) ? $r('app.media.ic_avatar6') : item.pixelMapPath)
+        Image(StrUtil.isEmpty(item.pixelMapPath) ?Utility.getMusisBg2(index) : item.pixelMapPath)
           .height(150)
           .width(150)
           .alt($r('app.media.ic_avatar6'))
@@ -3130,14 +3155,14 @@ export struct LocalMusic {
       }
       .width(180)
     }
-    .height('40%')
+    .height(item.type === CommonConstants.TYPE_IS_DIR ?'22%':'40%')
   }
 
-
+  private listMaxScrollOffsetY: number = 0
   @Builder
   getListView() {
 
-    List() {
+    List({ scroller: this.listScroller }) {
       LazyForEach(this.dataSource, (item: VideoItem, index: number) => {
         ListItem() {
           Column() {
@@ -3191,7 +3216,9 @@ export struct LocalMusic {
           .animation({ curve: Curve.Sharp, duration: 300 })
 
         }
-        .swipeAction((((this.modeType==3||this.modeType==2)&&this.isCanBack) && item.type !== CommonConstants.TYPE_IS_CSJAD &&
+        .swipeAction((
+          (this.modeType==0||this.modeType==1 ||((this.modeType==3||this.modeType==2)&&this.isCanBack))
+          && item.type !== CommonConstants.TYPE_IS_CSJAD &&
           !this.isHistory) ? { end: this.DeleteButton(item, index, item.filePath) } : {}) //左滑
         .onClick(() => {
 
@@ -3254,7 +3281,23 @@ export struct LocalMusic {
                     this.itemMove(indexA, indexA - 1);
                   });
                 }
+                let curListOffset = this.listScroller.currentOffset()
+                // 获取手指信息
+                let fingerInfo = event.fingerList[0]
+                let clickPercentY =
+                  (fingerInfo.globalY - Number(this.listArea.globalPosition.y)) / Number(this.listArea.height)
+                if (clickPercentY > 0.8 && !this.listScroller.isAtEnd()) {
+                  let scrollVelocity = clickPercentY > 0.9 ? 4 : 2
+                  if (this.listMaxScrollOffsetY - curListOffset.yOffset > scrollVelocity + 5) {
+                    this.listScroller.scrollTo({xOffset: 0, yOffset: curListOffset.yOffset += scrollVelocity})
 
+                  }
+                } else if (clickPercentY < 0.2 && curListOffset.yOffset >= 0) {
+                  let scrollVelocity = clickPercentY < 0.1 ? 4 : 2
+                  if (curListOffset.yOffset > scrollVelocity + 5) {
+                    this.listScroller.scrollTo({xOffset: 0, yOffset: curListOffset.yOffset -= scrollVelocity})
+                  }
+                }
 
               })
               .onActionEnd((event: GestureEvent) => {
@@ -3288,7 +3331,7 @@ export struct LocalMusic {
       }, (item: VideoItem) => item.filePath)
     }
     // .divider({ strokeWidth: 1, color: this.isDarkMode? '#333333':'#ffe9f0f0' })
-    .margin({ bottom: this.isCoverOpacity() ? 50 : 158 })
+    .margin({ bottom: this.isCoverOpacity() ? 80 : 166 })
     .cachedCount(30)
     .borderRadius(20)
     .layoutWeight(1)
@@ -3309,14 +3352,25 @@ export struct LocalMusic {
         xxl: 20
       }).getValue(this.currentBreakpoint)
     )
+    .onAreaChange((oldValue: Area, newValue: Area) => {
+      this.listArea = newValue
+      this.listMaxScrollOffsetY = this.videoLocalList.length * (ITEM_HEIGHT) - 10
+    })
     .onScrollFrameBegin((offset: number) => {
+
       //滚动小屏幕 比如puraX外屏和手机横屏可以隐藏bottomBarHeight topBarHeight
       if(this.isPhoneLan()){
         this.setBarHeightHide(offset)
       }else if (this.currentWidthBreakpoint !== WidthBreakpoint.WIDTH_SM ||
         (this.currentHeightBreakpoint !== HeightBreakpoint.HEIGHT_MD &&
           this.currentHeightBreakpoint !== HeightBreakpoint.HEIGHT_SM)) {
+        if(this.isScrollHide){
+          this.setBarHeightHide2(offset)
+
+        }else{
           this.setBarHeightNormal()
+        }
+
       }else{
         this.setBarHeightHide(offset)
       }
@@ -3334,6 +3388,7 @@ export struct LocalMusic {
       this.bottomBarHeight = 55 + 0;
       this.topBarHeight = 50 + 0;
       this.barOpacity = 1;
+      this.barBottomOpacity = 1
       this.currentYOffset = 0;
       this.isHiding = false;
     });
@@ -3346,9 +3401,11 @@ export struct LocalMusic {
         this.bottomBarHeight = this.bottomBarHeight * (1 - this.currentYOffset / 100);
         this.topBarHeight = this.topBarHeight * (1 - this.currentYOffset / 100);
         this.barOpacity = 1 - this.currentYOffset / 100;
+        this.barBottomOpacity =  1 - this.currentYOffset / 100;
       } else {
         this.topBarHeight = 0;
         this.bottomBarHeight = 0;
+        this.barBottomOpacity = 0
         this.barOpacity = 0;
         this.hideDone = true;
       }
@@ -3360,6 +3417,33 @@ export struct LocalMusic {
         duration: 300
       }, () => {
         this.bottomBarHeight = 55 + 0;
+        this.topBarHeight = 50 + 0;
+        this.barOpacity = 1;
+        this.barBottomOpacity = 1
+        this.currentYOffset = 0;
+        this.isHiding = false;
+      });
+    }
+  }
+  //这个方法没隐藏bottomBar,只隐藏topBar
+  setBarHeightHide2(offset: number){
+    if (offset > 0 && !this.hideDone) {
+      this.currentYOffset += offset;
+      if (this.currentYOffset <= 100) {
+        this.topBarHeight = this.topBarHeight * (1 - this.currentYOffset / 100);
+        this.barOpacity = 1 - this.currentYOffset / 100;
+      } else {
+        this.topBarHeight = 0;
+        this.barOpacity = 0;
+        this.hideDone = true;
+      }
+      this.isHiding = true;
+    }
+    if (offset < 0 && this.isHiding) {
+      this.hideDone = false;
+      this.getUIContext().animateTo({
+        duration: 300
+      }, () => {
         this.topBarHeight = 50 + 0;
         this.barOpacity = 1;
         this.currentYOffset = 0;
@@ -4607,6 +4691,7 @@ export struct LocalMusic {
   @StorageProp('currentWidthBreakpoint') currentWidthBreakpoint: WidthBreakpoint | undefined = WidthBreakpoint.WIDTH_SM;
   @State topBarHeight: number = 50
   @State barOpacity: number = 1
+  @State barBottomOpacity: number = 1
   private hideDone: boolean = false;
   @State currentYOffset: number = 0;
   @State bottomBarHeight: number = 55;
@@ -4642,7 +4727,7 @@ export struct LocalMusic {
   isPhoneLan() {
     if (DeviceUtil.getDeviceType() === resourceManager.DeviceType.DEVICE_TYPE_PHONE
       && this.currentBreakpoint !== BreakpointTypeEnum.SM) {
-      if (DisplayUtil.getFoldStatus() === 0 || DisplayUtil.getFoldStatus() === 2) {
+      if (DisplayUtil.getFoldStatus() === 0 ) {
         return true
       }
     }
@@ -4882,6 +4967,7 @@ export struct LocalMusic {
     this.setHighLyricTextSize(PreferencesUtil.getNumberSync('HighLyricTextSize', 1.23))
     this.lyricController.setLineSpace(PreferencesUtil.getNumberSync('LyricLineSpace', 52))
     this.changeLyricColor(PreferencesUtil.getStringSync('LyricColor', '#FFFFFF'))
+    this.changeLyricHightLightColor(PreferencesUtil.getStringSync('LyricHighLightColor', '#FFFFFF'))
     this.isHightLightCenter = PreferencesUtil.getBooleanSync(SettingPage.IS_SHOW_SIMI, false)
     this.lyricController.setHightLightCenter(this.isHightLightCenter)
     this.lyricTextWeight = PreferencesUtil.getNumberSync('lyricTextWeight',400)
@@ -5782,6 +5868,7 @@ export struct LocalMusic {
 
   @State timeOffset: number = 0.0
   @State currentLyricColor: string = '#FFFFFF'
+  @State currentHighLightLyricColor: string = '#FF4081'
   // 歌词字号状态
   @State currentLyricSize: number = 20
   // 高亮歌词放大倍数
@@ -5789,6 +5876,25 @@ export struct LocalMusic {
   @State currentLyricLineSpace: number = 52 //{
   @State currentLyricAlignMode: number = 1
   @State blurDegree: number = 2
+  @State isShowSelectColor: boolean = false
+  @State isShowHLSelectColor: boolean = false
+  // 构建颜色选择器
+  @Builder
+  SelectColor(isHighColor:boolean) {
+    Row({space: 10}) {
+      HSBColorPicker({
+        color: '#FFFFFF',
+        radius: 8,
+        layout: HSBColorPickerLayout.COLUMN,
+        predefine: ['#8b27f4', '#73f9fc', '#fffe55', '#f5cee3', '#eb4827', '#e93bf4', '#3e68f4', '#c5e6d3', '#e4e4e4', '#fa7105'],
+        onChange:(value: string) =>isHighColor?this.changeLyricHightLightColor(value):this.changeLyricColor(value)
+      })
+        .height(250)
+        .layoutWeight(1)
+        .padding(25)
+    }
+    .width('66%')
+  }
 
   // 构建字号控制器
   @Builder
@@ -5814,7 +5920,7 @@ export struct LocalMusic {
               .onClick(() => {
                 this.setLyricAlignMode(index)
               })
-              .margin({ left: 8, right: 8 })
+              .margin({ left: 10, right: 8 })
           })
         }
         .width('76%')
@@ -5823,22 +5929,148 @@ export struct LocalMusic {
       }
       .margin({ top:10,bottom:10,right:20,left:20})
 
+      Row() {
+        Text(`高亮居中:`)
+          .fontSize(14)
+          .fontColor(Color.White)
+
+        Column(){
+          Toggle({ type: ToggleType.Switch, isOn: this.isHightLightCenter })
+            .selectedColor($r('app.color.tab_item_bg'))
+            .switchPointColor(Color.White)
+            .onChange((checked: boolean) => {
+              this.isHightLightCenter = checked;
+              PreferencesUtil.put(SettingPage.IS_SHOW_SIMI, this.isHightLightCenter)
+              this.lyricController.setHightLightCenter(this.isHightLightCenter)
+            })
+            .width(50)
+            .height(30)
+            .alignSelf(ItemAlign.Start)
+            .margin({ left: 12 })
+          Blank()
+
+        }
+        .width('76%')
+
+      }
+      .margin({
+        left: 20,
+        right: 15,
+        top: 10,
+        bottom: 10
+      })
       Row() {
         Text(`歌词颜色:`)
           .fontSize(14)
           .fontColor(Color.White)
+        Text(this.currentLyricColor)
+          .fontSize(15)
+          .fontColor(Color.White)
+          .margin({ left: 12, right: 12 })
+        Column(){}
+        .backgroundColor(this.currentLyricColor)
+        .margin({ right: 12 })
+        .borderRadius(20)
+        .height(28)
+        .width(28)
 
-        Row({space: 10}) {
-          HSBColorPicker({
-            color: '#FFFFFF',
-            radius: 8,
-            layout: HSBColorPickerLayout.COLUMN,
-            onChange:(value: string) =>this.changeLyricColor(value)
-          })
-            .height(88)
-            .layoutWeight(1)
-            .padding({left:15,right:35})
+        Button({ type: ButtonType.Capsule, stateEffect: true }) {
+          Row() {
+            SymbolGlyph($r('sys.symbol.paintbrush'))
+              .fontColor([Color.White])
+              .effectStrategy(1)
+            Text(`选择颜色`)
+              .fontSize(13)
+              .margin({ left: 10 })
+              .fontColor(Color.White)
+
+          }
+        }
+        .backgroundColor(Color.Transparent)
+        .border({
+          color: '#FFFFFF',
+          radius: 20,
+          width: 1.8
+        })
+        .height(36)
+        .width(110)
+        .onClick(()=>{
+          this.isShowSelectColor = !this.isShowSelectColor
+        })
+        .bindPopup(this.isShowSelectColor, {
+          builder: this.SelectColor(false),
+          placement: Placement.Top,
+          // autoCancel: true,
+          mask: {color:'#33000000'},
+          // popupColor: Color.Yellow,
+          enableArrow: false,//是否显示箭头
+          showInSubWindow: false,
+          onStateChange: (e) => {
+            if (!e.isVisible) {
+              this.isShowSelectColor = false
+            }
+          }
+        })
+
+
+
+      }
+      .width('76%')
+      .margin({ top:10,bottom:10,right:45,left:20})
+
+      Row() {
+        Text(`高亮颜色:`)
+          .fontSize(14)
+          .fontColor(Color.White)
+        Text(this.currentHighLightLyricColor)
+          .fontSize(15)
+          .fontColor(Color.White)
+          .margin({ left: 12, right: 12 })
+        Column(){}
+        .backgroundColor(this.currentHighLightLyricColor)
+        .margin({ right: 12 })
+        .borderRadius(20)
+        .height(28)
+        .width(28)
+        Button({ type: ButtonType.Capsule, stateEffect: true }) {
+          Row() {
+            SymbolGlyph($r('sys.symbol.paintbrush'))
+              .fontColor([Color.White])
+              .effectStrategy(1)
+            Text(`选择颜色`)
+              .fontSize(13)
+              .margin({ left: 10 })
+              .fontColor(Color.White)
+
+          }
         }
+        .backgroundColor(Color.Transparent)
+        .border({
+          color: '#FFFFFF',
+          radius: 20,
+          width: 1.8
+        })
+        .height(36)
+        .width(110)
+        .onClick(()=>{
+          this.isShowHLSelectColor = !this.isShowHLSelectColor
+        })
+        .bindPopup(this.isShowHLSelectColor, {
+          builder: this.SelectColor(true),
+          placement: Placement.Top,
+          // autoCancel: true,
+          mask: {color:'#33000000'},
+          // popupColor: Color.Yellow,
+          enableArrow: false,//是否显示箭头
+          showInSubWindow: false,
+          onStateChange: (e) => {
+            if (!e.isVisible) {
+              this.isShowHLSelectColor = false
+            }
+          }
+        })
+
+
 
       }
       .width('76%')
@@ -5881,7 +6113,6 @@ export struct LocalMusic {
           .fontSize(14)
           .fontColor(Color.White)
 
-
         Slider({
           value: this.currentHightLyricSize,
           min: 1,
@@ -6003,32 +6234,6 @@ export struct LocalMusic {
         bottom: 15
       })
 
-      Row() {
-        Text(`高亮居中:`)
-          .fontSize(14)
-          .fontColor(Color.White)
-        Column(){
-          Toggle({ type: ToggleType.Switch, isOn: this.isHightLightCenter })
-            .selectedColor($r('app.color.tab_item_bg'))
-            .switchPointColor(Color.White)
-            .onChange((checked: boolean) => {
-              this.isHightLightCenter = checked;
-              PreferencesUtil.put(SettingPage.IS_SHOW_SIMI, this.isHightLightCenter)
-              this.lyricController.setHightLightCenter(this.isHightLightCenter)
-            })
-            .width(50)
-            .height(30)
-        }
-        .justifyContent(FlexAlign.Start)
-          .width('76%')
-
-      }
-      .margin({
-        left: 20,
-        right: 15,
-        top: 5,
-        bottom: 15
-      })
 
       Row() {
         this.pushLyricButton($r('app.media.cut_current'), 0, '本地歌词')
@@ -6085,10 +6290,16 @@ export struct LocalMusic {
     this.currentLyricColor = color
     this.lyricController
       .setTextColor(this.currentLyricColor)
-      .setHighlightColor(this.currentLyricColor)
     PreferencesUtil.putSync('LyricColor', this.currentLyricColor)
   }
 
+  private changeLyricHightLightColor(color: string) {
+    this.currentHighLightLyricColor = color
+    this.lyricController
+      .setHighlightColor(this.currentHighLightLyricColor)
+    PreferencesUtil.putSync('LyricHighLightColor', this.currentHighLightLyricColor)
+  }
+
   // 构建时间控制器
   @Builder
   BuildTimeControls() {
@@ -6101,7 +6312,7 @@ export struct LocalMusic {
 
       Row() {
         this.PrecisionTimeButton($r('app.media.ic_previous'), -0.5, ' -0.5s ')
-        this.PrecisionTimeButton($r('app.media.loop'), 0, 'RESET')
+        this.PrecisionTimeButton($r('app.media.loop'), 0, '重置')
         this.PrecisionTimeButton($r('app.media.ic_next'), 0.5, ' +0.5s ')
       }
       .justifyContent(FlexAlign.Center)
@@ -6112,25 +6323,27 @@ export struct LocalMusic {
   // 精度按钮组件
   @Builder
   PrecisionTimeButton(icon: Resource, step: number, label: string) {
-    Column() {
-      Image(icon)
-        .width(28)
-        .margin({ bottom: 5 })
-        .opacity(this.isButtonDisabled(step) ? 0.5 : 1)
+    Button({ type: ButtonType.Capsule, stateEffect: true }) {
+      Column() {
+        Image(icon)
+          .width(28)
+          .margin({ bottom: 5 })
+          .opacity(this.isButtonDisabled(step) ? 0.5 : 1)
 
-      Text(label)
-        .fontSize(12)
-        .fontColor('#FFFFFF')
+        Text(label)
+          .fontSize(12)
+          .fontColor('#FFFFFF')
+      }
     }
+    .backgroundColor(Color.Transparent)
     .enabled(!this.isButtonDisabled(step))
     .onClick(() => this.handlePrecisionAdjust(step))
     .padding(5)
-    .width(60)
-    .height(60)
+    .width(66)
+    .height(66)
     .margin({ left: 18, right: 18 })
     .border({
       color: '#FFFFFF',
-      radius: 20,
       width: 1.8
     })
   }
@@ -6169,17 +6382,19 @@ export struct LocalMusic {
   // 导入  本地歌词 搜索歌词
   @Builder
   pushLyricButton(icon: Resource, step: number, label: string) {
-    Row() {
-      Image(icon)
+    Button({ type: ButtonType.Capsule, stateEffect: true }) {
+      Row() {
+        Image(icon)
         .width(14)
         .margin({ left: 13 })
 
-      Text(label)
-        .fontSize(12)
-        .margin({ left: 6 })
-        .fontColor('#FFFFFF')
+        Text(label)
+          .fontSize(12)
+          .margin({ left: 6 })
+          .fontColor('#FFFFFF')}
+
     }
-    // .visibility(step === 1 ? (Utility.isNoble() ? Visibility.Visible : Visibility.None) : Visibility.Visible)
+
     .onClick(() => {
       switch (step) {
         case 0:
@@ -6219,6 +6434,7 @@ export struct LocalMusic {
     })
     .padding(5)
     .width(110)
+    .backgroundColor(Color.Transparent)
     .height(40)
     .margin({ left: 6, right: 6 })
     .border({

+ 1 - 4
entry/src/main/module.json5

@@ -94,12 +94,9 @@
         "skills": [
           {
             "actions": [
-//              "action.system.home",
               "ohos.want.action.sendData"
             ],
-//            "entities": [
-//              "entity.system.home"
-//            ],
+
             // 目标应用在配置支持接收的数据类型时,需穷举支持的UTD,比如:支持全部图片类型,可声明:general.image
             // maxFileSupported 对于归属指定类型的文件,标识一次支持接收的最大数量。默认为0,代表不支持此类文件的分享。文件类型归属关系参考:@ohos.data.uniformTypeDescriptor (标准化数据定义与描述)
             "uris": [

+ 10 - 3
lib/src/main/ets/bean/LyricLine.ts

@@ -1,19 +1,26 @@
+import { LyricWord } from './LyricWord'
 /**
  * The line info of lyric.
  */
 export class LyricLine {
-    readonly text: string
+     text: string
     readonly beginTime: number
     nextTime: number
-
+    words: LyricWord[] = []
     /**
      * @param text The text of lyric line.
      * @param beginTime The begin timestamp of this lyric line.
      * @param nextTime The begin timestamp of the next lyric line.
      */
-    constructor(text: string, beginTime: number, nextTime: number) {
+    constructor(text: string, beginTime: number, nextTime: number,words?: LyricWord[] ) {
         this.text = text
         this.beginTime = beginTime
         this.nextTime = nextTime
+        this.words = words || []
+    }
+
+    // 新增方法:判断是否有逐字歌词
+    hasWords(): boolean {
+        return this.words.length > 0
     }
 }

+ 12 - 0
lib/src/main/ets/bean/LyricWord.ts

@@ -0,0 +1,12 @@
+// 逐字歌词的数据结构
+export class LyricWord {
+  word: string
+  startTime: number
+  duration: number
+
+  constructor(word: string, startTime: number, duration: number) {
+    this.word = word
+    this.startTime = startTime
+    this.duration = duration
+  }
+}

+ 140 - 16
lib/src/main/ets/parse/LyricParser.ts

@@ -2,6 +2,7 @@ import { IParser } from './IParser';
 import { Lyric } from '../bean/Lyric';
 import { LyricLine } from '../bean/LyricLine';
 import { printD, printW } from '../extensions/Extension';
+import { LyricWord } from '../bean/LyricWord';
 
 /**
  * The parser to parse the string array of a standard lyric file.
@@ -28,7 +29,7 @@ export class LyricParser implements IParser {
         let album = ""
         let by = ""
         let offset = 0
-        const ignoredTags = [ 'hash', 'sign', 'qq', 'total']; // 定义需要忽略的标签
+        const ignoredTags = [ 'hash', 'sign', 'qq', 'total','Outro']; // 定义需要忽略的标签
         for (let i = 0; i < src.length; i++) {
             let line = src[i]
             console.info(`content The line of file:line ${line}`);
@@ -37,6 +38,7 @@ export class LyricParser implements IParser {
                 printW("the lyric line is empty, carriage return or line feed, line index= " + i)
                 continue
             }
+
             // 检查是否是需要忽略的标签
             const shouldIgnore = ignoredTags.some(tag  => line.indexOf(tag)  > 0);
             if (shouldIgnore) {
@@ -54,23 +56,40 @@ export class LyricParser implements IParser {
             } else if (line.indexOf("offset") > 0) {
                 offset = Number.parseInt(this.parseIdTag(line))
             } else {
-                // [00:00.10]画心 - 张靓颖
-                // [01:05.49][02:08.40]看不穿 是你失落的魂魄
-                let spr = line.split(']')
-                if (spr.length <= 1) {
-                    printW("the lyric line is no timestamp, line index= " + i)
-                    continue
+
+                // 新增逐字歌词解析逻辑[mm:ss.xx] <mm:ss.xx>
+                if (this.isWordByWordLyric(line)) {
+                    const { timeline, words } = this.parseWordByWordLine(line, offset);
+                    lyricLines.push(new LyricLine('', timeline, -1, words))
+                    continue;
                 }
-                // parse text
-                let text = spr[spr.length-1]
-                // printD("text= " + text)
-                // parse timeline
-                for (let i = 0;i < spr.length - 1; i++) {
-                    let timeline = spr[i].replace("[", "")
-                    let timeStamp = this.parseTimeline(timeline)
-                    // printD("timestamp= " + timeStamp)
-                    lyricLines.push(new LyricLine(text, timeStamp - offset, -1))
+
+                    // 新增:逐字歌词[]检测方括号逐字歌词格式 [mm:ss.xxx] 文字
+                if (this.isSquareBracketWordByWordLyric(line))  {
+                    const { timeline, words } = this.parseSquareBracketWordLine(line,  offset);
+                    if (words.length  > 0) {
+                        lyricLines.push(new  LyricLine('', timeline, -1, words))
+                    }
+                } else {
+                    // 原逻辑处理,但支持逐字歌词
+                    // [00:00.10]画心 - 张靓颖
+                    // [01:05.49][02:08.40]看不穿 是你失落的魂魄
+                    let spr = line.split(']');
+                    if (spr.length <= 1) {
+                        printW("the lyric line is no timestamp, line index= " + i)
+                        continue
+                    }
+                    // parse text
+                    let text = spr[spr.length-1]
+                    // ... 原来的文本解析逻辑保持不变 ...
+                    for (let i = 0; i < spr.length - 1; i++) {
+                        let timeline = spr[i].replace("[", "");
+                        let timeStamp = this.parseTimeline(timeline);
+                        lyricLines.push(new LyricLine(text, timeStamp - offset, -1));
+                    }
                 }
+
+
             }
         }
         lyricLines.sort((l1, l2) => {
@@ -85,10 +104,115 @@ export class LyricParser implements IParser {
                 lyricLine.nextTime = next.beginTime
             }
         }
+        // 为逐字歌词填充text(拼接所有歌词词)
+        this.populateTextForWordLyrics(lyricLines);
         let result = new Lyric(artist, title, album, by, offset, lyricLines)
         return result
     }
 
+
+    // 检测方括号格式的逐字歌词 [00:00.000]文[00:01.000]字
+    private isSquareBracketWordByWordLyric(line: string): boolean {
+        return /\[\d{2}:\d{2}\.\d{2,3}\]\S/.test(line);
+    }
+
+    // 解析方括号格式的逐字歌词行
+    private parseSquareBracketWordLine(line: string, offset: number):
+        { timeline: number, words: LyricWord[] } {
+
+        const words: LyricWord[] = [];
+        let firstTimeline = -1;
+
+        // 正则匹配:[00:00.000]中文字
+        const regex = /\[(\d{2}:\d{2}\.\d{2,3})\]([^\[]*)/g;
+        let match;
+
+        while ((match = regex.exec(line))  !== null) {
+            const timeStr = match[1];   // 时间部分 00:00.000
+            const word = match[2].trim(); // 歌词文本
+
+            if (!word) continue; // 跳过空词
+
+            const timeline = this.parseTimeline2(timeStr)  - offset;
+            if (firstTimeline < 0) firstTimeline = timeline;
+
+            words.push(new  LyricWord(word, timeline, 0));
+        }
+
+        // 计算每个词的持续时间
+        for (let i = 0; i < words.length  - 1; i++) {
+            words[i].duration = words[i + 1].startTime - words[i].startTime;
+        }
+        if (words.length  > 0 && words[words.length - 1].duration === 0) {
+            words[words.length - 1].duration = 200; // 默认200ms
+        }
+
+        return { timeline: firstTimeline, words };
+    }
+
+    /******************** 时间解析增强 ********************/
+    private parseTimeline2(timeString: string): number {
+        // 增强支持毫秒/厘秒解析
+        const parts = timeString.split(':');
+        const minutes = parseInt(parts[0], 10);
+
+        const secondParts = parts[1].split('.');
+        const seconds = parseInt(secondParts[0], 10);
+        const fraction = parseInt(secondParts[1], 10);
+
+        // 根据小数位长度判断时间精度
+        const milliseconds = secondParts[1].length === 2 ?
+            fraction * 10 : // 厘秒转毫秒 (01 -> 10ms)
+            fraction;       // 毫秒直接使用
+
+        return minutes * 60000 + seconds * 1000 + milliseconds;
+    }
+
+    // 判断是否是逐字歌词行
+    private isWordByWordLyric(line: string): boolean {
+        const hasBracketTimestamp = /$$\d{2}:\d{2}\.\d{2,3}$$\S/.test(line);
+        const hasAngleTimestamp = /<\d{2}:\d{2}\.\d{2,3}>/.test(line);
+        return hasBracketTimestamp || hasAngleTimestamp;
+    }
+
+    // 解析逐字歌词行
+    private parseWordByWordLine(line: string, offset: number): { timeline: number, words: LyricWord[] } {
+        const words: LyricWord[] = [];
+        let firstTimeline = -1;
+        const regex = /((?:<|$$)(\d{2}:\d{2}\.\d{2,3})(?:>|$$))([^<\[]*)/g;
+        let match;
+
+        while ((match = regex.exec(line)) !== null) {
+            const [_, tag, timeStr, word] = match;
+            if (word.trim() === '') continue;
+
+            const timeline = this.parseTimeline(timeStr) - offset;
+            if (firstTimeline < 0) firstTimeline = timeline;
+
+            words.push(new LyricWord(word.trim(), timeline, 0));
+        }
+
+        // 设置每个词持续时间(下一个词开始时间-当前词开始时间)
+        for (let i = 0; i < words.length - 1; i++) {
+            words[i].duration = words[i + 1].startTime - words[i].startTime;
+        }
+        if (words.length > 0 && words[words.length - 1].duration === 0) {
+            // 最后一个词持续200ms
+            words[words.length - 1].duration = 200;
+        }
+
+        return { timeline: firstTimeline, words };
+    }
+
+    // 为逐字歌词拼接整行文本
+    private populateTextForWordLyrics(lyricLines: LyricLine[]) {
+        lyricLines.forEach(line => {
+            if (line.words.length > 0) {
+                line.text = line.words.map(word => word.word).join('');
+            }
+        });
+    }
+
     private parseIdTag(line: string): string {
         let spr = line.split(":")
         let spr1 = spr[1]

+ 61 - 30
lib/src/main/ets/view/LyricView2.ets

@@ -3,6 +3,7 @@ import { LyricController } from '../LyricController';
 import { Lyric } from '../bean/Lyric';
 import { ListAdapter } from '../extensions/ListAdapter';
 import { LyricLine } from '../bean/LyricLine';
+import { LyricWord } from '../bean/LyricWord';
 
 /**
  * A component to display the lyric with scroll animation.
@@ -69,6 +70,7 @@ export struct LyricView2 {
     @State isLoadingData: boolean = false
     private loadTimeout = -1
     @State isHightLightCenter: boolean = true
+    @State currentMediaPosition: number = 0
 
     private onDataChangedListener = (lyric: Lyric | null) => {
         clearTimeout(this.loadTimeout)
@@ -79,6 +81,7 @@ export struct LyricView2 {
         }, 300)
     }
     private onPositionChangedListener = (mediaPosition: number) => {
+        this.currentMediaPosition = mediaPosition
         this.onPositionChanged(mediaPosition)
     }
     private onInvalidatedListener = (reLayout: boolean) => {
@@ -168,7 +171,7 @@ export struct LyricView2 {
 
     private calculateOpacityFactor(index: number, currentIndex: number): number {
         const distance = Math.abs(index - currentIndex);
-        return Math.max(0.5, 1 - distance * 0.18); // 透明度随着距离增加而减小
+        return Math.max(0.15, 1 - distance * 0.18); // 透明度随着距离增加而减小
     }
 
 
@@ -181,32 +184,15 @@ export struct LyricView2 {
             LazyForEach(this.listAdapter, (item: LyricLine, index: number) => {
                 ListItem() {
                     Stack() {
-                        Text(item.text)
-                            .fontSize(this.textSize)
-                            .opacity(this.calculateOpacityFactor(index, this.currentIndex))
-                            .blur( this.calculateBlurFactor(index, this.currentIndex))
-                            .textAlign(this.alignMode == 'center' ? TextAlign.Center : TextAlign.Start)
-                            .scale({
-                                x: index == this.currentIndex ? this.controller.getHighlightScale() : 1,
-                                y: index == this.currentIndex ? this.controller.getHighlightScale() : 1,
-                                centerX: this.alignMode == 'center' ? '50%' : 0
-                            })
-                            .fontColor(index == this.currentIndex ? this.textHighlightColor : this.textColor)
-                            // .fontWeight(this.textWeight)
-                            .fontWeight(index == this.currentIndex && this.isHighlightBold ? FontWeight.Bold :
-                            this.textWeight)
-                                // .padding({
-                            .animation({ duration: this.animDuration, curve: Curve.FastOutSlowIn })
-                            .width(this.alignMode == 'center'?'100%':'76%')
-
-                        // if (this.seekUIStyle == 'listItem' && index == this.seekIndex && item.text.length > 0
-                        //     && this.enableSeek && this.isUserTouching) {
-                            // Row() {
-                            //     Image($r('app.media.cclyric_play'))
-                            //         .width(24)
-                            //         .height(24)
-                            //         .fillColor(this.seekUIColor)
-                            //         .objectFit(ImageFit.Fill)
+                        // 逐字歌词渲染
+                        if (item.hasWords() && item.words.length > 0) {
+                            this.WordByWordLyric(item, index)
+                        } else {
+                            // 普通歌词渲染(原有逻辑)
+                            this.NormalLyricLine(item, index)
+                        }
+
+
                             Text(this.scrollDurationText)
                                 .fontSize(this.textSize)
                                 .fontColor(this.seekUIColor)
@@ -214,9 +200,7 @@ export struct LyricView2 {
                                 .width(100)
                                 .visibility(this.seekUIStyle == 'listItem' && index == this.seekIndex && item.text.length > 0
                                       && this.enableSeek && this.isUserTouching?Visibility.Visible:Visibility.Hidden)
-                            // }.width('100%')
-                            // .justifyContent(FlexAlign.SpaceBetween)
-                        // }
+
                     }
                     .align(Alignment.End)
 
@@ -281,6 +265,53 @@ export struct LyricView2 {
         })
     }
 
+    @Builder
+    NormalLyricLine(item: LyricLine, index: number) {
+        Text(item.text)
+            .fontSize(this.textSize)
+            .opacity(this.calculateOpacityFactor(index, this.currentIndex))
+            .blur(this.calculateBlurFactor(index, this.currentIndex))
+            .textAlign(this.alignMode == 'center' ? TextAlign.Center : TextAlign.Start)
+            .scale({
+                x: index == this.currentIndex ? this.controller.getHighlightScale() : 1,
+                y: index == this.currentIndex ? this.controller.getHighlightScale() : 1,
+                centerX: this.alignMode == 'center' ? '50%' : 0
+            })
+            .fontColor(index == this.currentIndex ? this.textHighlightColor : this.textColor)
+            .fontWeight(index == this.currentIndex && this.isHighlightBold ? FontWeight.Bold : this.textWeight)
+            .animation({ duration: this.animDuration, curve: Curve.FastOutSlowIn })
+            .width(this.alignMode == 'center' ? '100%' : '76%')
+    }
+
+    @Builder
+    WordByWordLyric(item: LyricLine, index: number) {
+        Row({ space: 0 }) {
+            ForEach(item.words, (word: LyricWord, wordIndex: number) => {
+
+
+                Text(word.word)
+                    .fontSize(index == this.currentIndex ?this.textSize*this.controller.getHighlightScale():this.textSize)
+                    .fontColor(this.currentMediaPosition >= word.startTime ?
+                        index == this.currentIndex ? this.textHighlightColor : this.textColor : this.textColor)
+                    .fontWeight(this.currentMediaPosition >= word.startTime && this.isHighlightBold ?
+                        index == this.currentIndex? FontWeight.Bold : this.textWeight: this.textWeight)
+                    .margin(0)
+                    .opacity(this.calculateOpacityFactor(index, this.currentIndex))
+                    .blur(this.calculateBlurFactor(index, this.currentIndex))
+                    .animation({
+                        // 动画播放速度
+                        tempo: 0.8,
+                        // 动画持续时间,单位是毫秒
+                        duration: 777,
+                        // 动画缓动函数
+                        curve: Curve.FastOutSlowIn
+                    })
+            })
+        }
+        .justifyContent(this.alignMode === 'center' ? FlexAlign.Center : FlexAlign.Start)
+        .width(this.alignMode == 'center' ? '100%' : '76%')
+    }
+
     private handleSeekAction() {
         clearTimeout(this.seekUiHideTimeout);
         let targetPosition = this.listAdapter.getData(this.seekIndex).beginTime;

+ 0 - 19
oh-package-lock.json5

@@ -10,10 +10,8 @@
     "@changwei/chardet@^1.0.0": "@changwei/chardet@1.0.0",
     "@chinalike/popup@^0.0.7": "@chinalike/popup@0.0.7",
     "@keke/color-picker@^1.0.4": "@keke/color-picker@1.0.4",
-    "@ohos/gpu_transform@^1.0.2": "@ohos/gpu_transform@1.0.4",
     "@ohos/hamock@1.0.0": "@ohos/hamock@1.0.0",
     "@ohos/hypium@1.0.19": "@ohos/hypium@1.0.19",
-    "@ohos/imageknife@^3.2.3": "@ohos/imageknife@3.2.3",
     "@ohos/lottie@^2.0.19": "@ohos/lottie@2.0.19",
     "@ohos/pulltorefresh@^2.1.1": "@ohos/pulltorefresh@2.1.1",
     "@pura/harmony-dialog@^1.0.6": "@pura/harmony-dialog@1.0.6",
@@ -72,13 +70,6 @@
       "resolved": "https://repo.harmonyos.com/ohpm/@keke/color-picker/-/color-picker-1.0.4.har",
       "registryType": "ohpm"
     },
-    "@ohos/gpu_transform@1.0.4": {
-      "name": "@ohos/gpu_transform",
-      "version": "1.0.4",
-      "integrity": "sha512-PrKlOK66kzObw/ANIzt55YMrOLLmtrhmAZIE2c/60GBoTl7+NLxONeHA2NsDZuiW+A0KnD4QylDYWH4/yo8T0w==",
-      "resolved": "https://repo.harmonyos.com/ohpm/@ohos/gpu_transform/-/gpu_transform-1.0.4.har",
-      "registryType": "ohpm"
-    },
     "@ohos/hamock@1.0.0": {
       "name": "@ohos/hamock",
       "version": "1.0.0",
@@ -93,16 +84,6 @@
       "resolved": "https://repo.harmonyos.com/ohpm/@ohos/hypium/-/hypium-1.0.19.har",
       "registryType": "ohpm"
     },
-    "@ohos/imageknife@3.2.3": {
-      "name": "@ohos/imageknife",
-      "version": "3.2.3",
-      "integrity": "sha512-QAuTdId4UyDUra53YWqbBlKegujty+LYfFRlYTGNckSYQ9tXtECWmrgyvTrjO2rVaGPey4+tJ/+3i7zQ9tZF7Q==",
-      "resolved": "https://repo.harmonyos.com/ohpm/@ohos/imageknife/-/imageknife-3.2.3.har",
-      "registryType": "ohpm",
-      "dependencies": {
-        "@ohos/gpu_transform": "^1.0.2"
-      }
-    },
     "@ohos/lottie@2.0.19": {
       "name": "@ohos/lottie",
       "version": "2.0.19",

+ 0 - 1
oh-package.json5

@@ -25,7 +25,6 @@
     "@seagazer/cclyric": "file:./lib",
     "@changwei/chardet": "^1.0.0",
     "@cashier_alipay/cashiersdk": "^15.8.32",
-    "@ohos/imageknife": "^3.2.3",
     "@simplepeng/spider-man": "^1.0.1",
     "@keke/color-picker": "^1.0.4",
     "@sgaolei/lrc_parser": "^1.0.0",

+ 0 - 24
oh_modules/.ohpm/lock.json5

@@ -51,10 +51,6 @@
           "specifier": "^15.8.32",
           "version": "15.8.32"
         },
-        "@ohos/imageknife": {
-          "specifier": "^3.2.3",
-          "version": "3.2.3"
-        },
         "@simplepeng/spider-man": {
           "specifier": "^1.0.1",
           "version": "1.0.1"
@@ -275,26 +271,6 @@
       "dynamic": false,
       "maskedByOverrideDependencyMap": false
     },
-    "@ohos/imageknife@3.2.3": {
-      "integrity": "sha512-QAuTdId4UyDUra53YWqbBlKegujty+LYfFRlYTGNckSYQ9tXtECWmrgyvTrjO2rVaGPey4+tJ/+3i7zQ9tZF7Q==",
-      "storePath": "oh_modules/.ohpm/@ohos+imageknife@3.2.3",
-      "dependencies": {
-        "@ohos/gpu_transform": "1.0.4"
-      },
-      "dynamicDependencies": {},
-      "dev": false,
-      "dynamic": false,
-      "maskedByOverrideDependencyMap": false
-    },
-    "@ohos/gpu_transform@1.0.4": {
-      "integrity": "sha512-PrKlOK66kzObw/ANIzt55YMrOLLmtrhmAZIE2c/60GBoTl7+NLxONeHA2NsDZuiW+A0KnD4QylDYWH4/yo8T0w==",
-      "storePath": "oh_modules/.ohpm/@ohos+gpu_transform@1.0.4",
-      "dependencies": {},
-      "dynamicDependencies": {},
-      "dev": false,
-      "dynamic": false,
-      "maskedByOverrideDependencyMap": false
-    },
     "@simplepeng/spider-man@1.0.1": {
       "integrity": "sha512-rulclyolBPbYUzEav8crOr5WDuQs+zVWpLtefE2ei0YmBIbVUrpJN8mDRPNI+5kHZdkbYufKWyM/IzbVB/KoKg==",
       "storePath": "oh_modules/.ohpm/@simplepeng+spider-man@1.0.1",