mb-rrvideo-server 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/DOCKER.md CHANGED
@@ -28,6 +28,9 @@ docker images mb-rrvideo-converter
28
28
  # 运行容器
29
29
  docker-compose up -d
30
30
 
31
+ #第一次安装
32
+ sudo docker compose up -d --build --progress=plain
33
+
31
34
  # 容器名称
32
35
  docker ps | grep rrvideo-server
33
36
  ```
@@ -98,7 +101,7 @@ docker --version
98
101
 
99
102
  ```bash
100
103
  # 下载 Docker Compose
101
- sudo curl -L "https://github.com/docker/compose/releases/download/v2.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
104
+ sudo curl -L "https://gh-proxy.org/https://github.com/docker/compose/releases/download/v2.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
102
105
 
103
106
  # 添加执行权限
104
107
  sudo chmod +x /usr/local/bin/docker-compose
@@ -117,9 +120,10 @@ sudo mkdir -p /etc/docker
117
120
  sudo tee /etc/docker/daemon.json <<-'EOF'
118
121
  {
119
122
  "registry-mirrors": [
120
- "https://docker.mirrors.ustc.edu.cn",
121
- "https://hub-mirror.c.163.com",
122
- "https://mirror.ccs.tencentyun.com"
123
+ "https://docker.m.daocloud.io",
124
+ "https://dockerproxy.com",
125
+ "https://mirror.baidubce.com",
126
+ "https://docker.nju.edu.cn"
123
127
  ]
124
128
  }
125
129
  EOF
@@ -262,6 +266,13 @@ docker-compose up -d
262
266
  docker-compose ps
263
267
  ```
264
268
 
269
+ 更新后重装:
270
+ # 强制不使用缓存构建,确保拉到最新的 npm 包
271
+ sudo docker compose build --no-cache
272
+
273
+ # 重启服务
274
+ sudo docker compose up -d
275
+
265
276
  **输出示例:**
266
277
  ```
267
278
  NAME IMAGE STATUS PORTS
package/Dockerfile CHANGED
@@ -6,11 +6,18 @@
6
6
 
7
7
  FROM node:22-slim
8
8
 
9
+ # 设置代理参数(可从构建参数传入,也可在此处直接定义默认值)
10
+ # 如果不想每次构建都传参,可以在这里写死默认值
11
+ ARG HTTP_PROXY="http://172.168.1.117:10809"
12
+ ARG HTTPS_PROXY="http://172.168.1.117:10809"
13
+
9
14
  # 设置环境变量
10
15
  ENV TZ=Asia/Shanghai \
11
16
  NODE_ENV=production \
12
- PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=0 \
13
- PLAYWRIGHT_BROWSERS_PATH=/root/.cache/ms-playwright
17
+ PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 \
18
+ PLAYWRIGHT_BROWSERS_PATH=/root/.cache/ms-playwright
19
+
20
+ # PLAYWRIGHT_DOWNLOAD_HOST=https://npmmirror.com/mirrors/playwright
14
21
 
15
22
  # ============================================
16
23
  # 第一步:配置国内镜像源(加速构建)
@@ -56,42 +63,26 @@ RUN apt-get update && apt-get install -y \
56
63
  RUN npm config set registry https://registry.npmmirror.com
57
64
 
58
65
  # ============================================
59
- # 第四步:全局安装 PM2
60
- # ============================================
61
- RUN npm install -g pm2 && npm cache clean --force
62
-
66
+ # 第五步:全局安装 Node.js 包
67
+ # 使用 --verbose 查看详细日志
68
+ # 并显式添加 --ignore-scripts 参数以跳过所有 postinstall 脚本
63
69
  # ============================================
