diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d600b6c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,25 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+
diff --git a/BUILD_TROUBLESHOOTING.md b/BUILD_TROUBLESHOOTING.md
new file mode 100644
index 0000000..6f0009e
--- /dev/null
+++ b/BUILD_TROUBLESHOOTING.md
@@ -0,0 +1,118 @@
+# ZAPlayer 构建故障排除指南
+
+## 常见问题解决
+
+### 1. Terser 依赖错误
+
+**错误信息:**
+```
+error during build: [vite:terser] terser not found. Since Vite v3, terser has become an optional dependency. You need to install it.
+```
+
+**解决方案:**
+
+#### 方案A:使用简化构建(推荐)
+```bash
+# 使用不需要terser的简化配置
+npm run build:simple
+```
+
+#### 方案B:安装terser依赖
+```bash
+# 安装terser依赖
+npm run install:terser
+
+# 然后正常构建
+npm run build:min
+```
+
+#### 方案C:手动安装terser
+```bash
+npm install --save-dev terser
+npm run build:min
+```
+
+### 2. 构建配置选择
+
+我们提供了多个构建配置:
+
+| 配置文件 | 用途 | 特点 |
+|----------|------|------|
+| `vite.lib.simple.config.js` | 简化构建 | 使用Vite内置压缩,无需额外依赖 |
+| `vite.lib.config.js` | 高级构建 | 使用terser,压缩效果更好 |
+
+### 3. 构建输出文件
+
+成功构建后,会在 `dist/` 目录下生成:
+- `za-player.min.js` - UMD格式,浏览器使用
+- `za-player.es.js` - ES模块格式,现代项目使用
+
+### 4. 验证构建结果
+
+构建完成后,可以通过以下方式验证:
+
+#### 检查文件是否存在
+```bash
+ls -la dist/
+# Windows: dir dist\
+```
+
+#### 检查文件大小
+```bash
+# 查看文件大小(应该有一定压缩)
+wc -c dist/za-player.min.js
+wc -c dist/za-player.es.js
+```
+
+#### 测试功能
+打开 `test-build.html` 文件,在浏览器中测试两个构建文件是否正常工作。
+
+### 5. 快速开始(推荐流程)
+
+```bash
+# 1. 安装依赖
+npm install
+
+# 2. 使用简化构建(避免terser问题)
+npm run build:simple
+
+# 3. 验证构建结果
+ls dist/
+# 应该看到 za-player.min.js 和 za-player.es.js
+
+# 4. 测试功能
+# 在浏览器中打开 test-build.html
+```
+
+### 6. 如果仍然有问题
+
+1. **清除node_modules并重新安装:**
+ ```bash
+ rm -rf node_modules package-lock.json
+ npm install
+ ```
+
+2. **检查Node.js版本:**
+ ```bash
+ node --version
+ # 建议使用 Node.js 16+
+ ```
+
+3. **检查Vite版本:**
+ ```bash
+ npm list vite
+ ```
+
+4. **查看详细错误信息:**
+ ```bash
+ npm run build:simple -- --debug
+ ```
+
+### 7. 获取帮助
+
+如果以上方法都不能解决问题,请提供以下信息:
+1. 完整的错误信息
+2. Node.js版本 (`node --version`)
+3. npm版本 (`npm --version`)
+4. 操作系统信息
+5. 使用的构建命令
\ No newline at end of file
diff --git a/README.md b/README.md
index cae1c3a..b04056d 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,176 @@
-# ZAPlayer
+# ZAPlayer 使用说明
-ZAPlayer是一个支持HLS(M3U8)和FLV格式的视频播放器类库。
\ No newline at end of file
+ZAPlayer是一个支持HLS(M3U8)和FLV格式的视频播放器类库。
+
+## 快速开始
+
+### 方法1:直接引用构建好的类库文件
+
+1. 首先构建类库文件:
+```bash
+npm run build:min
+```
+
+2. 构建完成后,会在 `dist/` 目录下生成两个文件:
+ - `za-player.min.js` - 压缩后的UMD格式,适合浏览器直接使用
+ - `za-player.es.js` - ES模块格式,适合现代JavaScript项目
+
+3. 在HTML文件中引用(浏览器使用):
+```html
+
+
+
+ ZAPlayer 示例
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### 方法2:使用ES模块
+
+```html
+
+
+
+ ZAPlayer ES模块示例
+
+
+
+
+
+
+
+```
+
+### 方法3:在Node.js或现代前端项目中使用ES模块
+
+```javascript
+// 使用ES模块导入
+import ZAPlayer from './dist/za-player.es.js';
+
+// 创建播放器
+const player = new ZAPlayer('#container', {
+ type: 'flv',
+ src: 'video.flv'
+});
+
+player.player.play();
+```
+
+### 方法4:动态加载(浏览器版本)
+
+```javascript
+// 动态加载ZAPlayer类库
+function loadZAPlayer(callback) {
+ const script = document.createElement('script');
+ script.src = 'dist/za-player.min.js'; // 使用压缩版本
+ script.onload = callback;
+ document.head.appendChild(script);
+}
+
+// 使用动态加载的类库
+loadZAPlayer(function() {
+ const player = new ZAPlayer('#videoContainer', {
+ type: 'flv',
+ src: 'your-video-url.flv'
+ });
+
+ player.player.play();
+});
+```
+
+## API 说明
+
+### 构造函数
+```javascript
+new ZAPlayer(container, options)
+```
+
+**参数:**
+- `container` (string|Element): 视频容器的选择器字符串或DOM元素
+- `options` (object): 配置选项
+ - `type` (string): 视频类型,'hls' 或 'flv',默认为 'hls'
+ - `src` (string, 可选): 视频地址,可以在创建后通过load方法加载
+
+**返回值:**
+- 返回一个对象,包含player属性,player对象有以下方法:
+ - `play()`: 播放视频
+ - `pause()`: 暂停视频
+ - `stop()`: 停止视频
+ - `load(url)`: 加载新的视频地址
+
+## 示例视频地址
+
+### FLV格式
+```javascript
+// 示例FLV地址
+player.player.load('http://192.168.1.200:10037/live/PUGE0hFBYluVe_01.flv');
+```
+
+### HLS(M3U8)格式
+```javascript
+// 示例HLS地址
+player.player.load('http://192.168.1.201:9080/DS-2CD5026FWD20180811AACH220809006/0000000B/hls.m3u8');
+```
+
+## 浏览器兼容性
+
+- 支持现代浏览器的Media Source Extensions (MSE)
+- 支持WebCodecs API(用于高级解码)
+- 支持Fetch API
+
+## 注意事项
+
+1. 确保视频地址支持跨域访问(CORS)
+2. 对于直播流,确保服务器支持持续的数据传输
+3. 某些浏览器可能需要HTTPS协议才能正常工作
+
+## 构建说明
+
+```bash
+# 安装依赖
+npm install
+
+# 开发模式
+npm run dev
+
+# 构建演示页面
+npm run build
+
+# 构建类库文件(同时生成两个文件)
+npm run build:min
+```
+
+构建完成后,类库文件会在`dist/`目录下生成:
+- `za-player.min.js` - 压缩后的UMD格式类库文件,适合浏览器直接使用
+- `za-player.es.js` - ES模块格式,适合现代JavaScript项目和打包工具
\ No newline at end of file
diff --git a/USAGE.md b/USAGE.md
new file mode 100644
index 0000000..b04056d
--- /dev/null
+++ b/USAGE.md
@@ -0,0 +1,176 @@
+# ZAPlayer 使用说明
+
+ZAPlayer是一个支持HLS(M3U8)和FLV格式的视频播放器类库。
+
+## 快速开始
+
+### 方法1:直接引用构建好的类库文件
+
+1. 首先构建类库文件:
+```bash
+npm run build:min
+```
+
+2. 构建完成后,会在 `dist/` 目录下生成两个文件:
+ - `za-player.min.js` - 压缩后的UMD格式,适合浏览器直接使用
+ - `za-player.es.js` - ES模块格式,适合现代JavaScript项目
+
+3. 在HTML文件中引用(浏览器使用):
+```html
+
+
+
+ ZAPlayer 示例
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### 方法2:使用ES模块
+
+```html
+
+
+
+ ZAPlayer ES模块示例
+
+
+
+
+
+
+
+```
+
+### 方法3:在Node.js或现代前端项目中使用ES模块
+
+```javascript
+// 使用ES模块导入
+import ZAPlayer from './dist/za-player.es.js';
+
+// 创建播放器
+const player = new ZAPlayer('#container', {
+ type: 'flv',
+ src: 'video.flv'
+});
+
+player.player.play();
+```
+
+### 方法4:动态加载(浏览器版本)
+
+```javascript
+// 动态加载ZAPlayer类库
+function loadZAPlayer(callback) {
+ const script = document.createElement('script');
+ script.src = 'dist/za-player.min.js'; // 使用压缩版本
+ script.onload = callback;
+ document.head.appendChild(script);
+}
+
+// 使用动态加载的类库
+loadZAPlayer(function() {
+ const player = new ZAPlayer('#videoContainer', {
+ type: 'flv',
+ src: 'your-video-url.flv'
+ });
+
+ player.player.play();
+});
+```
+
+## API 说明
+
+### 构造函数
+```javascript
+new ZAPlayer(container, options)
+```
+
+**参数:**
+- `container` (string|Element): 视频容器的选择器字符串或DOM元素
+- `options` (object): 配置选项
+ - `type` (string): 视频类型,'hls' 或 'flv',默认为 'hls'
+ - `src` (string, 可选): 视频地址,可以在创建后通过load方法加载
+
+**返回值:**
+- 返回一个对象,包含player属性,player对象有以下方法:
+ - `play()`: 播放视频
+ - `pause()`: 暂停视频
+ - `stop()`: 停止视频
+ - `load(url)`: 加载新的视频地址
+
+## 示例视频地址
+
+### FLV格式
+```javascript
+// 示例FLV地址
+player.player.load('http://192.168.1.200:10037/live/PUGE0hFBYluVe_01.flv');
+```
+
+### HLS(M3U8)格式
+```javascript
+// 示例HLS地址
+player.player.load('http://192.168.1.201:9080/DS-2CD5026FWD20180811AACH220809006/0000000B/hls.m3u8');
+```
+
+## 浏览器兼容性
+
+- 支持现代浏览器的Media Source Extensions (MSE)
+- 支持WebCodecs API(用于高级解码)
+- 支持Fetch API
+
+## 注意事项
+
+1. 确保视频地址支持跨域访问(CORS)
+2. 对于直播流,确保服务器支持持续的数据传输
+3. 某些浏览器可能需要HTTPS协议才能正常工作
+
+## 构建说明
+
+```bash
+# 安装依赖
+npm install
+
+# 开发模式
+npm run dev
+
+# 构建演示页面
+npm run build
+
+# 构建类库文件(同时生成两个文件)
+npm run build:min
+```
+
+构建完成后,类库文件会在`dist/`目录下生成:
+- `za-player.min.js` - 压缩后的UMD格式类库文件,适合浏览器直接使用
+- `za-player.es.js` - ES模块格式,适合现代JavaScript项目和打包工具
\ No newline at end of file
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..50d1660
--- /dev/null
+++ b/index.html
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+ qhlsplayer
+
+
+
+
+
+
ZAPlayer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/install-deps.js b/install-deps.js
new file mode 100644
index 0000000..f6dda24
--- /dev/null
+++ b/install-deps.js
@@ -0,0 +1,26 @@
+// 依赖安装检查脚本
+const { execSync } = require('child_process');
+const fs = require('fs');
+const path = require('path');
+
+console.log('检查并安装必要的依赖...');
+
+try {
+ // 检查package.json是否存在
+ if (!fs.existsSync('package.json')) {
+ console.error('package.json 不存在!');
+ process.exit(1);
+ }
+
+ // 安装terser(如果需要高级压缩功能)
+ console.log('安装 terser...');
+ execSync('npm install --save-dev terser', { stdio: 'inherit' });
+
+ console.log('依赖安装完成!');
+ console.log('可以运行以下命令进行构建:');
+ console.log(' npm run build:min');
+
+} catch (error) {
+ console.error('依赖安装失败:', error.message);
+ process.exit(1);
+}
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..157a784
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,1221 @@
+{
+ "name": "qhlsplayer",
+ "version": "0.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "qhlsplayer",
+ "version": "0.0.0",
+ "dependencies": {
+ "flv.js": "^1.6.2"
+ },
+ "devDependencies": {
+ "terser": "^5.46.0",
+ "vite": "^7.2.4"
+ }
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz",
+ "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.27.2.tgz",
+ "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz",
+ "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.27.2.tgz",
+ "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz",
+ "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz",
+ "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz",
+ "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz",
+ "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz",
+ "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz",
+ "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz",
+ "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz",
+ "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz",
+ "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz",
+ "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz",
+ "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz",
+ "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz",
+ "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz",
+ "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz",
+ "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz",
+ "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz",
+ "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmmirror.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz",
+ "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz",
+ "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz",
+ "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz",
+ "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.27.2",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.13",
+ "resolved": "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/source-map": {
+ "version": "0.3.11",
+ "resolved": "https://registry.npmmirror.com/@jridgewell/source-map/-/source-map-0.3.11.tgz",
+ "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.25"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.31",
+ "resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.55.1",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.1.tgz",
+ "integrity": "sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.55.1",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.1.tgz",
+ "integrity": "sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.55.1",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.1.tgz",
+ "integrity": "sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.55.1",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.1.tgz",
+ "integrity": "sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-arm64": {
+ "version": "4.55.1",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.1.tgz",
+ "integrity": "sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-x64": {
+ "version": "4.55.1",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.1.tgz",
+ "integrity": "sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.55.1",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.1.tgz",
+ "integrity": "sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.55.1",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.1.tgz",
+ "integrity": "sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.55.1",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.1.tgz",
+ "integrity": "sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.55.1",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.1.tgz",
+ "integrity": "sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-gnu": {
+ "version": "4.55.1",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.1.tgz",
+ "integrity": "sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-musl": {
+ "version": "4.55.1",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.1.tgz",
+ "integrity": "sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-gnu": {
+ "version": "4.55.1",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.1.tgz",
+ "integrity": "sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-musl": {
+ "version": "4.55.1",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.1.tgz",
+ "integrity": "sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.55.1",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.1.tgz",
+ "integrity": "sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
+ "version": "4.55.1",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.1.tgz",
+ "integrity": "sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.55.1",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.1.tgz",
+ "integrity": "sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.55.1",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.55.1.tgz",
+ "integrity": "sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.55.1",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.1.tgz",
+ "integrity": "sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-openbsd-x64": {
+ "version": "4.55.1",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.1.tgz",
+ "integrity": "sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-openharmony-arm64": {
+ "version": "4.55.1",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.1.tgz",
+ "integrity": "sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.55.1",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.1.tgz",
+ "integrity": "sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.55.1",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.1.tgz",
+ "integrity": "sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-gnu": {
+ "version": "4.55.1",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.55.1",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.8",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/acorn": {
+ "version": "8.15.0",
+ "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.15.0.tgz",
+ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmmirror.com/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/es6-promise": {
+ "version": "4.2.8",
+ "resolved": "https://registry.npmmirror.com/es6-promise/-/es6-promise-4.2.8.tgz",
+ "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
+ "license": "MIT"
+ },
+ "node_modules/esbuild": {
+ "version": "0.27.2",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.27.2",
+ "@esbuild/android-arm": "0.27.2",
+ "@esbuild/android-arm64": "0.27.2",
+ "@esbuild/android-x64": "0.27.2",
+ "@esbuild/darwin-arm64": "0.27.2",
+ "@esbuild/darwin-x64": "0.27.2",
+ "@esbuild/freebsd-arm64": "0.27.2",
+ "@esbuild/freebsd-x64": "0.27.2",
+ "@esbuild/linux-arm": "0.27.2",
+ "@esbuild/linux-arm64": "0.27.2",
+ "@esbuild/linux-ia32": "0.27.2",
+ "@esbuild/linux-loong64": "0.27.2",
+ "@esbuild/linux-mips64el": "0.27.2",
+ "@esbuild/linux-ppc64": "0.27.2",
+ "@esbuild/linux-riscv64": "0.27.2",
+ "@esbuild/linux-s390x": "0.27.2",
+ "@esbuild/linux-x64": "0.27.2",
+ "@esbuild/netbsd-arm64": "0.27.2",
+ "@esbuild/netbsd-x64": "0.27.2",
+ "@esbuild/openbsd-arm64": "0.27.2",
+ "@esbuild/openbsd-x64": "0.27.2",
+ "@esbuild/openharmony-arm64": "0.27.2",
+ "@esbuild/sunos-x64": "0.27.2",
+ "@esbuild/win32-arm64": "0.27.2",
+ "@esbuild/win32-ia32": "0.27.2",
+ "@esbuild/win32-x64": "0.27.2"
+ }
+ },
+ "node_modules/fdir": {
+ "version": "6.5.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/flv.js": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmmirror.com/flv.js/-/flv.js-1.6.2.tgz",
+ "integrity": "sha512-xre4gUbX1MPtgQRKj2pxJENp/RnaHaxYvy3YToVVCrSmAWUu85b9mug6pTXF6zakUjNP2lFWZ1rkSX7gxhB/2A==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "es6-promise": "^4.2.8",
+ "webworkify-webpack": "^2.1.5"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.11",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/picomatch": {
+ "version": "4.0.3",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.5.6",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.11",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "4.55.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "1.0.8"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.55.1",
+ "@rollup/rollup-android-arm64": "4.55.1",
+ "@rollup/rollup-darwin-arm64": "4.55.1",
+ "@rollup/rollup-darwin-x64": "4.55.1",
+ "@rollup/rollup-freebsd-arm64": "4.55.1",
+ "@rollup/rollup-freebsd-x64": "4.55.1",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.55.1",
+ "@rollup/rollup-linux-arm-musleabihf": "4.55.1",
+ "@rollup/rollup-linux-arm64-gnu": "4.55.1",
+ "@rollup/rollup-linux-arm64-musl": "4.55.1",
+ "@rollup/rollup-linux-loong64-gnu": "4.55.1",
+ "@rollup/rollup-linux-loong64-musl": "4.55.1",
+ "@rollup/rollup-linux-ppc64-gnu": "4.55.1",
+ "@rollup/rollup-linux-ppc64-musl": "4.55.1",
+ "@rollup/rollup-linux-riscv64-gnu": "4.55.1",
+ "@rollup/rollup-linux-riscv64-musl": "4.55.1",
+ "@rollup/rollup-linux-s390x-gnu": "4.55.1",
+ "@rollup/rollup-linux-x64-gnu": "4.55.1",
+ "@rollup/rollup-linux-x64-musl": "4.55.1",
+ "@rollup/rollup-openbsd-x64": "4.55.1",
+ "@rollup/rollup-openharmony-arm64": "4.55.1",
+ "@rollup/rollup-win32-arm64-msvc": "4.55.1",
+ "@rollup/rollup-win32-ia32-msvc": "4.55.1",
+ "@rollup/rollup-win32-x64-gnu": "4.55.1",
+ "@rollup/rollup-win32-x64-msvc": "4.55.1",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-support": {
+ "version": "0.5.21",
+ "resolved": "https://registry.npmmirror.com/source-map-support/-/source-map-support-0.5.21.tgz",
+ "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ }
+ },
+ "node_modules/terser": {
+ "version": "5.46.0",
+ "resolved": "https://registry.npmmirror.com/terser/-/terser-5.46.0.tgz",
+ "integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "peer": true,
+ "dependencies": {
+ "@jridgewell/source-map": "^0.3.3",
+ "acorn": "^8.15.0",
+ "commander": "^2.20.0",
+ "source-map-support": "~0.5.20"
+ },
+ "bin": {
+ "terser": "bin/terser"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/tinyglobby": {
+ "version": "0.2.15",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "node_modules/vite": {
+ "version": "7.3.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.27.0",
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.3",
+ "postcss": "^8.5.6",
+ "rollup": "^4.43.0",
+ "tinyglobby": "^0.2.15"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^20.19.0 || >=22.12.0",
+ "jiti": ">=1.21.0",
+ "less": "^4.0.0",
+ "lightningcss": "^1.21.0",
+ "sass": "^1.70.0",
+ "sass-embedded": "^1.70.0",
+ "stylus": ">=0.54.8",
+ "sugarss": "^5.0.0",
+ "terser": "^5.16.0",
+ "tsx": "^4.8.1",
+ "yaml": "^2.4.2"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "jiti": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ },
+ "tsx": {
+ "optional": true
+ },
+ "yaml": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/webworkify-webpack": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmmirror.com/webworkify-webpack/-/webworkify-webpack-2.1.5.tgz",
+ "integrity": "sha512-2akF8FIyUvbiBBdD+RoHpoTbHMQF2HwjcxfDvgztAX5YwbZNyrtfUMgvfgFVsgDhDPVTlkbb5vyasqDHfIDPQw==",
+ "license": "MIT"
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..09f1eb1
--- /dev/null
+++ b/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "qhlsplayer",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "build:lib": "vite build --config vite.lib.config.js",
+ "build:simple": "vite build --config vite.lib.simple.config.js",
+ "build:min": "npm run build:simple && echo '构建完成!文件输出为:dist/za-player.min.js 和 dist/za-player.es.js'",
+ "install:terser": "npm install --save-dev terser",
+ "preview": "vite preview"
+ },
+ "devDependencies": {
+ "terser": "^5.46.0",
+ "vite": "^7.2.4"
+ },
+ "dependencies": {
+ "flv.js": "^1.6.2"
+ }
+}
diff --git a/public/vite.svg b/public/vite.svg
new file mode 100644
index 0000000..e7b8dfb
--- /dev/null
+++ b/public/vite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/flv-player.js b/src/flv-player.js
new file mode 100644
index 0000000..c6297af
--- /dev/null
+++ b/src/flv-player.js
@@ -0,0 +1,114 @@
+// 导入flv.js库
+import flvjs from 'flv.js';
+
+class FLVPlayer {
+ constructor(videoElement) {
+ this.videoElement = videoElement;
+ this.flvPlayer = null;
+ this.flvUrl = null;
+ this.isLoading = false;
+ this.isPlaying = false;
+ this.setupErrorHandlers();
+ }
+
+ setupErrorHandlers() {
+ // 监听视频元素错误
+ this.videoElement.addEventListener('error', () => {
+ console.error('视频元素错误:', this.videoElement.error);
+ // 不要在错误事件中立即停止,这可能导致无限循环
+ if (this.videoElement.error.code === 4 && this.videoElement.src === '') {
+ // 忽略空src错误,这可能是正常的重置操作
+ return;
+ }
+ this.stop();
+ });
+ }
+
+ async load(url) {
+ try {
+ // 重置播放器状态
+ this.isLoading = true;
+ this.flvUrl = url;
+
+ // 检查浏览器是否支持flv.js
+ if (!flvjs.isSupported()) {
+ throw new Error('浏览器不支持flv.js');
+ }
+
+ // 如果已经有播放器实例,先销毁
+ if (this.flvPlayer) {
+ this.flvPlayer.destroy();
+ }
+
+ // 创建新的flv.js播放器实例
+ this.flvPlayer = flvjs.createPlayer({
+ type: 'flv',
+ url: url
+ });
+
+ // 附加到video元素
+ this.flvPlayer.attachMediaElement(this.videoElement);
+
+ // 监听flv.js错误事件
+ this.flvPlayer.on(flvjs.Events.ERROR, (errorType, errorDetail, errorInfo) => {
+ console.error('flv.js错误:', errorType, errorDetail, errorInfo);
+ this.stop();
+ });
+
+ // 加载视频
+ await this.flvPlayer.load();
+
+ this.isPlaying = true;
+ } catch (error) {
+ console.error('加载FLV失败:', error);
+ this.stop();
+ } finally {
+ this.isLoading = false;
+ }
+ }
+
+ // 添加play方法
+ play() {
+ this.isPlaying = true;
+ if (this.flvPlayer) {
+ this.flvPlayer.play().catch(error => {
+ console.error('播放失败:', error);
+ });
+ }
+ }
+
+ // 添加pause方法
+ pause() {
+ this.isPlaying = false;
+ if (this.flvPlayer) {
+ this.flvPlayer.pause();
+ }
+ }
+
+ stop() {
+ // 停止播放
+ this.isPlaying = false;
+ this.isLoading = false;
+
+ // 暂停视频播放
+ this.pause();
+
+ // 销毁flv.js播放器实例
+ if (this.flvPlayer) {
+ this.flvPlayer.destroy();
+ this.flvPlayer = null;
+ }
+
+ // 清除视频元素的src
+ this.videoElement.src = '';
+ this.videoElement.load();
+ }
+
+ destroy() {
+ // 完全销毁播放器
+ this.stop();
+ this.videoElement = null;
+ }
+}
+
+export default FLVPlayer;
\ No newline at end of file
diff --git a/src/m3u8-player.js b/src/m3u8-player.js
new file mode 100644
index 0000000..08f2921
--- /dev/null
+++ b/src/m3u8-player.js
@@ -0,0 +1,670 @@
+class M3U8Player {
+ constructor(videoElement) {
+ this.videoElement = videoElement;
+ this.mediaSource = null;
+ this.sourceBuffer = null;
+ this.segments = [];
+ this.currentSegmentIndex = 0;
+ this.isLoading = false;
+ this.isLiveStream = false; // 标识是否为直播流
+ this.refreshInterval = null; // 直播刷新定时器
+ this.m3u8Url = null; // 保存M3U8地址
+ this.setupErrorHandlers();
+
+ // WebCodecs相关属性
+ this.useWebCodecs = false;
+ this.videoDecoder = null;
+ // this.audioDecoder = null;
+ this.videoQueue = [];
+ this.audioQueue = [];
+ this.isPlaying = false;
+ this.startTime = 0;
+ this.canvas = null;
+ this.ctx = null;
+ this.audioContext = null;
+ this.audioSource = null;
+ this.audioProcessor = null;
+ this.frameRate = 30;
+ this.lastRenderTime = 0;
+ }
+
+ setupErrorHandlers() {
+ // 监听视频元素错误
+ this.videoElement.addEventListener('error', () => {
+ console.error('视频元素错误:', this.videoElement.error);
+ // 发生错误时跳过当前片段
+ this.currentSegmentIndex++;
+ setTimeout(() => this.loadNextSegment(), 0);
+ });
+ }
+
+ async load(url) {
+ try {
+ // 完全重置播放器状态
+ this.stop();
+
+ // 保存M3U8地址
+ this.m3u8Url = url;
+
+ // 完全清除视频元素的src和缓冲
+ this.videoElement.src = '';
+ this.videoElement.load();
+
+ // 初始化WebCodecs模式的canvas
+ this.initWebCodecsCanvas();
+
+ // 创建新的MediaSource
+ this.mediaSource = new MediaSource();
+ this.videoElement.src = URL.createObjectURL(this.mediaSource);
+
+ await this.waitForMediaSourceOpen();
+ await this.parseM3U8(url);
+ this.startLoading();
+
+ // 如果是直播流,设置定期刷新
+ if (this.isLiveStream) {
+ this.setupLiveRefresh();
+ }
+ } catch (error) {
+ console.error('加载M3U8失败:', error);
+ this.stop();
+ }
+ }
+
+ initWebCodecsCanvas() {
+ // 创建canvas元素用于WebCodecs渲染
+ this.canvas = document.createElement('canvas');
+ this.canvas.style.display = 'none';
+ this.canvas.width = this.videoElement.clientWidth || 640;
+ this.canvas.height = this.videoElement.clientHeight || 360;
+ this.ctx = this.canvas.getContext('2d');
+
+ // 将canvas插入到video元素后面
+ this.videoElement.parentNode.insertBefore(this.canvas, this.videoElement.nextSibling);
+ }
+
+ waitForMediaSourceOpen() {
+ return new Promise((resolve, reject) => {
+ if (this.mediaSource && this.mediaSource.readyState === 'open') {
+ resolve();
+ return;
+ }
+
+ const timeout = setTimeout(() => {
+ reject(new Error('MediaSource打开超时'));
+ }, 5000);
+
+ const onSourceOpen = () => {
+ clearTimeout(timeout);
+ this.mediaSource.removeEventListener('sourceopen', onSourceOpen);
+ this.mediaSource.removeEventListener('sourceerror', onSourceError);
+ resolve();
+ };
+
+ const onSourceError = (e) => {
+ clearTimeout(timeout);
+ this.mediaSource.removeEventListener('sourceopen', onSourceOpen);
+ this.mediaSource.removeEventListener('sourceerror', onSourceError);
+ reject(new Error('MediaSource打开错误'));
+ };
+
+ this.mediaSource.addEventListener('sourceopen', onSourceOpen);
+ this.mediaSource.addEventListener('sourceerror', onSourceError);
+ });
+ }
+
+ async parseM3U8(url) {
+ try {
+ const response = await fetch(url);
+ const text = await response.text();
+ const lines = text.split('\n');
+ let duration = 0;
+ let segmentUrl = '';
+ let newSegments = [];
+ let currentTimestamp = 0;
+
+ // 检查是否为直播流(没有#EXT-X-ENDLIST标签)
+ this.isLiveStream = !text.includes('#EXT-X-ENDLIST');
+
+ // 计算每个片段的时间戳范围
+ for (let i = 0; i < lines.length; i++) {
+ const line = lines[i].trim();
+ if (line.startsWith('#EXTINF:')) {
+ // 获取片段时长
+ duration = parseFloat(line.split(':')[1].split(',')[0]);
+ } else if (!line.startsWith('#') && line) {
+ // 构建完整的片段URL
+ if (line.startsWith('http')) {
+ segmentUrl = line;
+ } else {
+ const baseUrl = url.substring(0, url.lastIndexOf('/') + 1);
+ segmentUrl = baseUrl + line;
+ }
+
+ // 添加时间戳信息
+ newSegments.push({
+ url: segmentUrl,
+ duration,
+ startTime: currentTimestamp,
+ endTime: currentTimestamp + duration
+ });
+
+ currentTimestamp += duration;
+ }
+ }
+
+ //console.log('解析到的片段:', newSegments);
+
+ // 如果是直播流且不是第一次加载,需要特殊处理
+ if (this.isLiveStream && this.segments.length > 0) {
+ // 找出真正的新片段(基于URL比较)
+ const existingUrls = new Set(this.segments.map(s => s.url));
+ const newAddedSegments = newSegments.filter(segment => !existingUrls.has(segment.url));
+
+ // 确保新片段的时间戳是递增的
+ if (newAddedSegments.length > 0) {
+ // 找到最后一个现有片段的结束时间
+ const lastEndTime = this.segments[this.segments.length - 1].endTime;
+
+ // 调整新片段的时间戳
+ let adjustedTimestamp = lastEndTime;
+ newAddedSegments.forEach(segment => {
+ segment.startTime = adjustedTimestamp;
+ segment.endTime = adjustedTimestamp + segment.duration;
+ adjustedTimestamp += segment.duration;
+ });
+
+ // 添加新片段到现有列表
+ this.segments = [...this.segments, ...newAddedSegments];
+
+ //console.log('新增片段:', newAddedSegments);
+ }
+ } else {
+ // 第一次加载或非直播流,直接使用新列表
+ this.segments = newSegments;
+ this.currentSegmentIndex = 0; // 确保从第一个片段开始播放
+ }
+
+ return this.segments;
+ } catch (error) {
+ console.error('解析M3U8失败:', error);
+ throw error;
+ }
+ }
+
+ startLoading() {
+ this.isLoading = true;
+ this.loadNextSegment();
+ }
+
+ async loadNextSegment() {
+ if (!this.isLoading || !this.segments.length) {
+ return;
+ }
+
+ try {
+ // 对于直播流,确保索引不越界
+ if (this.isLiveStream && this.currentSegmentIndex >= this.segments.length) {
+ // 等待新的片段
+ await new Promise(resolve => setTimeout(resolve, 500));
+ this.loadNextSegment();
+ return;
+ }
+
+ // 确保索引在有效范围内
+ if (this.currentSegmentIndex >= this.segments.length) {
+ return;
+ }
+
+ const segment = this.segments[this.currentSegmentIndex];
+ const response = await fetch(segment.url);
+ const data = await response.arrayBuffer();
+
+ if (!this.sourceBuffer && !this.useWebCodecs) {
+ // 提供更全面的MIME类型和编解码器组合的后备方案
+ const mimeTypes = [
+ // 首选:具体的编解码器组合
+ 'video/mp2t; codecs="avc1.42E01E, mp4a.40.2"', // 完整编解码器(原方案)
+ 'video/mp2t; codecs="avc1.42001E, mp4a.40.2"', // 另一种常见的编解码器组合
+ 'video/mp2t; codecs="avc1.64001F, mp4a.40.2"', // 更高质量的视频编解码器
+ 'video/mp2t; codecs="avc1.4D401E, mp4a.40.2"', // 另一种常见的H.264编解码器
+
+ // 备选:只指定视频编解码器
+ 'video/mp2t; codecs="avc1.42E01E"',
+ 'video/mp2t; codecs="avc1.42001E"',
+ 'video/mp2t; codecs="h264"',
+
+ // 备选:只指定音频编解码器
+ 'video/mp2t; codecs="mp4a.40.2"',
+ 'video/mp2t; codecs="aac"',
+
+ // 最后选择:不指定编解码器或使用其他容器格式
+ 'video/mp2t',
+ 'video/x-mpeg2-transport-stream',
+
+ 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"'
+ ];
+
+ // 尝试找到浏览器支持的MIME类型
+ let supportedMimeType = null;
+ for (const mimeType of mimeTypes) {
+ if (MediaSource.isTypeSupported(mimeType)) {
+ supportedMimeType = mimeType;
+ console.log('使用支持的MIME类型:', mimeType);
+ break;
+ }
+ }
+
+ if (!supportedMimeType) {
+ // 尝试使用最基础的类型,如果失败则会在下面的try-catch中处理
+ supportedMimeType = 'video/mp2t';
+ }
+
+ // 在调用addSourceBuffer前再次检查
+ if (MediaSource.isTypeSupported(supportedMimeType)) {
+ try {
+ // 使用sequence模式更适合直接播放
+ this.sourceBuffer = this.mediaSource.addSourceBuffer(supportedMimeType);
+ this.sourceBuffer.mode = 'sequence';
+ this.setupSourceBuffer();
+ } catch (error) {
+ console.error('创建SourceBuffer失败:', error);
+ // 尝试其他方法,比如使用更简单的格式
+ try {
+ this.sourceBuffer = this.mediaSource.addSourceBuffer('video/mp2t; codecs="h264,aac"');
+ this.sourceBuffer.mode = 'sequence';
+ this.setupSourceBuffer();
+ } catch (e) {
+ console.error('再次创建SourceBuffer失败:', e);
+ // 如果都失败,尝试使用WebCodecs
+ console.log('尝试使用WebCodecs解码视频');
+ this.useWebCodecs = true;
+ await this.initWebCodecs();
+ }
+ }
+ } else {
+ // 使用WebCodecs解码视频
+ console.log('MIME类型不受支持,尝试使用WebCodecs解码视频');
+ this.useWebCodecs = true;
+ await this.initWebCodecs();
+ }
+ }
+
+ if (this.useWebCodecs) {
+ // 使用WebCodecs解码
+ await this.decodeWithWebCodecs(data, segment);
+ } else {
+ // 使用MediaSource解码
+ await this.appendBuffer(data, segment);
+ }
+
+ this.currentSegmentIndex++;
+ this.loadNextSegment();
+ } catch (error) {
+ console.error('加载片段失败:', error);
+ // 跳过当前片段,继续加载下一个
+ this.currentSegmentIndex++;
+ setTimeout(() => this.loadNextSegment(), 0);
+ }
+ }
+
+ async initWebCodecs() {
+ // 检查浏览器是否支持WebCodecs
+ if (!('VideoDecoder' in window) || !('AudioDecoder' in window)) {
+ throw new Error('浏览器不支持WebCodecs API');
+ }
+
+ // 初始化视频解码器
+ this.videoDecoder = new VideoDecoder({
+ output: this.decodeVideoChunk.bind(this),
+ error: (e) => {
+ console.error('视频解码错误:', e);
+ }
+ });
+
+ // 初始化音频解码器
+ // this.audioDecoder = new AudioDecoder({
+ // output: this.decodeAudioChunk.bind(this),
+ // error: (e) => {
+ // console.error('音频解码错误:', e);
+ // }
+ // });
+
+ // 配置解码器(取消注释并确保配置完成)
+ try {
+ await this.videoDecoder.configure({
+ codec: 'avc1.42E01E',
+ hardwareAcceleration: 'prefer-hardware'
+ });
+ } catch (e) {
+ console.error('视频解码器配置失败:', e);
+ // 尝试使用其他编解码器
+ await this.videoDecoder.configure({
+ codec: 'h264',
+ hardwareAcceleration: 'prefer-hardware'
+ });
+ }
+
+ // try {
+ // await this.audioDecoder.configure({
+ // codec: 'mp4a.40.2'
+ // });
+ // } catch (e) {
+ // console.error('音频解码器配置失败:', e);
+ // // 尝试使用其他编解码器
+ // try {
+ // await this.audioDecoder.configure({
+ // codec: 'aac'
+ // });
+ // } catch (e2) {
+ // console.error('音频解码器再次配置失败:', e2);
+ // // 如果音频配置失败,我们仍然可以继续,只播放视频
+ // }
+ // }
+
+ // 显示canvas,隐藏video元素
+ this.canvas.style.display = 'block';
+ this.videoElement.style.display = 'none';
+
+ // 开始渲染循环
+ this.isPlaying = true;
+ this.startTime = performance.now();
+ this.renderLoop();
+ }
+
+ decodeVideoChunk(frame) {
+ this.videoQueue.push({
+ frame,
+ timestamp: frame.timestamp / 1000000 // 转换为毫秒
+ });
+ }
+
+ decodeAudioChunk(frame) {
+ this.audioQueue.push({
+ frame,
+ timestamp: frame.timestamp / 1000000 // 转换为毫秒
+ });
+ }
+
+ async decodeWithWebCodecs(data, segment) {
+ // 检查解码器是否已配置
+ if (!this.videoDecoder || this.videoDecoder.state !== 'configured') {
+ console.error('视频解码器未配置');
+ return;
+ }
+
+ }
+
+ renderLoop() {
+ if (!this.isPlaying) {
+ return;
+ }
+
+ const currentTime = performance.now() - this.startTime;
+
+ // 渲染视频帧
+ while (this.videoQueue.length > 0 && this.videoQueue[0].timestamp <= currentTime) {
+ const { frame } = this.videoQueue.shift();
+ this.renderFrame(frame);
+ frame.close();
+ }
+
+ // 播放音频帧
+ while (this.audioQueue.length > 0 && this.audioQueue[0].timestamp <= currentTime) {
+ const { frame } = this.audioQueue.shift();
+ this.playAudioFrame(frame);
+ frame.close();
+ }
+
+ // 继续渲染循环
+ requestAnimationFrame(() => this.renderLoop());
+ }
+
+ renderFrame(frame) {
+ if (!this.ctx) {
+ return;
+ }
+
+ // 调整canvas大小
+ if (this.canvas.width !== frame.displayWidth || this.canvas.height !== frame.displayHeight) {
+ this.canvas.width = frame.displayWidth;
+ this.canvas.height = frame.displayHeight;
+ }
+
+ // 渲染帧
+ this.ctx.drawImage(frame, 0, 0);
+ }
+
+ playAudioFrame(frame) {
+ // 初始化音频上下文
+ if (!this.audioContext) {
+ this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
+ }
+
+ // 创建音频缓冲区
+ const buffer = this.audioContext.createBuffer(
+ frame.numberOfChannels,
+ frame.length,
+ frame.sampleRate
+ );
+
+ // 填充音频数据
+ for (let channel = 0; channel < frame.numberOfChannels; channel++) {
+ const data = buffer.getChannelData(channel);
+ frame.copyTo(data, { planeIndex: channel });
+ }
+
+ // 播放音频
+ const source = this.audioContext.createBufferSource();
+ source.buffer = buffer;
+ source.connect(this.audioContext.destination);
+ source.start();
+ }
+
+ setupSourceBuffer() {
+ this.sourceBuffer.addEventListener('updateend', () => {
+ // 检查视频元素和MediaSource的状态
+ if (this.videoElement.error) {
+ console.error('视频元素出错,停止更新:', this.videoElement.error);
+ this.currentSegmentIndex++;
+ setTimeout(() => this.loadNextSegment(), 0);
+ return;
+ }
+
+ // 检查MediaSource状态
+ if (!this.mediaSource || this.mediaSource.readyState !== 'open') {
+ console.error('MediaSource未打开,停止SourceBuffer更新');
+ return;
+ }
+
+ // 立即播放,不等待缓冲
+ if (!this.videoElement.paused && this.videoElement.readyState > 2) {
+ this.videoElement.play().catch(error => {
+ console.error('自动播放失败:', error);
+ });
+ }
+ });
+ }
+
+ // 简化的appendBuffer方法,不做缓冲处理
+ appendBuffer(data, segment) {
+ return new Promise((resolve) => {
+ // 检查数据是否为空
+ if (!data || data.byteLength === 0) {
+ console.error('数据为空,无法追加缓冲区');
+ // 数据为空,跳过当前片段
+ this.currentSegmentIndex++;
+ setTimeout(() => this.loadNextSegment(), 0);
+ resolve();
+ return;
+ }
+
+ // 检查视频元素是否已卸载
+ if (!this.videoElement || this.videoElement.disconnected) {
+ console.error('视频元素已卸载,无法追加缓冲区');
+ resolve();
+ return;
+ }
+
+ // 检查当前片段是否有效
+ if (!segment || !segment.url) {
+ console.error('无效的片段信息');
+ // 无效片段,跳过当前片段
+ this.currentSegmentIndex++;
+ setTimeout(() => this.loadNextSegment(), 0);
+ resolve();
+ return;
+ }
+
+ const append = () => {
+ // 检查视频元素错误
+ if (this.videoElement.error) {
+ console.error('视频元素错误,无法追加缓冲区:', this.videoElement.error);
+ this.currentSegmentIndex++;
+ setTimeout(() => this.loadNextSegment(), 0);
+ resolve();
+ return;
+ }
+
+ if (!this.mediaSource) {
+ console.error('MediaSource未初始化,无法追加缓冲区');
+ resolve();
+ return;
+ }
+
+ if (this.mediaSource.readyState !== 'open') {
+ console.warn('MediaSource未打开,无法追加缓冲区');
+ resolve();
+ return;
+ }
+
+ if (!this.sourceBuffer || this.sourceBuffer.updating) {
+ setTimeout(append, 10);
+ return;
+ }
+
+ try {
+ this.sourceBuffer.appendBuffer(data);
+ //console.log('追加片段:', segment.url);
+ resolve();
+ } catch (error) {
+ console.error('追加Buffer失败:', error);
+ // 任何错误都跳过当前片段
+ this.currentSegmentIndex++;
+ setTimeout(() => this.loadNextSegment(), 0);
+ resolve();
+ }
+ };
+
+ append();
+ });
+ }
+
+ setupLiveRefresh() {
+ // 每隔几秒重新请求M3U8文件
+ this.refreshInterval = setInterval(async () => {
+ if (!this.isLiveStream || !this.isLoading) return;
+
+ try {
+ await this.parseM3U8(this.m3u8Url);
+ } catch (error) {
+ console.error('刷新M3U8失败:', error);
+ }
+ }, 3000); // 每3秒刷新一次
+ }
+
+ play() {
+ if (this.useWebCodecs) {
+ // WebCodecs模式
+ this.isPlaying = true;
+ this.startTime = performance.now() - (this.lastRenderTime || 0);
+ this.renderLoop();
+ } else {
+ // MediaSource模式
+ // 检查src是否为空
+ if (!this.videoElement.src) {
+ console.error('视频源地址为空,请先加载M3U8文件');
+ return;
+ }
+
+ if (this.videoElement.error) {
+ console.error('视频元素出错,无法播放:', this.videoElement.error);
+ return;
+ }
+
+ this.videoElement.play().catch(error => {
+ console.error('播放失败:', error);
+ });
+ }
+ }
+
+ pause() {
+ if (this.useWebCodecs) {
+ // WebCodecs模式
+ this.isPlaying = false;
+ } else {
+ // MediaSource模式
+ this.videoElement.pause();
+ }
+ }
+
+ stop() {
+ this.isLoading = false;
+ this.isPlaying = false;
+ this.currentSegmentIndex = 0;
+ this.lastRenderTime = 0;
+
+ // 清除直播刷新定时器
+ if (this.refreshInterval) {
+ clearInterval(this.refreshInterval);
+ this.refreshInterval = null;
+ }
+
+ if (this.mediaSource) {
+ try {
+ URL.revokeObjectURL(this.videoElement.src);
+ } catch (e) {
+ console.error('撤销ObjectURL失败:', e);
+ }
+ this.mediaSource = null;
+ this.sourceBuffer = null;
+ }
+
+ // 释放WebCodecs资源
+ if (this.videoDecoder) {
+ this.videoDecoder.close();
+ this.videoDecoder = null;
+ }
+
+ // 注意:当前版本未使用音频解码器
+ // if (this.audioDecoder) {
+ // this.audioDecoder.close();
+ // this.audioDecoder = null;
+ // }
+
+ if (this.audioContext) {
+ this.audioContext.close();
+ this.audioContext = null;
+ }
+
+ // 清空队列
+ this.videoQueue = [];
+ this.audioQueue = [];
+
+ try {
+ this.videoElement.pause();
+ this.videoElement.src = '';
+ this.videoElement.load();
+
+ // 恢复显示video元素,隐藏canvas
+ this.videoElement.style.display = 'block';
+ if (this.canvas) {
+ this.canvas.style.display = 'none';
+ }
+ } catch (e) {
+ console.error('重置视频元素失败:', e);
+ }
+ }
+}
+
+export default M3U8Player;
\ No newline at end of file
diff --git a/src/main.js b/src/main.js
new file mode 100644
index 0000000..3494df0
--- /dev/null
+++ b/src/main.js
@@ -0,0 +1,29 @@
+import M3U8Player from './m3u8-player.js'
+import FLVPlayer from './flv-player.js'
+
+class ZAPlayer {
+ constructor(videoWrapper,params={type:'hls'}){
+ videoWrapper = (typeof videoWrapper === 'string') ? document.querySelector(videoWrapper)||document.getElementById(videoWrapper) : videoWrapper;
+ videoWrapper.innerHTML = '';
+ const videoElement = document.getElementById('videoPlayer');
+
+ if(params.type==='hls'){
+ // 初始化hls播放器
+ this.player = new M3U8Player(videoElement);
+ if(params.src){
+ this.player.load(params.src);
+ }
+ }else{
+ //flv视频播放支持
+ this.player = new FLVPlayer(videoElement);
+ if(params.src){
+ this.player.load(params.src);
+ }
+ }
+ }
+}
+
+// 将ZAPlayer挂载到window对象,使其成为全局可用的类库
+window.ZAPlayer = ZAPlayer;
+
+export default ZAPlayer;
\ No newline at end of file
diff --git a/src/style.css b/src/style.css
new file mode 100644
index 0000000..70c18fe
--- /dev/null
+++ b/src/style.css
@@ -0,0 +1,107 @@
+:root {
+ font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
+ line-height: 1.5;
+ font-weight: 400;
+
+ color-scheme: light dark;
+ color: rgba(255, 255, 255, 0.87);
+ background-color: #242424;
+
+ font-synthesis: none;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+body {
+ margin: 0;
+ display: flex;
+ place-items: center;
+ min-width: 320px;
+ min-height: 100vh;
+}
+
+#app {
+ margin: 0 auto;
+ padding: 2rem;
+ text-align: center;
+}
+
+.player-container {
+ width: 100%;
+ margin: 0 auto;
+}
+
+.video-wrapper {
+ margin: 20px 0;
+ border-radius: 8px;
+ overflow: hidden;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
+ background: #000;
+ position: relative;
+}
+
+video {
+ width: 100%;
+ height: auto;
+ display: block;
+}
+
+.controls {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 10px;
+ justify-content: center;
+ margin-top: 20px;
+}
+
+input[type="text"] {
+ flex: 1;
+ min-width: 200px;
+ padding: 0.6em 1.2em;
+ border-radius: 8px;
+ border: 1px solid #ccc;
+ font-size: 1em;
+ font-family: inherit;
+ background-color: #1a1a1a;
+ color: white;
+}
+
+button {
+ border-radius: 8px;
+ border: 1px solid transparent;
+ padding: 0.6em 1.2em;
+ font-size: 1em;
+ font-weight: 500;
+ font-family: inherit;
+ background-color: #1a1a1a;
+ cursor: pointer;
+ transition: border-color 0.25s;
+}
+
+button:hover {
+ border-color: #646cff;
+}
+
+button:focus,
+button:focus-visible {
+ outline: 4px auto -webkit-focus-ring-color;
+}
+
+@media (prefers-color-scheme: light) {
+ :root {
+ color: #213547;
+ background-color: #ffffff;
+ }
+ a:hover {
+ color: #747bff;
+ }
+ button {
+ background-color: #f9f9f9;
+ }
+ input[type="text"] {
+ background-color: #ffffff;
+ color: #213547;
+ border-color: #ccc;
+ }
+}
diff --git a/test-build.html b/test-build.html
new file mode 100644
index 0000000..f43a529
--- /dev/null
+++ b/test-build.html
@@ -0,0 +1,92 @@
+
+
+
+
+
+ ZAPlayer 构建测试
+
+
+
+ ZAPlayer 构建文件测试
+
+
+
测试1:UMD格式 (za-player.min.js)
+
+
+
+
+
+
测试2:ES模块格式 (za-player.es.js)
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/vite.config.js b/vite.config.js
new file mode 100644
index 0000000..e3c57a1
--- /dev/null
+++ b/vite.config.js
@@ -0,0 +1,15 @@
+import { defineConfig } from 'vite'
+
+export default defineConfig({
+ build: {
+ rollupOptions: {
+ input: {
+ main: 'index.html'
+ }
+ }
+ },
+ server: {
+ port: 3000,
+ open: true
+ }
+})
\ No newline at end of file
diff --git a/vite.lib.config.js b/vite.lib.config.js
new file mode 100644
index 0000000..d3d7af5
--- /dev/null
+++ b/vite.lib.config.js
@@ -0,0 +1,31 @@
+import { defineConfig } from 'vite'
+import { resolve } from 'path'
+
+export default defineConfig({
+ build: {
+ lib: {
+ entry: resolve(__dirname, 'src/main.js'),
+ name: 'ZAPlayer',
+ fileName: (format) => {
+ // 根据格式生成不同的文件名
+ if (format === 'es') {
+ return 'za-player.es.js' // ES模块格式
+ } else if (format === 'umd') {
+ return 'za-player.min.js' // UMD压缩格式
+ }
+ return `za-player.${format}.js`
+ },
+ formats: ['es', 'umd'] // 同时生成ES和UMD格式
+ },
+ rollupOptions: {
+ external: [],
+ output: {
+ globals: {}
+ }
+ },
+ // 使用Vite内置的压缩(esbuild),不需要额外依赖
+ minify: 'esbuild', // 或者使用 true(Vite默认压缩)
+ // 不生成source map
+ sourcemap: false
+ }
+})
\ No newline at end of file
diff --git a/vite.lib.simple.config.js b/vite.lib.simple.config.js
new file mode 100644
index 0000000..692e345
--- /dev/null
+++ b/vite.lib.simple.config.js
@@ -0,0 +1,29 @@
+import { defineConfig } from 'vite'
+import { resolve } from 'path'
+
+export default defineConfig({
+ build: {
+ lib: {
+ entry: resolve(__dirname, 'src/main.js'),
+ name: 'ZAPlayer',
+ fileName: (format) => {
+ if (format === 'es') {
+ return 'za-player.es.js'
+ } else if (format === 'umd') {
+ return 'za-player.min.js'
+ }
+ return `za-player.${format}.js`
+ },
+ formats: ['es', 'umd']
+ },
+ rollupOptions: {
+ external: [],
+ output: {
+ globals: {}
+ }
+ },
+ // 使用esbuild压缩(Vite内置,无需额外依赖)
+ minify: true,
+ sourcemap: false
+ }
+})
\ No newline at end of file