Jelajahi Sumber

修改文档

chendeben 1 tahun lalu
induk
melakukan
1a190f4e18
3 mengubah file dengan 147 tambahan dan 357 penghapusan
  1. 15 2
      README.md
  2. 59 355
      README_zh.md
  3. 73 0
      开发者文档.md

+ 15 - 2
README.md

@@ -1,3 +1,16 @@
-# ctv_player_oho
+# TTMusic 鸿蒙音乐播放器
 
-ctv_player_oho 鸿蒙版本
+TTMusic 是基于 OpenHarmony(鸿蒙)平台开发的本地音乐播放器,支持本地音频文件的管理、播放、歌单、收藏、歌词显示、封面管理、批量操作等丰富功能。
+
+## 主要功能
+- 支持多种音频格式的本地播放
+- 歌单管理、收藏夹、最近播放
+- 歌词同步显示与导入
+- 音乐封面自动提取与自定义
+- 批量导入、剪切、复制、删除、重命名
+- 艺术家、专辑、媒体库分组浏览
+- 支持倍速播放、音频焦点、循环播放等
+- 适配多种鸿蒙设备,支持平板、折叠屏等
+
+## 开源协议
+本项目基于 [Apache 2.0 License](LICENSE) 开源,欢迎自由使用和参与贡献。

+ 59 - 355
README_zh.md

@@ -1,366 +1,70 @@
-# ijkplayer
+# TTMusic 鸿蒙音乐播放器
 
 ## 简介
->  ijkplayer是OpenHarmony环境下可用的一款基于FFmpeg的视频播放器。
+TTMusic 是一款基于 OpenHarmony(鸿蒙)平台开发的本地音乐播放器,支持多种音频格式的本地播放,具备歌单管理、歌词显示、封面管理、批量操作等丰富功能,适配多种鸿蒙设备。
+
+## 主要功能
+- 支持多种音频格式的本地播放
+- 歌单管理、收藏夹、最近播放
+- 歌词同步显示与导入
+- 音乐封面自动提取与自定义
+- 批量导入、剪切、复制、删除、重命名
+- 艺术家、专辑、媒体库分组浏览
+- 支持倍速播放、音频焦点、循环播放等
+- 适配平板、折叠屏等多种鸿蒙设备
+
+## 安装与运行
+1. 使用 DevEco Studio 打开本项目。
+2. 下载并安装 OpenHarmony SDK,API 版本建议 >= 9。
+3. 连接支持的鸿蒙设备或模拟器。
+4. 编译并运行项目。
 