64
- # 第五步:安装本地依赖包 (mb-rrvideo)
65
- # 方案:直接使用源码在容器内编译安装
66
- # 前置条件:构建前由 server-run.sh 脚本将 ../mb-rrvideo 复制到 ./_deps/mb-rrvideo
67
- # ============================================
68
- COPY _deps/mb-rrvideo /tmp/mb-rrvideo
69
- RUN cd /tmp/mb-rrvideo && \
70
- # 安装依赖(包含 devDependencies 以便执行 build)
71
- npm install && \
72
- # 编译 TypeScript
73
- npm run build && \
74
- # 全局安装
75
- npm install -g . && \
76
- # 清理源码和缓存
77
- cd / && rm -rf /tmp/mb-rrvideo && npm cache clean --force
70
+ RUN npm install -g --verbose --ignore-scripts \
71
+ pm2 \
72
+ mb-rrvideo \
73
+ mb-rrvideo-server \
74
+ && npm cache clean --force
78
75
 
79
76
  # ============================================
80
- # 第六步:复制项目源码并安装
77
+ # 第六步:安装 Playwright 浏览器(Chromium)
78
+ # 使用构建参数中的代理(只在此步骤生效)
81
79
  # ============================================
82
- WORKDIR /app
83
- COPY . /app
84
-
85
- # 安装当前项目依赖并链接命令
86
- RUN npm install -g . && npm cache clean --force
80
+ RUN export HTTP_PROXY=$HTTP_PROXY && \
81
+ export HTTPS_PROXY=$HTTPS_PROXY && \
82
+ npx playwright install chromium
87
83
 
88
84
  # ============================================
89
- # 第七步:安装 Playwright 浏览器(Chromium)
90
- # ============================================
91
- RUN npx playwright install chromium
92
-
93
- # ============================================
94
- # 第八步:创建应用目录
85
+ # 第七步:创建应用目录
95
86
  # ============================================
96
87
  RUN mkdir -p /app/config \
97
88
  && mkdir -p /app/logs \
@@ -99,23 +90,25 @@ RUN mkdir -p /app/config \
99
90
  && mkdir -p /app/Video \
100
91
  && mkdir -p /app/tasks
101
92
 
93
+ WORKDIR /app
94
+
102
95
  # ============================================
103
- # 第九步:复制 PM2 配置文件
96
+ # 第八步:复制 PM2 配置文件
104
97
  # ============================================
105
98
  COPY ecosystem.docker.config.js /app/ecosystem.config.js
106
99
 
107
100
  # ============================================
108
- # 第十步:暴露端口
101
+ # 第九步:暴露端口
109
102
  # ============================================
110
103
  EXPOSE 24203
111
104
 
112
105
  # ============================================
113
- # 第十一步:健康检查
106
+ # 第十步:健康检查
114
107
  # ============================================
115
108
  HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
116
109
  CMD curl -f http://localhost:24203/health || exit 1
117
110
 
118
111
  # ============================================
119
- # 第十二步:启动服务
112
+ # 第十一步:启动服务
120
113
  # ============================================
121
114
  CMD ["pm2-runtime", "start", "ecosystem.config.js"]
@@ -7,23 +7,29 @@
7
7
 
8
8
  // 存储配置
9
9
  "storage": {
10
- "type": "local", // 存储类型: "local" 或 "minio"
10
+ "type": "aliyun", // 存储类型: "local" 或 "minio"
11
11
 
12
12
  // 本地存储配置
13
13
  "local": {
14
14
  "video_dir": "./Video", // 视频存储目录
15
15
  "temp_dir": "./temp" // 临时文件目录
16
16
  },
17
+ "aliyun":{
18
+ "accessKeyId": "",
19
+ "accessKeySecret": "",
20
+ "endpoint": "",
21
+ "bucket": ""
22
+ },
17
23
 
18
24
  // MinIO 对象存储配置
19
25
  "minio": {
20
- "endpoint": "172.168.1.2",
26
+ "endpoint": "",
21
27
  "port": 9000,
22
28
  "useSSL": false,
23
29
  "accessKey": "your-access-key",
24
30
  "secretKey": "your-secret-key",
25
- "bucket": "record-prod",
26
- "public_host": "https://oss-bbx.17maibaoxian.com:10008"
31
+ "bucket": "",
32
+ "publicHost": ""
27
33
  }
28
34
  },
