mb-rrvideo-server 1.0.4 → 1.0.6

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
@@ -16,8 +16,7 @@
16
16
 
17
17
  **快速参考:**
18
18
  ```bash
19
- # 下载 npm 包
20
- npm pack mb-rrvideo-server
19
+
21
20
 
22
21
  # 构建 Docker 镜像
23
22
  docker build -t mb-rrvideo-converter:latest .
@@ -31,8 +30,14 @@ docker-compose up -d
31
30
  #第一次安装
32
31
  sudo docker compose up -d --build --progress=plain
33
32
 
33
+ # 更新docker镜像:
34
+ sudo docker compose build --no-cache
35
+
34
36
  # 容器名称
35
37
  docker ps | grep rrvideo-server
38
+
39
+ # 下载 npm 包
40
+ npm pack mb-rrvideo-server
36
41
  ```
37
42
 
38
43
  ## 目录
@@ -266,6 +271,13 @@ docker-compose up -d
266
271
  docker-compose ps
267
272
  ```
268
273
 
274
+ 更新后重装:
275
+ # 强制不使用缓存构建,确保拉到最新的 npm 包
276
+ sudo docker compose build --no-cache
277
+
278
+ # 重启服务
279
+ sudo docker compose up -d
280
+
269
281
  **输出示例:**
270
282
  ```
271
283
  NAME IMAGE STATUS PORTS
package/Dockerfile CHANGED
@@ -6,6 +6,11 @@
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 \
@@ -70,10 +75,10 @@ RUN npm install -g --verbose --ignore-scripts \
70
75
 
71
76
  # ============================================
72
77
  # 第六步:安装 Playwright 浏览器(Chromium)
73
- # 使用 HTTPS_PROXY 环境变量(注意是 HTTPS_PROXY,且要在一行内执行)
78
+ # 使用构建参数中的代理(只在此步骤生效)
74
79
  # ============================================
75
- RUN export HTTPS_PROXY=http://172.168.1.118:1087 && \
76
- export HTTP_PROXY=http://172.168.1.118:1087 && \
80
+ RUN export HTTP_PROXY=$HTTP_PROXY && \
81
+ export HTTPS_PROXY=$HTTPS_PROXY && \
77
82
  npx playwright install chromium
78
83
 
79
84
  # ============================================
@@ -6,9 +6,10 @@
6
6
 
7
7
  const path = require('path');
8
8
 
9
- // 设置工作目录为项目根目录
10
- const projectRoot = path.resolve(__dirname, '..');
11
- process.chdir(projectRoot);
9
+ // 设置工作目录为项目根目录(如果有必要,或者保持当前目录)
10
+ // const projectRoot = path.resolve(__dirname, '..');
11
+ // process.chdir(projectRoot);
12
12
 
13
13
  // 启动服务
14
- require('../src/index.js');
14
+ const { startServer } = require('../src/index.js');
15
+ startServer();
@@ -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.4",
3
+ "version": "1.0.6",
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
@@ -138,8 +138,8 @@ class ConfigManager {
138
138
  }
139
139
 
140
140
  const storageType = this.config.storage.type;
141
- if (storageType !== 'local' && storageType !== 'minio') {
142
- throw new Error('storage.type 必须是 local 或 minio');
141
+ if (storageType !== 'local' && storageType !== 'minio' && storageType !== 'aliyun') {
142
+ throw new Error('storage.type 必须是 local, minio aliyun');
143
143
  }
144
144
 
145
145
  // 如果使用 MinIO,验证 MinIO 配置
@@ -150,6 +150,14 @@ class ConfigManager {
150
150
  }
151
151
  }
152
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
+
153
161
  console.log('[Config] 配置验证通过');
154
162
  console.log('[Config] 存储类型:', storageType);
155
163
  }
package/src/index.js CHANGED
@@ -11,6 +11,35 @@ const { handleReceiveRequest } = require('./routes/receive');
11
11
  const { handleConvertV1, handleConvertV2 } = require('./routes/convert');
12
12
  const { handleMerge } = require('./routes/merge');
13
13
 
14
+ // 全局错误处理
15
+ process.on('exit', (code) => {
16
+ console.log(`进程退出,代码: ${code}`);
17
+ logger.flushAll();
18
+ });
19
+
20
+ process.on('SIGINT', () => {
21
+ console.log('收到 SIGINT 信号,正在关闭...');
22
+ logger.flushAll();
23
+ process.exit(0);
24
+ });
25
+
26
+ process.on('SIGTERM', () => {
27
+ console.log('收到 SIGTERM 信号,正在关闭...');
28
+ logger.flushAll();
29
+ process.exit(0);
30
+ });
31
+
32
+ process.on('uncaughtException', (err) => {
33
+ console.error(`未捕获的异常: ${err.message}`);
34
+ console.error(err.stack);
35
+ logger.flushAll();
36
+ process.exit(1);
37
+ });
38
+
39
+ process.on('unhandledRejection', (reason, promise) => {
40
+ console.error(`未处理的 Promise 拒绝: ${reason}`);
41
+ });
42
+
14
43
  // 创建 HTTP 服务器
15
44
  const server = http.createServer((req, res) => {
16
45
  try {
@@ -94,8 +123,8 @@ const server = http.createServer((req, res) => {
94
123
  }
95
124
  });
96
125
 
97
- // 启动服务器
98
- if (require.main === module) {
126
+ // 封装启动逻辑
127
+ function startServer() {
99
128
  const PORT = config.get('server.port', 24203);
100
129
  const HOST = config.get('server.host', '0.0.0.0');
101
130
 
@@ -104,35 +133,12 @@ if (require.main === module) {
104
133
  console.log(`Storage type: ${config.get('storage.type')}`);
105
134
  console.log(`Log level: ${config.get('log.level')}`);
106
135
  });
107
-
108
- // 程序异常或提前终止时的处理
109
- process.on('exit', (code) => {
110
- console.log(`进程退出,代码: ${code}`);
111
- logger.flushAll();
112
- });
113
-
114
- process.on('SIGINT', () => {
115
- console.log('收到 SIGINT 信号,正在关闭...');
116
- logger.flushAll();
117
- process.exit(0);
118
- });
119
-
120
- process.on('SIGTERM', () => {
121
- console.log('收到 SIGTERM 信号,正在关闭...');
122
- logger.flushAll();
123
- process.exit(0);
124
- });
125
-
126
- process.on('uncaughtException', (err) => {
127
- console.error(`未捕获的异常: ${err.message}`);
128
- console.error(err.stack);
129
- logger.flushAll();
130
- process.exit(1);
131
- });
136
+ }
132
137
 
133
- process.on('unhandledRejection', (reason, promise) => {
134
- console.error(`未处理的 Promise 拒绝: ${reason}`);
135
- });
138
+ // 如果是直接运行脚本,则启动服务器
139
+ if (require.main === module) {
140
+ startServer();
136
141
  }
137
142
 
138
- module.exports = { server };
143
+ // 导出 server 和启动函数
144
+ module.exports = { server, startServer };
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
  */