-## 演示
-<img src="preview_zh.gif" width="100%"/>
-
-## 编译运行
-
-### ffmpeg soundtouch yuv依赖
-
-1. FFmpeg:基于B站的FFmpeg版本(ff4.0--ijk0.8.8--20210426--001):[FFmpeg源码链接](https://github.com/bilibili/FFmpeg/tags), [FFmpeg](https://gitee.com/openharmony-sig/tpc_c_cplusplus/tree/support_x86/thirdparty/FFmpeg-ff4.0)可以在交叉编译出库文件和头文件,编译可参考[FFmpeg-ff4.0编译指导](https://gitee.com/openharmony-sig/tpc_c_cplusplus/blob/support_x86/thirdparty/FFmpeg-ff4.0/README_zh.md)。
-
-   1. 编译成功后会在lycium\usr生成FFmpeg-ff4.0文件夹改名为ffmpeg。
-
-2. soudtouch:基于B站的soudtouch版本(ijk-r0.1.2-dev):[soundtouch源码链接](https://github.com/bilibili/soundtouch/branches) ,soundtouch须在交叉编译出库文件和头文件。
-
-   1. 把doc目录下的soundtouch-ijk文件夹拷贝到thirdparty下在lycium文件夹执行./build.sh soundtouch-ijk可以在lycium\usr目录下编译出soundtouch的静态库和头文件
-
-3. yuv:基于B站的yuv版本(ijk-r0.2.1-dev):[yuv源码链接](https://github.com/bilibili/libyuv/branches),yuv须在交叉编译出库文件和头文件。
-   1. 把doc目录下的libyuv-ijk文件夹拷贝到thirdparty下在lycium文件夹执行./build.sh libyuv-ijk可以在lycium\usr目录下编译出yuv的静态库和头文件
-
-4. 把编译生成的ffmpeg文件夹拷贝到ijkplayer/src/main/cpp/third_party/ffmpeg下
-
-5. 把编译生成的openssl、soundtouch、yuv的文件夹,拷贝到工程的ijkplayer/src/main/cpp/third_party下,如图所示:
-
-![img.png](image/img.png)
-
-### IDE编译运行
-
-1、通过IDE工具下载依赖SDK,Tools->SDK Manager->OpenHarmony SDK 把native选项勾上下载,API版本>=9
-
-2、开发板选择RK3568,[ROM下载地址](http://ci.openharmony.cn/workbench/cicd/dailybuild/dailylist). 选择开发板类型是rk3568,请使用最新的版本
-
-3、使用git clone下载源码,不要直接通过gitee网页的方式下载
-
-## 下载安装
-```shell
-ohpm install @ohos/ijkplayer
-```
 ## 使用说明
-```
-   import { IjkMediaPlayer } from "@ohos/ijkplayer";
-   import type { OnPreparedListener } from "@ohos/ijkplayer";
-   import type { OnVideoSizeChangedListener } from "@ohos/ijkplayer";
-   import type { OnCompletionListener } from "@ohos/ijkplayer";
-   import type { OnBufferingUpdateListener } from "@ohos/ijkplayer";
-   import type { OnErrorListener } from "@ohos/ijkplayer";
-   import type { OnInfoListener } from "@ohos/ijkplayer";
-   import type { OnSeekCompleteListener } from "@ohos/ijkplayer";
-   import { LogUtils } from "@ohos/ijkplayer";
-```
-### 在UI中配置XComponent控件
-```
-    XComponent({
-      id: 'xcomponentId',
-      type: 'surface',
-      libraryname: 'ijkplayer_napi'
-    })
-    .onLoad((context) => {
-      this.initDelayPlay(context);
-     })
-     .onDestroy(() => {
-     })
-     .width('100%')
-     .aspectRatio(this.aspRatio)
-```
-
-### 播放
-```
-    //单例模式
-    let mIjkMediaPlayer = IjkMediaPlayer.getInstance();
-    //多实例模式
-    let mIjkMediaPlayer = new IjkMediaPlayer();
-    // 如果播放视频,调用setContext接口,参数1为XComponent回调的context, 可选参数2为XComponent的id属性值
-    mIjkMediaPlayer.setContext(this.mContext, "xcomponentId");
-    // 如果只播放音频,则调用setAudioId接口,参数为音频对象的id
-    // mIjkMediaPlayer.setAudioId('audioIjkId');
-    // 设置debug模式
-    mIjkMediaPlayer.setDebug(true);
-    // 初始化配置
-    mIjkMediaPlayer.native_setup();
-    // 设置视频源
-    mIjkMediaPlayer.setDataSource(url); 
-    // 设置视频源http请求头
-    let headers =  new Map([
-      ["user_agent", "Mozilla/5.0 BiliDroid/7.30.0 (bbcallen@gmail.com)"],
-      ["referer", "https://www.bilibili.com"]
-    ]);
-    mIjkMediaPlayer.setDataSourceHeader(headers);
-    // 使用精确寻帧 例如,拖动播放后,会寻找最近的关键帧进行播放,很有可能关键帧的位置不是拖动后的位置,而是较前的位置.可以设置这个参数来解决问题
-    mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "enable-accurate-seek", "1");
-    // 预读数据的缓冲区大小
-    mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max-buffer-size", "102400");
-    // 停止预读的最小帧数
-    mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "min-frames", "100");
-    // 启动预加载
-    mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", "1");
-    // 设置无缓冲,这是播放器的缓冲区,有数据就播放
-    mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "packet-buffering", "0");
-    // 跳帧处理,放CPU处理较慢时,进行跳帧处理,保证播放流程,画面和声音同步
-    mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", "5");
-    // 最大缓冲cache是3s, 有时候网络波动,会突然在短时间内收到好几秒的数据
-    // 因此需要播放器丢包,才不会累积延时
-    // 这个和第三个参数packet-buffering无关。
-    mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max_cached_duration", "3000");
-    // 无限制收流
-    mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "infbuf", "1");
-    // 屏幕常亮
-    mIjkMediaPlayer.setScreenOnWhilePlaying(true);
-    // 设置超时
-    mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "timeout", "10000000");
-    mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "connect_timeout", "10000000");
-    mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "listen_timeout", "10000000");
-    mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "addrinfo_timeout", "10000000");
-    mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "dns_cache_timeout", "10000000");
-    
-    let mOnVideoSizeChangedListener: OnVideoSizeChangedListener = {
-      onVideoSizeChanged(width: number, height: number, sar_num: number, sar_den: number) {
-        that.aspRatio = width / height;
-        LogUtils.getInstance()
-          .LOGI("setOnVideoSizeChangedListener-->go:" + width + "," + height + "," + sar_num + "," + sar_den)
-        that.hideLoadIng();
-      }
-    }
-    mIjkMediaPlayer.setOnVideoSizeChangedListener(mOnVideoSizeChangedListener);
-    let mOnPreparedListener: OnPreparedListener = {
-      onPrepared() {
-        LogUtils.getInstance().LOGI("setOnPreparedListener-->go");
-      }
-    }
-    mIjkMediaPlayer.setOnPreparedListener(mOnPreparedListener);
-
-    let mOnCompletionListener: OnCompletionListener = {
-      onCompletion() {
-        LogUtils.getInstance().LOGI("OnCompletionListener-->go")
-        that.currentTime = that.stringForTime(mIjkMediaPlayer.getDuration());
-        that.progressValue = PROGRESS_MAX_VALUE;
-        that.stop();
-      }
-    }
-    mIjkMediaPlayer.setOnCompletionListener(mOnCompletionListener);
-
-    let mOnBufferingUpdateListener: OnBufferingUpdateListener = {
-      onBufferingUpdate(percent: number) {
-        LogUtils.getInstance().LOGI("OnBufferingUpdateListener-->go:" + percent)
-      }
-    }
-    mIjkMediaPlayer.setOnBufferingUpdateListener(mOnBufferingUpdateListener);
-
-    let mOnSeekCompleteListener: OnSeekCompleteListener = {
-      onSeekComplete() {
-        LogUtils.getInstance().LOGI("OnSeekCompleteListener-->go")
-        that.startPlayOrResumePlay();
-      }
-    }
-    mIjkMediaPlayer.setOnSeekCompleteListener(mOnSeekCompleteListener);
-
-    let mOnInfoListener: OnInfoListener = {
-      onInfo(what: number, extra: number) {
-        LogUtils.getInstance().LOGI("OnInfoListener-->go:" + what + "===" + extra)
-      }
-    }
-    mIjkMediaPlayer.setOnInfoListener(mOnInfoListener);
-
-    let mOnErrorListener: OnErrorListener = {
-      onError(what: number, extra: number) {
-        LogUtils.getInstance().LOGI("OnErrorListener-->go:" + what + "===" + extra)
-        that.hideLoadIng();
-        prompt.showToast({
-          message:"亲,视频播放异常,系统开小差咯"
-        });
-      }
-    }
-    mIjkMediaPlayer.setOnErrorListener(mOnErrorListener);
-
-    mIjkMediaPlayer.setMessageListener();
-
-    mIjkMediaPlayer.prepareAsync();
-
-    mIjkMediaPlayer.start();
-```
-### 暂停
-```
-   mIjkMediaPlayer.pause();
-```
-### 停止
-```
-   mIjkMediaPlayer.stop();
-```
-### 重置
-```
-   mIjkMediaPlayer.reset();
-```
-### 释放
-```
-   mIjkMediaPlayer.release();
-```
-### 快进、后退
-```
-   mIjkMediaPlayer.seekTo(msec);
-```
-### 倍数播放
-```
-   mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "soundtouch", "1");
-   mIjkMediaPlayer.setSpeed("2f");
-```
-### 屏幕常亮
-```
-   mIjkMediaPlayer.setScreenOnWhilePlaying(true);
-```
-### 循环播放
-```
-   mIjkMediaPlayer.setLoopCount(true);
-```
-### 设置音量
-```
-   mIjkMediaPlayer.setVolume(leftVolume, rightVolume);
-```
-### 音频焦点监控
-```
-   import { InterruptEvent, InterruptHintType } from '@ohos/ijkplayer/src/main/ets/ijkplayer/IjkMediaPlayer';
-   import { Callback } from '@ohos.base';
-   // 音频焦点变化回调处理
-   let event:  Callback<InterruptEvent> = (event) => {
-     console.info(`event: ${JSON.stringify(event)}`);
-     if (event.hintType === InterruptHintType.INTERRUPT_HINT_PAUSE) {
-       this.pause();
-     } else if (event.hintType === InterruptHintType.INTERRUPT_HINT_RESUME) {
-       this.startPlayOrResumePlay();
-     } else if (event.hintType === InterruptHintType.INTERRUPT_HINT_STOP) {
-       this.stop();
-     }
-   }
-   // 设置监听音频中断事件
-   mIjkMediaPlayer.on('audioInterrupt', event);
-
-   // 取消订阅音频中断事件
-   mIjkMediaPlayer.off('audioInterrupt');
-```
-
-### 开启硬解码
-```
-   // 开启h264与h265硬解码
-   ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-all-videos", "1");
-   // 开启h265硬解码
-   ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-hevc", "1");
-```
-
-## 接口说明
-
-### IjkMediaPlayer.getInstance()
-| 接口名                           | 参数                                                           | 返回值               | 说明                                                           |
-|-------------------------------|--------------------------------------------------------------|-------------------|--------------------------------------------------------------|
-| setContext                    | context: object, id?: string                                 | void              | 设置XComponent回调的context, 设置XComponent的id属性值(可选), 播放视频时需要调用该接口 |
-| setDebug                      | open: boolean                                                | void              | 设置日志开关                                                       |
-| native_setup                  | 无                                                            | void              | 初始化配置                                                        |
-| setDataSource                 | url: string                                                  | void              | 设置视频源地址                                                      |
-| setDataSourceHeader           | headers: Map<string, string>                                 | void              | 设置视频源的HTTP请求头                                                |
-| setOption                     | category:string, key: string, value: string                  | void              | 设置播放前预设参数(用于设置char类型参数)                                      |
-| setOptionLong                 | category:string, key: string, value: string                  | void              | 设置播放前预设参数(用于设置int类型参数)                                       |
-| prepareAsync                  | 无                                                            | void              | 加载视频                                                         |
-| start                         | 无                                                            | void              | 播放视频                                                         |
-| stop                          | 无                                                            | void              | 停止播放                                                         |
-| pause                         | 无                                                            | void              | 暂停播放                                                         |
-| reset                         | 无                                                            | void              | 视频重置                                                         | 
-| release                       | 无                                                            | void              | 释放资源                                                         |
-| seekTo                        | msec: string                                                 | void              | 快进、后退                                                        |
-| setScreenOnWhilePlaying       | on: boolean                                                  | void              | 设置屏幕常亮                                                       |
-| setSpeed                      | speed: string                                                | void              | 设置播放倍数                                                       |
-| getSpeed                      | 无                                                            | number            | 获取设置的倍数                                                      |
-| isPlaying                     | 无                                                            | boolean           | 查看是否正在播放状态                                                   |
-| setOnVideoSizeChangedListener | listener: OnVideoSizeChangedListener                         | void              | 设置获取视频宽高回调监听                                                 |
-| setOnPreparedListener         | listener: OnPreparedListener                                 | void              | 设置视频准备就绪回调监听                                                 |
-| setOnInfoListener             | listener: OnInfoListener                                     | void              | 设置播放器的各种状态回调监听                                               |
-| setOnErrorListener            | listener: OnErrorListener                                    | void              | 设置播放异常回调监听                                                   |
-| setOnBufferingUpdateListener  | listener: OnBufferingUpdateListener                          | void              | 设置buffer缓冲回调监听                                               |
-| setOnSeekCompleteListener     | listener: OnSeekCompleteListener                             | void              | 设置快进后退回调监听                                                   |
-| setMessageListener            | 无                                                            | void              | 设置视频监听器到napi用于接收回调                                           |
-| getVideoWidth                 | 无                                                            | number            | 获取视频宽度                                                       |
-| getVideoHeight                | 无                                                            | number            | 获取视频高度                                                       |
-| getVideoSarNum                | 无                                                            | number            | 获取视频宽高比的分子                                                   |
-| getVideoSarDen                | 无                                                            | number            | 获取视频宽高比的分母                                                   |
-| getDuration                   | 无                                                            | number            | 获取视频总的时长                                                     |
-| getCurrentPosition            | 无                                                            | number            | 获取视频播放当前位置                                                   |
-| getAudioSessionId             | 无                                                            | number            | 获取音频sessionID                                                |
-| setVolume                     | leftVolume: string,rightVolume:string                        | void              | 设置音量                                                         |
-| setLoopCount                  | looping: boolean                                             | void              | 设置循环播放                                                       |
-| isLooping                     | 无                                                            | boolean           | 查看当前是否循环播放                                                   |
-| selectTrack                   | track: string                                                | void              | 选择轨道                                                         |
-| deselectTrack                 | track: string                                                | void              | 删除选择轨道                                                       |
-| getMediaInfo                  | 无                                                            | object            | 获取媒体信息                                                       |
-| setAudioId                    | id: string                                                   | void              | 设置创建音频对象,设置id                                                |
-| on                            | type: ‘audioInterrupt’, callback: Callback< InterruptEvent > | void              | 监听音频中断事件,使用callback方式返回结果                                    |
-| off                           | type: ‘audioInterrupt’                                       | void              | 取消订阅音频中断事件                                                   |
-
-### 参数说明
-1.	InterruptEvent
-播放中断时,应用接收的中断事件。
-
-| 名称      | 类型               | 必填 | 说明                                 |
-|-----------|--------------------|------|--------------------------------------|
-| forceType | InterruptForceType | 是   | 操作是由系统执行或是由应用程序执行。 |
-| hintType  | InterruptHint      | 是   | 中断提示。                           |
-
-2.	InterruptForceType
-枚举,强制打断类型。
-
-| 名称            | 值 | 说明                                 |
-|-----------------|----|--------------------------------------|
-| INTERRUPT_FORCE | 0  | 由系统进行操作,强制打断音频播放。   |
-| INTERRUPT_SHARE | 1  | 由应用进行操作,可以选择打断或忽略。 |
-
-3.	InterruptHint
-枚举,中断提示。
-
-| 名称                  | 值 | 说明                                         |
-|-----------------------|----|----------------------------------------------|
-| INTERRUPT_HINT_NONE   | 0  | 无提示。                                     |
-| INTERRUPT_HINT_RESUME | 1  | 提示音频恢复。                               |
-| INTERRUPT_HINT_PAUSE  | 2  | 提示音频暂停。                               |
-| INTERRUPT_HINT_STOP   | 3  | 提示音频停止。                               |
-| INTERRUPT_HINT_DUCK   | 4  | 提示音频躲避。(躲避:音量减弱,而不会停止) |
-| INTERRUPT_HINT_UNDUCK | 5  | 提示音量恢复。                               |
-
-## 约束与限制
-
-在下述版本验证通过:
-- DevEco Studio: NEXT Beta1-5.0.3.806, SDK: API12 Release (5.0.0.66)
-- DevEco Studio NEXT 5.0(5.0.3.427)--SDK:API12
-
- 监听音频中断事件需保证设备系统版本在22以上。
- 设置音量需保证SDK版本在12及以上。
+- 首次启动会自动扫描本地 Download 目录下的音频文件。
+- 支持手动导入音频文件、歌词文件(歌词文件需与歌曲同名且同目录)。
+- 支持歌单新建、重命名、删除、批量管理。
+- 支持音乐收藏、最近播放、历史记录。
+- 支持歌词同步显示、音乐封面自定义。
+- 支持多选批量操作(剪切、复制、删除等)。
+- 支持艺术家、专辑、媒体库分组浏览。
+
+## 主要API简要
+播放器核心接口基于 IjkMediaPlayer,支持如下常用方法:
+- `setDataSource(url: string)` 设置音频源
+- `prepareAsync()` 异步准备播放
+- `start()` 开始播放
+- `pause()` 暂停播放
+- `stop()` 停止播放
+- `seekTo(msec: number)` 跳转到指定位置
+- `setSpeed(speed: string)` 设置播放速度
+- `setLoopCount(looping: boolean)` 设置循环播放
+- `setVolume(left: string, right: string)` 设置音量
+- `setOnCompletionListener(listener)` 播放完成回调
+- `setOnErrorListener(listener)` 错误回调
+- 详见 `entry/src/main/ets/view/LocalMusic.ets` 及相关 ViewModel
 
 ## 目录结构
-
-```javascript
-|---- ijkplayer  
-|     |---- entry  # 示例代码文件夹
-|     |---- ijkplayer  # ijkplayer 库文件夹
-|			|---- cpp  # native模块
-|                  |----- ijkplayer # ijkplayer内部业务
-|                  |----- ijksdl    # ijkplayer内部业务
-|                  |----- napi      # 封装NAPI接口
-|                  |----- proxy     # 代理提供给NAPI调用处理ijkplayer内部业务
-|                  |----- third_party #三方库依赖 
-|                  |----- utils     #工具
-|            |---- ets  # ets接口模块
-|                  |----- callback  #视频回调接口
-|                  |----- common    #常量
-|                  |----- utils     #工具  
-|                  |----- IjkMediaPlayer.ets #ijkplayer暴露的napi调用接口
-|     |---- README_zh.MD  # 安装使用方法                   
-```
-
-## 贡献代码
-
-使用过程中发现任何问题都可以提[Issue](https://gitee.com/openharmony-sig/ijkplayer/issues) 给组件,当然,也非常欢迎发[PR](https://gitee.com/openharmony-sig/ijkplayer/pulls)共建。
+```text
+|-- entry
+|   |-- src/main/ets
+|   |   |-- view/           # 主要UI与音乐播放逻辑
+|   |   |-- viewmodel/      # 数据模型与业务逻辑
+|   |   |-- common/         # 常量、工具类
+|   |   |-- controller/     # 控制器
+|   |   |-- resources/      # 资源文件
+|   |-- oh_modules/         # 三方依赖
+|-- ijkplayer/              # 播放器内核及native模块
+|-- lib/                    # 公共库
+|-- doc/                    # 相关文档
+|-- README.md
+|-- README_zh.md
+```
+
+## 贡献方式
+如在使用过程中发现问题,欢迎通过 Issue 反馈,或提交 Pull Request 参与共建。
 
 ## 开源协议
-
-本项目基于 [LGPLv2.1 or later](LICENSE),请自由地享受和参与开源。
+本项目基于 [Apache 2.0 License](LICENSE) 开源,欢迎自由使用和参与贡献。
 
 
 

+ 73 - 0
开发者文档.md

@@ -0,0 +1,73 @@
+# TTMusic 开发者文档
+
+## 1. 项目简介
+TTMusic 是基于 OpenHarmony(鸿蒙)平台开发的本地音乐播放器,支持本地音频文件的管理、播放、歌单、歌词、封面、批量操作等功能。适配多种鸿蒙设备,代码结构清晰,易于二次开发和功能扩展。
+
+## 2. 环境准备
+- 操作系统:Windows、Linux 或 macOS
+- 开发工具:DevEco Studio(建议 4.0 及以上版本)
+- **OpenHarmony SDK:API 12(5.0.0(12))及以上**
+  - 说明:本项目在 `build-profile.json5` 文件的 `compatibleSdkVersion` 字段中声明了所需 API 版本号为 `5.0.0(12)`,即 API 12。
+- 设备:支持鸿蒙系统的真机或模拟器
+- Node.js(部分脚本依赖)
+
+## 3. 主要目录与代码结构说明
+```
+TTMusic/
+├── entry/                  # 主工程目录
+│   ├── src/main/ets/      # 主要业务代码
+│   │   ├── view/          # 主要UI与音乐播放逻辑(如 LocalMusic.ets)
+│   │   ├── viewmodel/     # 数据模型与业务逻辑
+│   │   ├── common/        # 常量、工具类
+│   │   ├── controller/    # 控制器
+│   │   ├── resources/     # 资源文件(图片、音频、布局等)
+│   ├── oh_modules/        # 三方依赖
+├── ijkplayer/             # 播放器内核及native模块
+├── lib/                   # 公共库
+├── doc/                   # 相关文档
+├── README.md              # 简要说明
+├── README_zh.md           # 中文说明
+├── 开发者文档.md          # 开发者文档(本文件)
+```
+
+## 4. 核心模块与功能说明
+- **LocalMusic.ets**:音乐播放器主界面,负责本地音频文件的浏览、播放、歌单管理、批量操作等。
+- **viewmodel/**:如 `VideoItem`、`MainViewModel`,负责数据结构和业务逻辑。
+- **controller/**:如 `AvSessionController`,负责音频会话、播放控制等。
+- **common/**:常量、工具类、通用方法。
+- **ijkplayer/**:播放器内核,基于 FFmpeg,支持多种音频格式。
+- **oh_modules/**:三方依赖库,如歌词、弹窗、广告等。
+
+### 主要功能点
+- 本地音频扫描与导入(支持自动、手动、批量)
+- 歌单管理、收藏、最近播放、历史记录
+- 歌词同步显示、歌词导入
+- 音乐封面自动提取与自定义
+- 艺术家、专辑、媒体库分组浏览
+- 批量操作(剪切、复制、删除、重命名)
+- 支持倍速播放、音频焦点、循环播放
+
+## 5. 如何本地调试与运行
+1. 使用 DevEco Studio 打开项目根目录。
+2. 配置好 OpenHarmony SDK,**API 版本需为 12(5.0.0(12))及以上**。
+3. 连接鸿蒙真机或启动模拟器。
+4. 点击"运行"按钮,选择目标设备,编译并安装应用。
+5. 首次启动会自动扫描 Download 目录下的音频文件。
+6. 可在 UI 上进行导入、播放、歌单管理等操作。
+
+## 6. 常见开发问题与建议
+- **依赖缺失/编译报错**:请确认 SDK、ohpm 依赖已正确安装,必要时重新同步依赖。
+- **真机调试无响应**:请检查设备已解锁、连接正常,且已允许安装调试应用。
+- **音频无法播放**:请确认音频格式受支持,或查看日志排查 IjkMediaPlayer 初始化问题。
+- **歌词/封面不显示**:请确保歌词文件与音频同名同目录,封面图片格式受支持。
+- **批量操作异常**:建议先单独测试单个文件操作,排查路径、权限等问题。
+- **UI适配问题**:本项目已适配多种屏幕,若需自定义可参考 BreakpointSystem 相关代码。
+
+## 7. 参与贡献方式
+- 欢迎通过 Issue 反馈 bug 或建议。
+- 欢迎提交 Pull Request 参与代码共建。
+- 代码风格建议遵循现有结构,注释清晰,命名规范。
+- 重要变更请先与维护者沟通。
+
+---
+如有更多问题,欢迎查阅源码或联系维护者。祝开发愉快!