29
35
 
@@ -10,7 +10,8 @@ module.exports = {
10
10
  watch: false,
11
11
  max_memory_restart: '2G',
12
12
  env: {
13
- NODE_ENV: 'production'
13
+ NODE_ENV: 'production',
14
+ CONFIG_PATH: '/app/config/config.json'
14
15
  },
15
16
  error_file: '/app/logs/pm2-error.log',
16
17
  out_file: '/app/logs/pm2-out.log',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mb-rrvideo-server",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "视频转码服务 - 接收可回溯机请求,执行转码/合并,上传MinIO/本地存储",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -35,6 +35,7 @@
35
35
  "author": "",
36
36
  "license": "MIT",
37
37
  "dependencies": {
38
+ "ali-oss": "^6.23.0",
38
39
  "minio": "^7.1.3"
39
40
  },
40
41
  "devDependencies": {
package/src/config.js CHANGED
@@ -4,7 +4,22 @@ const path = require('path');
4
4
  class ConfigManager {
5
5
  constructor() {
6
6
  this.config = null;
7
- this.configPath = path.join(__dirname, '../config.json');
7
+ // 优先使用环境变量 CONFIG_PATH,如果没设置,再按顺序查找
8
+ // 1. 当前工作目录下的 config.json (本地开发路径)
9
+ // 2. 源码所在目录的上级目录 (兜底)
10
+
11
+ if (process.env.CONFIG_PATH) {
12
+ this.configPath = process.env.CONFIG_PATH;
13
+ } else {
14
+ const fs = require('fs');
15
+ const candidates = [
16
+ path.join(process.cwd(), 'config.json'),
17
+ path.join(__dirname, '../config.json')
18
+ ];
19
+
20
+ this.configPath = candidates.find(p => fs.existsSync(p)) || candidates[1];
21
+ }
22
+
8
23
  this.examplePath = path.join(__dirname, '../config.example.json');
9
24
  }
10
25
 
@@ -123,8 +138,8 @@ class ConfigManager {
123
138
  }
124
139
 
125
140
  const storageType = this.config.storage.type;
126
- if (storageType !== 'local' && storageType !== 'minio') {
127
- throw new Error('storage.type 必须是 local 或 minio');
141
+ if (storageType !== 'local' && storageType !== 'minio' && storageType !== 'aliyun') {
142
+ throw new Error('storage.type 必须是 local, minio aliyun');
128
143
  }
129
144
 
130
145
  // 如果使用 MinIO,验证 MinIO 配置
@@ -135,6 +150,14 @@ class ConfigManager {
135
150
  }
136
151
  }
137
152
 
153
+ // 如果使用 Aliyun OSS,验证 Aliyun OSS 配置
154
+ if (storageType === 'aliyun') {
155
+ const aliyun = this.config.storage.aliyun;
156
+ if (!aliyun || !aliyun.accessKeyId || !aliyun.accessKeySecret || !aliyun.endpoint || !aliyun.bucket) {
157
+ throw new Error('阿里云 OSS 配置不完整');
158
+ }
159
+ }
160
+
138
161
  console.log('[Config] 配置验证通过');
139
162
  console.log('[Config] 存储类型:', storageType);
140
163
  }
package/src/storage.js CHANGED
@@ -1,12 +1,14 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
  const Minio = require('minio');
4
+ const OSS = require('ali-oss');
4
5
  const config = require('./config');
5
6
 
6
7
  class StorageManager {
7
8
  constructor() {
8
9
  this.storageType = null;
9
10
  this.minioClient = null;
11
+ this.ossClient = null;
10
12
  this.init();
11
13
  }
12
14
 
@@ -24,6 +26,17 @@ class StorageManager {
24
26
  secretKey: minioConfig.secretKey
25
27
  });
26
28
  console.log('[Storage] MinIO 客户端已初始化');
29
+ } else if (this.storageType === 'aliyun') {
30
+ const aliyunConfig = storageConfig.aliyun;
31
+ this.ossClient = new OSS({
32
+ // region: aliyunConfig.region || 'oss-cn-hangzhou', // 默认为杭州,或者从endpoint解析
33
+ accessKeyId: aliyunConfig.accessKeyId,
34
+ accessKeySecret: aliyunConfig.accessKeySecret,
35
+ bucket: aliyunConfig.bucket,
36
+ endpoint: aliyunConfig.endpoint,
37
+ secure: true // 默认使用 HTTPS
38
+ });
39
+ console.log('[Storage] 阿里云 OSS 客户端已初始化');
27
40
  } else {
28
41
  console.log('[Storage] 使用本地存储');
29
42
  }
@@ -64,6 +77,8 @@ class StorageManager {
64
77
 
65
78
  if (this.storageType === 'minio') {
66
79
  return await this.uploadToMinio(localPath, remotePath);
80
+ } else if (this.storageType === 'aliyun') {
81
+ return await this.uploadToOss(localPath, remotePath);
67
82
  } else {
68
83
  return await this.saveToLocal(localPath, remotePath);
69
84
  }
@@ -95,7 +110,7 @@ class StorageManager {
95
110
  await this.minioClient.fPutObject(bucket, remotePath, localPath, metaData);
96
111
 
97
112
  // 生成公网访问 URL
98
- const publicHost = minioConfig.public_host;
113
+ const publicHost = minioConfig.publicHost;
99
114
  const videoUrl = `${publicHost}/${bucket}/${remotePath}`;
100
115
 
101
116
  console.log('[Storage] MinIO 上传成功:', videoUrl);
@@ -106,6 +121,50 @@ class StorageManager {
106
121
  }
107
122
  }
108
123
 
124
+ /**
125
+ * 上传到 阿里云 OSS
126
+ */
127
+ async uploadToOss(localPath, remotePath) {
128
+ try {
129
+ // 检查文件是否存在
130
+ if (!fs.existsSync(localPath)) {
131
+ throw new Error(`本地文件不存在: ${localPath}`);
132
+ }
133
+
134
+ // 上传选项
135
+ const headers = {
136
+ // 指定Object的存储类型。
137
+ 'x-oss-storage-class': 'Standard',
138
+ // 指定Object的访问权限。
139
+ 'x-oss-object-acl': 'public-read', // 通常视频需要公共读权限以便播放
140
+ // 指定PutObject操作时是否覆盖同名目标Object。此处设置为true,表示禁止覆盖同名Object。
141
+ 'x-oss-forbid-overwrite': 'false', // 允许覆盖
142
+ 'Content-Type': 'video/mp4'
143
+ };
144
+
145
+ const result = await this.ossClient.put(remotePath, path.normalize(localPath), { headers });
146
+
147
+ // 生成访问 URL
148
+ // 优先使用 result.url,如果配置了自定义域名(publicHost)则使用自定义域名
149
+ const aliyunConfig = config.get('storage.aliyun');
150
+ let videoUrl = result.url;
151
+
152
+ if (aliyunConfig.publicHost) {
153
+ // 确保 publicHost 不带末尾斜杠
154
+ const host = aliyunConfig.publicHost.replace(/\/$/, '');
155
+ // 确保 remotePath 不带开头斜杠
156
+ const key = remotePath.replace(/^\//, '');
157
+ videoUrl = `${host}/${key}`;
158
+ }
159
+
160
+ console.log('[Storage] 阿里云 OSS 上传成功:', videoUrl);
161
+ return videoUrl;
162
+ } catch (error) {
163
+ console.error('[Storage] 阿里云 OSS 上传失败:', error.message);
164
+ throw error;
165
+ }
166
+ }
167
+
109
168
  /**
110
169
  * 保存到本地
111
170
  */