@dofe/infra-shared-services 0.1.17 → 0.1.19

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.
Files changed (274) hide show
  1. package/dist/agentx/agentx-client.module.d.ts.map +1 -1
  2. package/dist/agentx/agentx-client.module.js.map +1 -1
  3. package/dist/agentx/agentx-client.service.d.ts.map +1 -1
  4. package/dist/agentx/agentx-client.service.js.map +1 -1
  5. package/dist/agentx/agentx-file-client.service.d.ts.map +1 -1
  6. package/dist/agentx/agentx-file-client.service.js.map +1 -1
  7. package/dist/agentx/index.d.ts.map +1 -1
  8. package/dist/agentx/index.js.map +1 -1
  9. package/dist/agentx/interfaces/file.interface.d.ts.map +1 -1
  10. package/dist/agentx/interfaces/file.interface.js.map +1 -1
  11. package/dist/agentx/interfaces/task.interface.d.ts.map +1 -1
  12. package/dist/agentx/interfaces/task.interface.js.map +1 -1
  13. package/dist/email/dto/email.dto.d.ts +70 -0
  14. package/dist/email/dto/email.dto.d.ts.map +1 -0
  15. package/dist/email/dto/email.dto.js +58 -0
  16. package/dist/email/dto/email.dto.js.map +1 -0
  17. package/dist/email/email.module.d.ts.map +1 -1
  18. package/dist/email/email.module.js.map +1 -1
  19. package/dist/email/email.service.d.ts.map +1 -1
  20. package/dist/email/email.service.js +1 -1
  21. package/dist/email/email.service.js.map +1 -1
  22. package/dist/email/index.d.ts +5 -0
  23. package/dist/email/index.d.ts.map +1 -0
  24. package/dist/email/index.js +26 -0
  25. package/dist/email/index.js.map +1 -0
  26. package/dist/file-cdn/dto/file-cdn.dto.d.ts.map +1 -1
  27. package/dist/file-cdn/dto/file-cdn.dto.js.map +1 -1
  28. package/dist/file-cdn/file-cdn.client.d.ts +1 -1
  29. package/dist/file-cdn/file-cdn.client.d.ts.map +1 -1
  30. package/dist/file-cdn/file-cdn.client.js +2 -2
  31. package/dist/file-cdn/file-cdn.client.js.map +1 -1
  32. package/dist/file-cdn/file-cdn.module.d.ts.map +1 -1
  33. package/dist/file-cdn/file-cdn.module.js +2 -2
  34. package/dist/file-cdn/file-cdn.module.js.map +1 -1
  35. package/dist/file-cdn/index.d.ts.map +1 -1
  36. package/dist/file-cdn/index.js.map +1 -1
  37. package/dist/file-storage/bucket-resolver.d.ts +9 -9
  38. package/dist/file-storage/bucket-resolver.d.ts.map +1 -1
  39. package/dist/file-storage/bucket-resolver.js +4 -4
  40. package/dist/file-storage/bucket-resolver.js.map +1 -1
  41. package/dist/file-storage/file-storage.factory.d.ts +6 -6
  42. package/dist/file-storage/file-storage.factory.d.ts.map +1 -1
  43. package/dist/file-storage/file-storage.factory.js +10 -10
  44. package/dist/file-storage/file-storage.factory.js.map +1 -1
  45. package/dist/file-storage/file-storage.module.d.ts.map +1 -1
  46. package/dist/file-storage/file-storage.module.js.map +1 -1
  47. package/dist/file-storage/file-storage.service.d.ts +3 -3
  48. package/dist/file-storage/file-storage.service.d.ts.map +1 -1
  49. package/dist/file-storage/file-storage.service.js +1 -1
  50. package/dist/file-storage/file-storage.service.js.map +1 -1
  51. package/dist/file-storage/index.d.ts +1 -1
  52. package/dist/file-storage/index.d.ts.map +1 -1
  53. package/dist/file-storage/index.js.map +1 -1
  54. package/dist/file-storage/types.d.ts +7 -7
  55. package/dist/file-storage/types.d.ts.map +1 -1
  56. package/dist/file-storage/types.js.map +1 -1
  57. package/dist/index.d.ts +6 -1
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +5 -0
  60. package/dist/index.js.map +1 -1
  61. package/dist/ip-geo/continent-mapping.d.ts.map +1 -1
  62. package/dist/ip-geo/continent-mapping.js.map +1 -1
  63. package/dist/ip-geo/index.d.ts +33 -0
  64. package/dist/ip-geo/index.d.ts.map +1 -0
  65. package/dist/ip-geo/index.js +41 -0
  66. package/dist/ip-geo/index.js.map +1 -0
  67. package/dist/ip-geo/ip-geo.module.d.ts.map +1 -1
  68. package/dist/ip-geo/ip-geo.module.js.map +1 -1
  69. package/dist/ip-geo/ip-geo.service.d.ts.map +1 -1
  70. package/dist/ip-geo/ip-geo.service.js.map +1 -1
  71. package/dist/ip-info/index.d.ts +7 -0
  72. package/dist/ip-info/index.d.ts.map +1 -0
  73. package/dist/ip-info/index.js +13 -0
  74. package/dist/ip-info/index.js.map +1 -0
  75. package/dist/ip-info/ip-info.client.d.ts.map +1 -1
  76. package/dist/ip-info/ip-info.client.js +2 -2
  77. package/dist/ip-info/ip-info.client.js.map +1 -1
  78. package/dist/ip-info/ip-info.module.d.ts.map +1 -1
  79. package/dist/ip-info/ip-info.module.js.map +1 -1
  80. package/dist/ip-info/ip-info.service.d.ts.map +1 -1
  81. package/dist/ip-info/ip-info.service.js +3 -3
  82. package/dist/ip-info/ip-info.service.js.map +1 -1
  83. package/dist/ip-info-client/dto/ip-info.dto.d.ts.map +1 -1
  84. package/dist/ip-info-client/dto/ip-info.dto.js.map +1 -1
  85. package/dist/ip-info-client/index.d.ts.map +1 -1
  86. package/dist/ip-info-client/index.js.map +1 -1
  87. package/dist/ip-info-client/ip-info.client.d.ts.map +1 -1
  88. package/dist/ip-info-client/ip-info.client.js.map +1 -1
  89. package/dist/ip-info-client/ip-info.module.d.ts.map +1 -1
  90. package/dist/ip-info-client/ip-info.module.js.map +1 -1
  91. package/dist/notification/index.d.ts.map +1 -1
  92. package/dist/notification/index.js.map +1 -1
  93. package/dist/notification/notification.module.d.ts.map +1 -1
  94. package/dist/notification/notification.module.js.map +1 -1
  95. package/dist/notification/notification.service.d.ts.map +1 -1
  96. package/dist/notification/notification.service.js.map +1 -1
  97. package/dist/notification/notification.types.d.ts.map +1 -1
  98. package/dist/notification/notification.types.js.map +1 -1
  99. package/dist/ocr/index.d.ts +33 -0
  100. package/dist/ocr/index.d.ts.map +1 -0
  101. package/dist/ocr/index.js +53 -0
  102. package/dist/ocr/index.js.map +1 -0
  103. package/dist/ocr/ocr.module.d.ts.map +1 -1
  104. package/dist/ocr/ocr.module.js.map +1 -1
  105. package/dist/ocr/ocr.service.d.ts.map +1 -1
  106. package/dist/ocr/ocr.service.js.map +1 -1
  107. package/dist/openspeech/index.d.ts +35 -0
  108. package/dist/openspeech/index.d.ts.map +1 -0
  109. package/dist/openspeech/index.js +56 -0
  110. package/dist/openspeech/index.js.map +1 -0
  111. package/dist/openspeech/openspeech.client.d.ts +304 -0
  112. package/dist/openspeech/openspeech.client.d.ts.map +1 -0
  113. package/dist/openspeech/openspeech.client.js +405 -0
  114. package/dist/openspeech/openspeech.client.js.map +1 -0
  115. package/dist/openspeech/openspeech.factory.d.ts +247 -0
  116. package/dist/openspeech/openspeech.factory.d.ts.map +1 -0
  117. package/dist/openspeech/openspeech.factory.js +406 -0
  118. package/dist/openspeech/openspeech.factory.js.map +1 -0
  119. package/dist/openspeech/openspeech.module.d.ts +45 -0
  120. package/dist/openspeech/openspeech.module.d.ts.map +1 -0
  121. package/dist/openspeech/openspeech.module.js +68 -0
  122. package/dist/openspeech/openspeech.module.js.map +1 -0
  123. package/dist/openspeech/providers/aliyun.provider.d.ts +125 -0
  124. package/dist/openspeech/providers/aliyun.provider.d.ts.map +1 -0
  125. package/dist/openspeech/providers/aliyun.provider.js +274 -0
  126. package/dist/openspeech/providers/aliyun.provider.js.map +1 -0
  127. package/dist/openspeech/providers/base.provider.d.ts +98 -0
  128. package/dist/openspeech/providers/base.provider.d.ts.map +1 -0
  129. package/dist/openspeech/providers/base.provider.js +87 -0
  130. package/dist/openspeech/providers/base.provider.js.map +1 -0
  131. package/dist/openspeech/providers/index.d.ts +10 -0
  132. package/dist/openspeech/providers/index.d.ts.map +1 -0
  133. package/dist/openspeech/providers/index.js +26 -0
  134. package/dist/openspeech/providers/index.js.map +1 -0
  135. package/dist/openspeech/providers/volcengine-streaming.provider.d.ts +291 -0
  136. package/dist/openspeech/providers/volcengine-streaming.provider.d.ts.map +1 -0
  137. package/dist/openspeech/providers/volcengine-streaming.provider.js +1358 -0
  138. package/dist/openspeech/providers/volcengine-streaming.provider.js.map +1 -0
  139. package/dist/openspeech/providers/volcengine.provider.d.ts +144 -0
  140. package/dist/openspeech/providers/volcengine.provider.d.ts.map +1 -0
  141. package/dist/openspeech/providers/volcengine.provider.js +337 -0
  142. package/dist/openspeech/providers/volcengine.provider.js.map +1 -0
  143. package/dist/openspeech/types.d.ts +408 -0
  144. package/dist/openspeech/types.d.ts.map +1 -0
  145. package/dist/openspeech/types.js +11 -0
  146. package/dist/openspeech/types.js.map +1 -0
  147. package/dist/sms/index.d.ts +5 -0
  148. package/dist/sms/index.d.ts.map +1 -0
  149. package/dist/sms/index.js +29 -0
  150. package/dist/sms/index.js.map +1 -0
  151. package/dist/sms/sms.factory.d.ts.map +1 -1
  152. package/dist/sms/sms.factory.js +6 -6
  153. package/dist/sms/sms.factory.js.map +1 -1
  154. package/dist/sms/sms.module.d.ts.map +1 -1
  155. package/dist/sms/sms.module.js.map +1 -1
  156. package/dist/sms/sms.service.d.ts.map +1 -1
  157. package/dist/sms/sms.service.js.map +1 -1
  158. package/dist/sms/types.d.ts.map +1 -1
  159. package/dist/sms/types.js.map +1 -1
  160. package/dist/streaming-asr/index.d.ts +45 -0
  161. package/dist/streaming-asr/index.d.ts.map +1 -0
  162. package/dist/streaming-asr/index.js +66 -0
  163. package/dist/streaming-asr/index.js.map +1 -0
  164. package/dist/streaming-asr/streaming-asr.module.d.ts.map +1 -1
  165. package/dist/streaming-asr/streaming-asr.module.js.map +1 -1
  166. package/dist/streaming-asr/streaming-asr.service.d.ts.map +1 -1
  167. package/dist/streaming-asr/streaming-asr.service.js +2 -2
  168. package/dist/streaming-asr/streaming-asr.service.js.map +1 -1
  169. package/dist/streaming-asr/types.d.ts +1 -1
  170. package/dist/streaming-asr/types.d.ts.map +1 -1
  171. package/dist/streaming-asr/types.js.map +1 -1
  172. package/dist/system-health/index.d.ts +7 -0
  173. package/dist/system-health/index.d.ts.map +1 -0
  174. package/dist/system-health/index.js +25 -0
  175. package/dist/system-health/index.js.map +1 -0
  176. package/dist/system-health/system-health.controller.d.ts.map +1 -1
  177. package/dist/system-health/system-health.controller.js.map +1 -1
  178. package/dist/system-health/system-health.module.d.ts.map +1 -1
  179. package/dist/system-health/system-health.module.js.map +1 -1
  180. package/dist/system-health/system-health.service.d.ts.map +1 -1
  181. package/dist/system-health/system-health.service.js.map +1 -1
  182. package/dist/transcode/config/aliyun-oss.config.d.ts +14 -0
  183. package/dist/transcode/config/aliyun-oss.config.d.ts.map +1 -0
  184. package/dist/transcode/config/aliyun-oss.config.js +3 -0
  185. package/dist/transcode/config/aliyun-oss.config.js.map +1 -0
  186. package/dist/transcode/config/transcode.config.d.ts +55 -0
  187. package/dist/transcode/config/transcode.config.d.ts.map +1 -0
  188. package/dist/transcode/config/transcode.config.js +98 -0
  189. package/dist/transcode/config/transcode.config.js.map +1 -0
  190. package/dist/transcode/index.d.ts +27 -0
  191. package/dist/transcode/index.d.ts.map +1 -0
  192. package/dist/transcode/index.js +55 -0
  193. package/dist/transcode/index.js.map +1 -0
  194. package/dist/transcode/modules/aliyun-imm/aliyun-imm.client.d.ts +157 -0
  195. package/dist/transcode/modules/aliyun-imm/aliyun-imm.client.d.ts.map +1 -0
  196. package/dist/transcode/modules/aliyun-imm/aliyun-imm.client.js +880 -0
  197. package/dist/transcode/modules/aliyun-imm/aliyun-imm.client.js.map +1 -0
  198. package/dist/transcode/modules/aliyun-imm/aliyun-imm.module.d.ts +3 -0
  199. package/dist/transcode/modules/aliyun-imm/aliyun-imm.module.d.ts.map +1 -0
  200. package/dist/transcode/modules/aliyun-imm/aliyun-imm.module.js +23 -0
  201. package/dist/transcode/modules/aliyun-imm/aliyun-imm.module.js.map +1 -0
  202. package/dist/transcode/modules/aliyun-oss/aliyun-oss-transcode.client.d.ts +252 -0
  203. package/dist/transcode/modules/aliyun-oss/aliyun-oss-transcode.client.d.ts.map +1 -0
  204. package/dist/transcode/modules/aliyun-oss/aliyun-oss-transcode.client.js +1372 -0
  205. package/dist/transcode/modules/aliyun-oss/aliyun-oss-transcode.client.js.map +1 -0
  206. package/dist/transcode/modules/aliyun-oss/aliyun-oss-transcode.module.d.ts +3 -0
  207. package/dist/transcode/modules/aliyun-oss/aliyun-oss-transcode.module.d.ts.map +1 -0
  208. package/dist/transcode/modules/aliyun-oss/aliyun-oss-transcode.module.js +25 -0
  209. package/dist/transcode/modules/aliyun-oss/aliyun-oss-transcode.module.js.map +1 -0
  210. package/dist/transcode/modules/transcode-strategy/transcode-strategy.client.d.ts +118 -0
  211. package/dist/transcode/modules/transcode-strategy/transcode-strategy.client.d.ts.map +1 -0
  212. package/dist/transcode/modules/transcode-strategy/transcode-strategy.client.js +566 -0
  213. package/dist/transcode/modules/transcode-strategy/transcode-strategy.client.js.map +1 -0
  214. package/dist/transcode/modules/transcode-strategy/transcode-strategy.module.d.ts +3 -0
  215. package/dist/transcode/modules/transcode-strategy/transcode-strategy.module.d.ts.map +1 -0
  216. package/dist/transcode/modules/transcode-strategy/transcode-strategy.module.js +33 -0
  217. package/dist/transcode/modules/transcode-strategy/transcode-strategy.module.js.map +1 -0
  218. package/dist/transcode/modules/volcengine-tos/volcengine-tos-transcode.client.d.ts +93 -0
  219. package/dist/transcode/modules/volcengine-tos/volcengine-tos-transcode.client.d.ts.map +1 -0
  220. package/dist/transcode/modules/volcengine-tos/volcengine-tos-transcode.client.js +487 -0
  221. package/dist/transcode/modules/volcengine-tos/volcengine-tos-transcode.client.js.map +1 -0
  222. package/dist/transcode/modules/volcengine-tos/volcengine-tos-transcode.dto.d.ts +505 -0
  223. package/dist/transcode/modules/volcengine-tos/volcengine-tos-transcode.dto.d.ts.map +1 -0
  224. package/dist/transcode/modules/volcengine-tos/volcengine-tos-transcode.dto.js +10 -0
  225. package/dist/transcode/modules/volcengine-tos/volcengine-tos-transcode.dto.js.map +1 -0
  226. package/dist/transcode/modules/volcengine-tos/volcengine-tos-transcode.module.d.ts +3 -0
  227. package/dist/transcode/modules/volcengine-tos/volcengine-tos-transcode.module.d.ts.map +1 -0
  228. package/dist/transcode/modules/volcengine-tos/volcengine-tos-transcode.module.js +31 -0
  229. package/dist/transcode/modules/volcengine-tos/volcengine-tos-transcode.module.js.map +1 -0
  230. package/dist/transcode/types/transcode.types.d.ts +93 -0
  231. package/dist/transcode/types/transcode.types.d.ts.map +1 -0
  232. package/dist/transcode/types/transcode.types.js +3 -0
  233. package/dist/transcode/types/transcode.types.js.map +1 -0
  234. package/dist/transcode/utils/file.validator.d.ts +43 -0
  235. package/dist/transcode/utils/file.validator.d.ts.map +1 -0
  236. package/dist/transcode/utils/file.validator.js +126 -0
  237. package/dist/transcode/utils/file.validator.js.map +1 -0
  238. package/dist/transcode/utils/transcode.helper.d.ts +42 -0
  239. package/dist/transcode/utils/transcode.helper.d.ts.map +1 -0
  240. package/dist/transcode/utils/transcode.helper.js +221 -0
  241. package/dist/transcode/utils/transcode.helper.js.map +1 -0
  242. package/dist/uploader/index.d.ts +3 -0
  243. package/dist/uploader/index.d.ts.map +1 -0
  244. package/dist/uploader/index.js +8 -0
  245. package/dist/uploader/index.js.map +1 -0
  246. package/dist/uploader/uploader.module.d.ts.map +1 -1
  247. package/dist/uploader/uploader.module.js.map +1 -1
  248. package/dist/uploader/uploader.service.d.ts +1 -1
  249. package/dist/uploader/uploader.service.d.ts.map +1 -1
  250. package/dist/uploader/uploader.service.js +1 -1
  251. package/dist/uploader/uploader.service.js.map +1 -1
  252. package/dist/verify/index.d.ts.map +1 -1
  253. package/dist/verify/index.js.map +1 -1
  254. package/dist/verify/verify.client.d.ts.map +1 -1
  255. package/dist/verify/verify.client.js.map +1 -1
  256. package/dist/verify/verify.module.d.ts.map +1 -1
  257. package/dist/verify/verify.module.js.map +1 -1
  258. package/dist/volcengine-tts/dto/tts.dto.d.ts +52 -0
  259. package/dist/volcengine-tts/dto/tts.dto.d.ts.map +1 -0
  260. package/dist/volcengine-tts/dto/tts.dto.js +59 -0
  261. package/dist/volcengine-tts/dto/tts.dto.js.map +1 -0
  262. package/dist/volcengine-tts/index.d.ts +4 -0
  263. package/dist/volcengine-tts/index.d.ts.map +1 -0
  264. package/dist/volcengine-tts/index.js +20 -0
  265. package/dist/volcengine-tts/index.js.map +1 -0
  266. package/dist/volcengine-tts/volcengine-tts.client.d.ts +104 -0
  267. package/dist/volcengine-tts/volcengine-tts.client.d.ts.map +1 -0
  268. package/dist/volcengine-tts/volcengine-tts.client.js +690 -0
  269. package/dist/volcengine-tts/volcengine-tts.client.js.map +1 -0
  270. package/dist/volcengine-tts/volcengine-tts.module.d.ts +3 -0
  271. package/dist/volcengine-tts/volcengine-tts.module.d.ts.map +1 -0
  272. package/dist/volcengine-tts/volcengine-tts.module.js +34 -0
  273. package/dist/volcengine-tts/volcengine-tts.module.js.map +1 -0
  274. package/package.json +30 -9
@@ -0,0 +1,1372 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ var __importDefault = (this && this.__importDefault) || function (mod) {
15
+ return (mod && mod.__esModule) ? mod : { "default": mod };
16
+ };
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.AliyunOssTranscodeClient = void 0;
19
+ const common_1 = require("@nestjs/common");
20
+ const nest_winston_1 = require("nest-winston");
21
+ const winston_1 = require("winston");
22
+ const config_1 = require("@nestjs/config");
23
+ const axios_1 = require("@nestjs/axios");
24
+ const client_1 = require("@prisma/client");
25
+ const infra_utils_1 = require("@dofe/infra-utils");
26
+ const infra_common_1 = require("@dofe/infra-common");
27
+ const aliyun_imm_client_1 = require("../aliyun-imm/aliyun-imm.client");
28
+ const ali_oss_1 = __importDefault(require("ali-oss"));
29
+ const rxjs_1 = require("rxjs");
30
+ let AliyunOssTranscodeClient = class AliyunOssTranscodeClient {
31
+ configService;
32
+ logger;
33
+ aliyunImm;
34
+ httpService;
35
+ ossClients;
36
+ configs;
37
+ constructor(configService, logger, aliyunImm, httpService) {
38
+ this.configService = configService;
39
+ this.logger = logger;
40
+ this.aliyunImm = aliyunImm;
41
+ this.httpService = httpService;
42
+ // 预初始化所有OSS客户端
43
+ this.configs = {
44
+ 'pardx-files': this.getAliyunOssConfig('oss', 'pardx-files'),
45
+ 'pardx-image': this.getAliyunOssConfig('oss', 'pardx-image'),
46
+ 'pardx-ai': this.getAliyunOssConfig('oss', 'pardx-ai'),
47
+ 'pardx-transcoding': this.getAliyunOssConfig('oss', 'pardx-transcoding'),
48
+ };
49
+ // 创建OSS客户端实例
50
+ this.ossClients = {};
51
+ Object.entries(this.configs).forEach(([bucket, config]) => {
52
+ this.ossClients[bucket] = this.createOssClient(config);
53
+ });
54
+ }
55
+ /**
56
+ * 获取阿里云 OSS 配置
57
+ */
58
+ getAliyunOssConfig(vendor, bucket) {
59
+ if (vendor !== 'oss') {
60
+ throw new Error(`Unsupported vendor: ${vendor}`);
61
+ }
62
+ const bucketConfigs = this.configService.getOrThrow('buckets');
63
+ const bucketConfig = infra_utils_1.arrayUtil.findOne(bucketConfigs, {
64
+ bucket,
65
+ vendor,
66
+ });
67
+ if (!bucketConfig) {
68
+ throw new Error(`Bucket config not found: ${bucket}`);
69
+ }
70
+ // 从配置中获取阿里云 OSS 配置
71
+ const ossConfig = (0, infra_common_1.getKeysConfig)()?.storage?.[vendor];
72
+ if (!ossConfig) {
73
+ throw new Error('Aliyun OSS configuration not found');
74
+ }
75
+ return {
76
+ endpoint: bucketConfig.endpoint,
77
+ accessKeyId: ossConfig.accessKey,
78
+ accessKeySecret: ossConfig.secretKey,
79
+ bucket,
80
+ };
81
+ }
82
+ /**
83
+ * 构建 OSS 处理 URL
84
+ */
85
+ buildProcessUrl(vendor, bucket, key, process) {
86
+ if (vendor !== 'oss') {
87
+ throw new Error(`Unsupported vendor: ${vendor}`);
88
+ }
89
+ const config = this.getAliyunOssConfig(vendor, bucket);
90
+ const encodedProcess = encodeURIComponent(process);
91
+ return `${config.endpoint}/${bucket}/${key}?x-oss-process=${encodedProcess}`;
92
+ }
93
+ /**
94
+ * 执行 OSS 处理请求
95
+ */
96
+ async executeOssProcess(vendor, bucket, key, process) {
97
+ if (vendor !== 'oss') {
98
+ throw new Error(`Unsupported vendor: ${vendor}`);
99
+ }
100
+ try {
101
+ this.logger.debug('Executing OSS process', {
102
+ bucket,
103
+ key,
104
+ process,
105
+ });
106
+ // 使用 ali-oss 客户端直接处理
107
+ const result = await this.executeOssProcessWithClient(vendor, bucket, key, process);
108
+ return result;
109
+ }
110
+ catch (error) {
111
+ this.logger.error('OSS process failed', {
112
+ vendor,
113
+ bucket,
114
+ key,
115
+ process,
116
+ error: (error instanceof Error ? error.message : String(error)),
117
+ });
118
+ throw new Error(`OSS process failed: ${(error instanceof Error ? error.message : String(error))}`);
119
+ }
120
+ }
121
+ /**
122
+ * 使用 ali-oss 客户端直接执行 OSS 处理请求
123
+ * 参考:https://github.com/ali-sdk/ali-oss/tree/master?tab=readme-ov-file#getname-file-options
124
+ */
125
+ async executeOssProcessWithClient(vendor, bucket, key, process, outputKey = null) {
126
+ if (vendor !== 'oss') {
127
+ throw new Error(`Unsupported vendor: ${vendor}`);
128
+ }
129
+ try {
130
+ const ossClient = this.getOssClient(bucket);
131
+ console.log('Executing OSS process with client', {
132
+ bucket,
133
+ key,
134
+ process,
135
+ outputKey,
136
+ });
137
+ // 使用 ali-oss 的 get 方法直接处理
138
+ // 参考:https://github.com/ali-sdk/ali-oss/tree/master?tab=readme-ov-file#getname-file-options
139
+ const result = await ossClient.processObjectSave(key, outputKey, process, bucket);
140
+ this.logger.debug('OSS process completed successfully', {
141
+ bucket,
142
+ key,
143
+ process,
144
+ resultSize: result.content?.length || 0,
145
+ });
146
+ return result;
147
+ }
148
+ catch (error) {
149
+ const err = error;
150
+ this.logger.error('OSS process with client failed', {
151
+ vendor,
152
+ bucket,
153
+ key,
154
+ process,
155
+ error: (error instanceof Error ? error.message : String(error)),
156
+ errorCode: err.code,
157
+ errorName: err.name,
158
+ });
159
+ // 根据错误类型提供更详细的错误信息
160
+ if (err.code === 'NoSuchKey') {
161
+ throw new Error(`File not found: ${key} in bucket ${bucket}`);
162
+ }
163
+ else if (err.code === 'AccessDenied') {
164
+ throw new Error(`Access denied to bucket ${bucket} or file ${key}`);
165
+ }
166
+ else if (err.code === 'InvalidArgument') {
167
+ throw new Error(`Invalid process parameters: ${process}`);
168
+ }
169
+ else if (err.name === 'RequestTimeoutError') {
170
+ throw new Error(`Request timeout for process: ${process}`);
171
+ }
172
+ else {
173
+ throw new Error(`OSS process failed: ${(error instanceof Error ? error.message : String(error))}`);
174
+ }
175
+ }
176
+ }
177
+ /**
178
+ * 获取视频信息(使用 IMM 服务)
179
+ */
180
+ async getVideoInfo(vendor, bucket, key, type = 'imm') {
181
+ try {
182
+ this.logger.info('Getting video info using IMM service', {
183
+ vendor,
184
+ bucket,
185
+ key,
186
+ type,
187
+ });
188
+ const fileType = 'video';
189
+ // 统一使用 IMM 服务获取视频信息
190
+ const result = await this.aliyunImm.detectMediaMeta(vendor, bucket, key, fileType);
191
+ this.logger.info('Video info extracted successfully', {
192
+ type: result.type,
193
+ info: result.info,
194
+ });
195
+ return result.info;
196
+ }
197
+ catch (error) {
198
+ this.logger.error('Failed to get video info', {
199
+ vendor,
200
+ bucket,
201
+ key,
202
+ type,
203
+ error: (error instanceof Error ? error.message : String(error)),
204
+ });
205
+ throw error;
206
+ }
207
+ }
208
+ /**
209
+ * 获取音频信息(使用 IMM 服务)
210
+ */
211
+ async getAudioInfo(vendor, bucket, key, type = 'imm') {
212
+ try {
213
+ this.logger.info('Getting audio info using IMM service', {
214
+ vendor,
215
+ bucket,
216
+ key,
217
+ type,
218
+ });
219
+ const fileType = 'audio';
220
+ // 统一使用 IMM 服务获取音频信息
221
+ const result = await this.aliyunImm.detectMediaMeta(vendor, bucket, key, fileType);
222
+ this.logger.info('Audio info extracted successfully', {
223
+ type: result.type,
224
+ info: result.info,
225
+ });
226
+ return result.info;
227
+ }
228
+ catch (error) {
229
+ this.logger.error('Failed to get audio info', {
230
+ vendor,
231
+ bucket,
232
+ key,
233
+ type,
234
+ error: (error instanceof Error ? error.message : String(error)),
235
+ });
236
+ throw error;
237
+ }
238
+ }
239
+ /**
240
+ * 获取图片信息(使用 IMM 服务)
241
+ */
242
+ async getImageInfo(vendor, bucket, key, type = 'imm') {
243
+ try {
244
+ this.logger.info('Getting image info using IMM service', {
245
+ vendor,
246
+ bucket,
247
+ key,
248
+ type,
249
+ });
250
+ const fileType = 'image';
251
+ // 统一使用 IMM 服务获取图片信息
252
+ const result = await this.aliyunImm.detectMediaMeta(vendor, bucket, key, fileType);
253
+ this.logger.info('Image info extracted successfully', {
254
+ type: result.type,
255
+ info: result.info,
256
+ });
257
+ return result.info;
258
+ }
259
+ catch (error) {
260
+ this.logger.error('Failed to get image info', {
261
+ vendor,
262
+ bucket,
263
+ key,
264
+ type,
265
+ error: (error instanceof Error ? error.message : String(error)),
266
+ });
267
+ throw error;
268
+ }
269
+ }
270
+ /**
271
+ * 视频转码(使用 IMM 服务)
272
+ */
273
+ async transcodeVideo(vendor, bucket, key, quality = [
274
+ client_1.VideoQuality.VIDEO_4K,
275
+ client_1.VideoQuality.VIDEO_1080P,
276
+ client_1.VideoQuality.VIDEO_720P,
277
+ client_1.VideoQuality.VIDEO_360P,
278
+ ], index = 0) {
279
+ try {
280
+ this.logger.info('Creating video transcode task using IMM service', {
281
+ vendor,
282
+ bucket,
283
+ key,
284
+ quality,
285
+ });
286
+ // 使用 IMM 服务创建媒体转码任务
287
+ const result = await this.aliyunImm.createMediaConvertTask(vendor, bucket, key, quality, index);
288
+ console.log('Video transcode task created successfully using IMM', result);
289
+ return result;
290
+ }
291
+ catch (error) {
292
+ this.logger.error('Failed to create video transcode task using IMM', {
293
+ vendor,
294
+ bucket,
295
+ key,
296
+ quality,
297
+ error: (error instanceof Error ? error.message : String(error)),
298
+ });
299
+ throw error;
300
+ }
301
+ }
302
+ /**
303
+ * 构建异步处理指令
304
+ */
305
+ buildAsyncProcessCommand(style, bucket, targetKey) {
306
+ // Base64 编码 bucket 和 targetKey
307
+ const bucketEncoded = Buffer.from(bucket)
308
+ .toString('base64')
309
+ .replace(/=/g, '');
310
+ const targetEncoded = Buffer.from(targetKey)
311
+ .toString('base64')
312
+ .replace(/=/g, '');
313
+ // 构建完整的异步处理指令
314
+ return `${style}|sys/saveas,b_${bucketEncoded},o_${targetEncoded}`;
315
+ }
316
+ /**
317
+ * 执行异步处理任务
318
+ */
319
+ async executeAsyncProcess(vendor, bucket, key, process) {
320
+ const config = this.getAliyunOssConfig(vendor, bucket);
321
+ const url = `${config.endpoint}/${bucket}/${key}?x-oss-async-process`;
322
+ try {
323
+ const headers = this.buildCompleteAuthorizationHeaders(config, 'POST', bucket, key, 'application/x-www-form-urlencoded');
324
+ const response = await (0, rxjs_1.firstValueFrom)(this.httpService.post(url, process, {
325
+ headers,
326
+ }));
327
+ return { taskId: this.extractTaskId(response.data) };
328
+ }
329
+ catch (error) {
330
+ this.logger.error('Async process execution failed', {
331
+ url,
332
+ process,
333
+ error: (error instanceof Error ? error.message : String(error)),
334
+ });
335
+ throw new Error(`Async process failed: ${(error instanceof Error ? error.message : String(error))}`);
336
+ }
337
+ }
338
+ /**
339
+ * 构建授权头
340
+ */
341
+ buildAuthorizationHeader(config, method, bucket, key) {
342
+ try {
343
+ const signature = this.generateSignature(method, bucket, key, config);
344
+ return `OSS ${config.accessKeyId}:${signature}`;
345
+ }
346
+ catch (error) {
347
+ this.logger.error('Failed to build authorization header', {
348
+ method,
349
+ bucket,
350
+ key,
351
+ error: (error instanceof Error ? error.message : String(error)),
352
+ });
353
+ throw new Error(`Failed to build authorization header: ${(error instanceof Error ? error.message : String(error))}`);
354
+ }
355
+ }
356
+ /**
357
+ * 解析媒体元信息响应
358
+ */
359
+ parseMediaMetaResponse(mediaMetadata, type) {
360
+ if (!mediaMetadata) {
361
+ throw new Error('No media metadata found in response');
362
+ }
363
+ if (type === 'image') {
364
+ const imageInfo = {
365
+ width: mediaMetadata?.ImageWidth.value,
366
+ height: mediaMetadata?.ImageHeight.value,
367
+ sar: mediaMetadata?.ImageWidth.value +
368
+ ':' +
369
+ mediaMetadata?.ImageHeight.value,
370
+ dar: mediaMetadata?.ImageWidth.value +
371
+ ':' +
372
+ mediaMetadata?.ImageHeight.value,
373
+ ffmpegInfo: JSON.parse(JSON.stringify(mediaMetadata)), // 确保序列化
374
+ };
375
+ return {
376
+ type,
377
+ info: imageInfo,
378
+ rawData: mediaMetadata,
379
+ };
380
+ }
381
+ const { duration, videoStreams, audioStreams, videoWidth, videoHeight, } = mediaMetadata;
382
+ if (type === 'video' && videoStreams && videoStreams.length > 0) {
383
+ const videoInfo = {
384
+ width: videoWidth,
385
+ height: videoHeight,
386
+ duration: duration,
387
+ streamDuration: videoStreams[0]?.streamDuration,
388
+ sar: videoStreams[0]?.sampleAspectRatio,
389
+ dar: videoStreams[0]?.displayAspectRatio,
390
+ rFrameRate: videoStreams[0]?.frameRate,
391
+ ffmpegInfo: JSON.parse(JSON.stringify(mediaMetadata)), // 确保序列化
392
+ };
393
+ return {
394
+ type,
395
+ info: videoInfo,
396
+ rawData: mediaMetadata,
397
+ };
398
+ }
399
+ if (type === 'audio' && audioStreams && audioStreams.length > 0) {
400
+ const audioInfo = {
401
+ duration: duration,
402
+ streamDuration: audioStreams[0]?.streamDuration,
403
+ channels: audioStreams[0]?.channels,
404
+ channelLayout: audioStreams[0]?.channelLayout,
405
+ sampleRate: audioStreams[0]?.sampleRate?.toString(),
406
+ bitRate: audioStreams[0]?.bitRate,
407
+ ffmpegInfo: JSON.parse(JSON.stringify(mediaMetadata)), // 确保序列化
408
+ };
409
+ return {
410
+ type,
411
+ info: audioInfo,
412
+ rawData: mediaMetadata,
413
+ };
414
+ }
415
+ // 如果无法确定类型或没有流信息,返回原始数据
416
+ return {
417
+ type: 'else',
418
+ info: {
419
+ ffmpegInfo: JSON.parse(JSON.stringify(mediaMetadata)), // 确保序列化
420
+ },
421
+ rawData: mediaMetadata,
422
+ };
423
+ }
424
+ /**
425
+ * 解析OSS图片响应
426
+ */
427
+ parseOssImageResponse(response) {
428
+ try {
429
+ if (response.content) {
430
+ const content = response.content.toString('utf-8');
431
+ return this.parseOssImageContent(content);
432
+ }
433
+ return response;
434
+ }
435
+ catch (error) {
436
+ this.logger.warn('Failed to parse OSS image response', {
437
+ error: (error instanceof Error ? error.message : String(error)),
438
+ });
439
+ return response;
440
+ }
441
+ }
442
+ /**
443
+ * 解析OSS图片内容
444
+ */
445
+ parseOssImageContent(content) {
446
+ try {
447
+ // 尝试解析JSON
448
+ if (content.startsWith('{') || content.startsWith('[')) {
449
+ return JSON.parse(content);
450
+ }
451
+ // 解析文本格式
452
+ const lines = content.split('\n').filter((line) => line.trim());
453
+ const imageInfo = {};
454
+ lines.forEach((line) => {
455
+ const [key, value] = line.split(':').map((s) => s.trim());
456
+ if (key && value) {
457
+ if (['width', 'height', 'size'].includes(key)) {
458
+ const numValue = parseFloat(value);
459
+ if (!isNaN(numValue)) {
460
+ imageInfo[key] = numValue;
461
+ }
462
+ else {
463
+ imageInfo[key] = value;
464
+ }
465
+ }
466
+ else {
467
+ imageInfo[key] = value;
468
+ }
469
+ }
470
+ });
471
+ return {
472
+ ImageWidth: { value: imageInfo.width },
473
+ ImageHeight: { value: imageInfo.height },
474
+ format: imageInfo.format || 'unknown',
475
+ size: imageInfo.size,
476
+ rawContent: content,
477
+ };
478
+ }
479
+ catch (error) {
480
+ this.logger.warn('Failed to parse OSS image content', {
481
+ error: (error instanceof Error ? error.message : String(error)),
482
+ content: content.substring(0, 200),
483
+ });
484
+ return { rawContent: content };
485
+ }
486
+ }
487
+ /**
488
+ * 解析OSS视频响应
489
+ */
490
+ parseOssVideoResponse(response) {
491
+ try {
492
+ if (response.content) {
493
+ const content = response.content.toString('utf-8');
494
+ return this.parseOssVideoContent(content);
495
+ }
496
+ return response;
497
+ }
498
+ catch (error) {
499
+ this.logger.warn('Failed to parse OSS video response', {
500
+ error: (error instanceof Error ? error.message : String(error)),
501
+ });
502
+ return response;
503
+ }
504
+ }
505
+ /**
506
+ * 解析OSS视频内容
507
+ */
508
+ parseOssVideoContent(content) {
509
+ try {
510
+ // 尝试解析JSON
511
+ if (content.startsWith('{') || content.startsWith('[')) {
512
+ return JSON.parse(content);
513
+ }
514
+ // 解析文本格式
515
+ const lines = content.split('\n').filter((line) => line.trim());
516
+ const videoInfo = {};
517
+ lines.forEach((line) => {
518
+ const [key, value] = line.split(':').map((s) => s.trim());
519
+ if (key && value) {
520
+ if ([
521
+ 'width',
522
+ 'height',
523
+ 'duration',
524
+ 'bitrate',
525
+ 'frameRate',
526
+ ].includes(key)) {
527
+ const numValue = parseFloat(value);
528
+ if (!isNaN(numValue)) {
529
+ videoInfo[key] = numValue;
530
+ }
531
+ else {
532
+ videoInfo[key] = value;
533
+ }
534
+ }
535
+ else {
536
+ videoInfo[key] = value;
537
+ }
538
+ }
539
+ });
540
+ return {
541
+ videoWidth: videoInfo.width,
542
+ videoHeight: videoInfo.height,
543
+ duration: videoInfo.duration,
544
+ bitrate: videoInfo.bitrate,
545
+ frameRate: videoInfo.frameRate,
546
+ format: videoInfo.format || 'unknown',
547
+ codec: videoInfo.codec || 'unknown',
548
+ videoStreams: [
549
+ {
550
+ width: videoInfo.width,
551
+ height: videoInfo.height,
552
+ duration: videoInfo.duration,
553
+ bitrate: videoInfo.bitrate,
554
+ frameRate: videoInfo.frameRate,
555
+ codec: videoInfo.codec || 'unknown',
556
+ format: videoInfo.format || 'unknown',
557
+ },
558
+ ],
559
+ rawContent: content,
560
+ };
561
+ }
562
+ catch (error) {
563
+ this.logger.warn('Failed to parse OSS video content', {
564
+ error: (error instanceof Error ? error.message : String(error)),
565
+ content: content.substring(0, 200),
566
+ });
567
+ return { rawContent: content };
568
+ }
569
+ }
570
+ /**
571
+ * 解析OSS音频响应
572
+ */
573
+ parseOssAudioResponse(response) {
574
+ try {
575
+ if (response.content) {
576
+ const content = response.content.toString('utf-8');
577
+ return this.parseOssAudioContent(content);
578
+ }
579
+ return response;
580
+ }
581
+ catch (error) {
582
+ this.logger.warn('Failed to parse OSS audio response', {
583
+ error: (error instanceof Error ? error.message : String(error)),
584
+ });
585
+ return response;
586
+ }
587
+ }
588
+ /**
589
+ * 解析OSS音频内容
590
+ */
591
+ parseOssAudioContent(content) {
592
+ try {
593
+ // 尝试解析JSON
594
+ if (content.startsWith('{') || content.startsWith('[')) {
595
+ return JSON.parse(content);
596
+ }
597
+ // 解析文本格式
598
+ const lines = content.split('\n').filter((line) => line.trim());
599
+ const audioInfo = {};
600
+ lines.forEach((line) => {
601
+ const [key, value] = line.split(':').map((s) => s.trim());
602
+ if (key && value) {
603
+ if ([
604
+ 'duration',
605
+ 'channels',
606
+ 'sampleRate',
607
+ 'bitrate',
608
+ ].includes(key)) {
609
+ const numValue = parseFloat(value);
610
+ if (!isNaN(numValue)) {
611
+ audioInfo[key] = numValue;
612
+ }
613
+ else {
614
+ audioInfo[key] = value;
615
+ }
616
+ }
617
+ else {
618
+ audioInfo[key] = value;
619
+ }
620
+ }
621
+ });
622
+ return {
623
+ duration: audioInfo.duration,
624
+ audioStreams: [
625
+ {
626
+ duration: audioInfo.duration,
627
+ channels: audioInfo.channels,
628
+ sampleRate: audioInfo.sampleRate,
629
+ bitRate: audioInfo.bitrate,
630
+ codec: audioInfo.codec || 'unknown',
631
+ format: audioInfo.format || 'unknown',
632
+ },
633
+ ],
634
+ rawContent: content,
635
+ };
636
+ }
637
+ catch (error) {
638
+ this.logger.warn('Failed to parse OSS audio content', {
639
+ error: (error instanceof Error ? error.message : String(error)),
640
+ content: content.substring(0, 200),
641
+ });
642
+ return { rawContent: content };
643
+ }
644
+ }
645
+ /**
646
+ * 解析OSS head响应
647
+ */
648
+ parseOssHeadResponse(headResult, mediaType) {
649
+ try {
650
+ const result = {
651
+ type: mediaType,
652
+ rawData: headResult,
653
+ };
654
+ // 从headers中提取信息
655
+ if (headResult.res && headResult.res.headers) {
656
+ const headers = headResult.res.headers;
657
+ if (mediaType === 'image') {
658
+ result.ImageWidth = {
659
+ value: parseInt(headers['x-oss-image-width']) || 0,
660
+ };
661
+ result.ImageHeight = {
662
+ value: parseInt(headers['x-oss-image-height']) || 0,
663
+ };
664
+ result.format = headers['x-oss-image-format'] || 'unknown';
665
+ result.size = parseInt(headers['content-length']) || 0;
666
+ }
667
+ else if (mediaType === 'video') {
668
+ result.videoWidth =
669
+ parseInt(headers['x-oss-video-width']) || 0;
670
+ result.videoHeight =
671
+ parseInt(headers['x-oss-video-height']) || 0;
672
+ result.duration =
673
+ parseFloat(headers['x-oss-video-duration']) || 0;
674
+ result.format = headers['x-oss-video-format'] || 'unknown';
675
+ }
676
+ else if (mediaType === 'audio') {
677
+ result.duration =
678
+ parseFloat(headers['x-oss-audio-duration']) || 0;
679
+ result.channels =
680
+ parseInt(headers['x-oss-audio-channels']) || 0;
681
+ result.sampleRate =
682
+ parseInt(headers['x-oss-audio-sample-rate']) || 0;
683
+ result.format = headers['x-oss-audio-format'] || 'unknown';
684
+ }
685
+ }
686
+ return result;
687
+ }
688
+ catch (error) {
689
+ this.logger.warn('Failed to parse OSS head response', {
690
+ error: (error instanceof Error ? error.message : String(error)),
691
+ });
692
+ return headResult;
693
+ }
694
+ }
695
+ /**
696
+ * 获取OSS客户端实例(缓存版本)
697
+ */
698
+ getOssClient(bucket) {
699
+ if (!this.ossClients[bucket]) {
700
+ this.logger.warn(`OSS client not found for bucket: ${bucket}, creating new instance`);
701
+ this.ossClients[bucket] = this.createOssClient(this.configs[bucket]);
702
+ }
703
+ return this.ossClients[bucket];
704
+ }
705
+ /**
706
+ * 创建优化的OSS客户端实例
707
+ */
708
+ createOssClient(config) {
709
+ return new ali_oss_1.default({
710
+ region: config.region || 'cn-shanghai',
711
+ accessKeyId: config.accessKeyId,
712
+ accessKeySecret: config.accessKeySecret,
713
+ bucket: config.bucket,
714
+ endpoint: config.endpoint,
715
+ // 启用V4签名
716
+ authorizationV4: true,
717
+ // 优化配置
718
+ timeout: 30000,
719
+ retryMax: 3,
720
+ // 启用调试模式(生产环境可关闭)
721
+ debug: process.env.NODE_ENV === 'dev',
722
+ });
723
+ }
724
+ /**
725
+ * 生成签名(使用 ali-oss 客户端)
726
+ */
727
+ generateSignature(method, bucket, key, config) {
728
+ try {
729
+ const ossClient = this.createOssClient(config);
730
+ const date = new Date().toUTCString();
731
+ // 构建资源路径
732
+ const resource = `/${bucket}/${key}`;
733
+ // 构建请求头
734
+ const headers = {
735
+ date: date,
736
+ 'content-type': 'application/x-www-form-urlencoded',
737
+ };
738
+ // 使用 OSS 客户端的 authorization 方法生成签名
739
+ const authHeader = ossClient.authorization(method, resource, {}, headers);
740
+ // 从 Authorization 头中提取签名部分
741
+ const signature = authHeader.replace(`OSS ${config.accessKeyId}:`, '');
742
+ return signature;
743
+ }
744
+ catch (error) {
745
+ this.logger.error('Failed to generate OSS signature', {
746
+ method,
747
+ bucket,
748
+ key,
749
+ error: (error instanceof Error ? error.message : String(error)),
750
+ });
751
+ // 如果签名生成失败,使用简单的占位符
752
+ return 'signature_placeholder';
753
+ }
754
+ }
755
+ /**
756
+ * 生成OSS媒体处理签名(专门处理查询参数)
757
+ */
758
+ generateMediaProcessSignature(method, bucket, key, process, config) {
759
+ try {
760
+ const ossClient = this.createOssClient(config);
761
+ const date = new Date().toUTCString();
762
+ // 构建资源路径
763
+ const resource = `/${bucket}/${key}`;
764
+ // 构建查询参数
765
+ const subres = {
766
+ 'x-oss-process': process,
767
+ };
768
+ // 构建请求头
769
+ const headers = {
770
+ date: date,
771
+ 'content-type': 'application/x-www-form-urlencoded',
772
+ };
773
+ // 使用 OSS 客户端的 authorization 方法生成签名,包含查询参数
774
+ const authHeader = ossClient.authorization(method, resource, subres, headers);
775
+ // 从 Authorization 头中提取签名部分
776
+ const signature = authHeader.replace(`OSS ${config.accessKeyId}:`, '');
777
+ return signature;
778
+ }
779
+ catch (error) {
780
+ this.logger.error('Failed to generate OSS media process signature', {
781
+ method,
782
+ bucket,
783
+ key,
784
+ process,
785
+ error: (error instanceof Error ? error.message : String(error)),
786
+ });
787
+ throw new Error(`Failed to generate OSS media process signature: ${(error instanceof Error ? error.message : String(error))}`);
788
+ }
789
+ }
790
+ /**
791
+ * 构建OSS媒体处理的完整授权头
792
+ */
793
+ buildMediaProcessHeaders(config, method, bucket, key, process) {
794
+ const date = new Date().toUTCString();
795
+ const signature = this.generateMediaProcessSignature(method, bucket, key, process, config);
796
+ return {
797
+ Authorization: `OSS ${config.accessKeyId}:${signature}`,
798
+ Date: date,
799
+ 'Content-Type': 'application/x-www-form-urlencoded',
800
+ 'User-Agent': 'PardxTranscodeClient/1.0',
801
+ };
802
+ }
803
+ /**
804
+ * 构建完整的授权头(包含所有必要的头部)
805
+ */
806
+ buildCompleteAuthorizationHeaders(config, method, bucket, key, contentType = 'application/x-www-form-urlencoded') {
807
+ const date = new Date().toUTCString();
808
+ const signature = this.generateSignature(method, bucket, key, config);
809
+ return {
810
+ Authorization: `OSS ${config.accessKeyId}:${signature}`,
811
+ Date: date,
812
+ 'Content-Type': contentType,
813
+ 'User-Agent': 'PardxTranscodeClient/1.0',
814
+ };
815
+ }
816
+ /**
817
+ * 从响应中提取 taskId
818
+ */
819
+ extractTaskId(responseData) {
820
+ // 根据实际响应格式提取 taskId
821
+ if (responseData && responseData.taskId) {
822
+ return responseData.taskId;
823
+ }
824
+ // 如果没有直接的 taskId,可能需要从其他字段获取
825
+ // 或者通过其他方式获取任务标识
826
+ return `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
827
+ }
828
+ /**
829
+ * 生成视频雪碧图
830
+ * 参考阿里云OSS文档:https://help.aliyun.com/zh/oss/video-cut-sprite
831
+ */
832
+ async generateSprite(vendor, bucket, key, options = {}) {
833
+ try {
834
+ // 验证参数
835
+ this.validateSpriteOptions(options);
836
+ const { width = 160, height = 90, interval = 10, columns = 10, lines = 10, startTime = '00:00:00', format = 'jpg', scaleType = 'fit', padding = 2, margin = 2, maxFrames, percentWidth, percentHeight, } = options;
837
+ // 将起始时间转换为毫秒
838
+ const startTimeMs = this.convertTimeToMilliseconds(startTime);
839
+ // 构建OSS处理参数,按照阿里云文档规范
840
+ const processParams = [
841
+ 'video/sprite',
842
+ `f_${format}`, // 输出格式
843
+ ];
844
+ // 添加起始时间参数
845
+ if (startTimeMs > 0) {
846
+ processParams.push(`ss_${startTimeMs}`);
847
+ }
848
+ // 添加尺寸参数(像素或百分比)
849
+ if (percentWidth && percentWidth > 0 && percentWidth <= 200) {
850
+ processParams.push(`psw_${percentWidth}`);
851
+ }
852
+ else if (width > 0) {
853
+ processParams.push(`sw_${width}`);
854
+ }
855
+ if (percentHeight && percentHeight > 0 && percentHeight <= 200) {
856
+ processParams.push(`psh_${percentHeight}`);
857
+ }
858
+ else if (height > 0) {
859
+ processParams.push(`sh_${height}`);
860
+ }
861
+ // 添加抽帧参数
862
+ if (interval > 0) {
863
+ processParams.push(`inter_${interval * 1000}`); // 转换为毫秒
864
+ }
865
+ if (maxFrames && maxFrames > 0) {
866
+ processParams.push(`num_${maxFrames}`);
867
+ }
868
+ // 添加布局参数
869
+ if (columns > 0) {
870
+ processParams.push(`tw_${columns}`);
871
+ }
872
+ if (lines > 0) {
873
+ processParams.push(`th_${lines}`);
874
+ }
875
+ // 添加间隔参数
876
+ if (padding >= 0) {
877
+ processParams.push(`pad_${padding}`);
878
+ }
879
+ if (margin >= 0) {
880
+ processParams.push(`margin_${margin}`);
881
+ }
882
+ // 添加缩放方式
883
+ if (scaleType &&
884
+ ['crop', 'stretch', 'fill', 'fit'].includes(scaleType)) {
885
+ processParams.push(`scaletype_${scaleType}`);
886
+ }
887
+ const process = processParams.join(',');
888
+ // 生成雪碧图文件名
889
+ const spriteKey = this.generateSpriteKey(key, format, startTime);
890
+ // 使用 ali-oss 直接处理,而不是构建URL
891
+ const result = await this.executeOssProcessWithClient(vendor, bucket, spriteKey, process);
892
+ console.log('Sprite generation initiated', {
893
+ spriteKey,
894
+ process,
895
+ options,
896
+ startTime: startTimeMs,
897
+ format,
898
+ dimensions: `${width}x${height}`,
899
+ layout: `${columns}x${lines}`,
900
+ interval: `${interval}s`,
901
+ result: result ? 'success' : 'failed',
902
+ });
903
+ // 返回处理后的文件路径,而不是URL
904
+ return spriteKey;
905
+ }
906
+ catch (error) {
907
+ this.logger.error('Failed to generate sprite', {
908
+ vendor,
909
+ bucket,
910
+ key,
911
+ options,
912
+ error: (error instanceof Error ? error.message : String(error)),
913
+ });
914
+ throw new Error(`Sprite generation failed: ${(error instanceof Error ? error.message : String(error))}`);
915
+ }
916
+ }
917
+ /**
918
+ * 生成标准雪碧图(10x10布局,每10秒一帧)
919
+ */
920
+ async generateStandardSprite(vendor, bucket, key, options = {}) {
921
+ const defaultOptions = {
922
+ width: 160,
923
+ height: 90,
924
+ interval: 10,
925
+ columns: 10,
926
+ lines: 10,
927
+ format: 'jpg',
928
+ scaleType: 'fit',
929
+ padding: 2,
930
+ margin: 2,
931
+ };
932
+ return this.generateSprite(vendor, bucket, key, {
933
+ ...defaultOptions,
934
+ ...options,
935
+ });
936
+ }
937
+ /**
938
+ * 生成高密度雪碧图(更多帧数,更小间隔)
939
+ */
940
+ async generateHighDensitySprite(vendor, bucket, key, options = {}) {
941
+ const defaultOptions = {
942
+ width: 120,
943
+ height: 68,
944
+ interval: 5,
945
+ columns: 15,
946
+ lines: 15,
947
+ format: 'jpg',
948
+ scaleType: 'fit',
949
+ padding: 1,
950
+ margin: 1,
951
+ };
952
+ return this.generateSprite(vendor, bucket, key, {
953
+ ...defaultOptions,
954
+ ...options,
955
+ });
956
+ }
957
+ /**
958
+ * 生成宽屏雪碧图(适合16:9视频)
959
+ */
960
+ async generateWidescreenSprite(vendor, bucket, key, options = {}) {
961
+ const defaultOptions = {
962
+ width: 320,
963
+ height: 180,
964
+ interval: 15,
965
+ columns: 8,
966
+ lines: 6,
967
+ format: 'jpg',
968
+ scaleType: 'fit',
969
+ padding: 3,
970
+ margin: 3,
971
+ };
972
+ return this.generateSprite(vendor, bucket, key, {
973
+ ...defaultOptions,
974
+ ...options,
975
+ });
976
+ }
977
+ /**
978
+ * 生成自定义时间范围雪碧图
979
+ */
980
+ async generateCustomTimeRangeSprite(vendor, bucket, key, startTime, endTime, options = {}) {
981
+ try {
982
+ const startMs = this.convertTimeToMilliseconds(startTime);
983
+ const endMs = this.convertTimeToMilliseconds(endTime);
984
+ if (startMs >= endMs) {
985
+ throw new Error('Start time must be less than end time');
986
+ }
987
+ const duration = endMs - startMs;
988
+ const interval = options.interval ||
989
+ Math.max(5, Math.floor(duration / 1000 / 100)); // 默认间隔,最多100帧
990
+ const spriteOptions = {
991
+ startTime,
992
+ interval,
993
+ maxFrames: Math.min(100, Math.floor(duration / 1000 / interval)),
994
+ ...options,
995
+ };
996
+ return this.generateSprite(vendor, bucket, key, spriteOptions);
997
+ }
998
+ catch (error) {
999
+ this.logger.error('Failed to generate custom time range sprite', {
1000
+ vendor,
1001
+ bucket,
1002
+ key,
1003
+ startTime,
1004
+ endTime,
1005
+ error: (error instanceof Error ? error.message : String(error)),
1006
+ });
1007
+ throw new Error(`Custom time range sprite generation failed: ${(error instanceof Error ? error.message : String(error))}`);
1008
+ }
1009
+ }
1010
+ /**
1011
+ * 视频单帧截取
1012
+ * 参考阿里云OSS文档:https://help.aliyun.com/zh/oss/video-snapshots
1013
+ */
1014
+ async takeSnapshot(vendor, bucket, key, options = {}) {
1015
+ const { time = '00:00:01', width = 0, height = 0, format = 'jpg', quality = 90, } = options;
1016
+ try {
1017
+ // 验证参数
1018
+ this.validateSnapshotOptions(options);
1019
+ // 将时间格式转换为毫秒
1020
+ const timeInMs = this.convertTimeToMilliseconds(time);
1021
+ // 构建OSS处理参数,按照阿里云文档规范
1022
+ const processParams = [
1023
+ 'video/snapshot',
1024
+ `t_${timeInMs}`, // 截图时间(毫秒)
1025
+ `f_${format}`, // 输出格式
1026
+ width ? `w_${width}` : '', // 宽度
1027
+ height ? `h_${height}` : '', // 高度
1028
+ 'm_fast', // 快速模式,截取最近关键帧
1029
+ ];
1030
+ // 添加可选参数
1031
+ if (format === 'jpg' && quality !== 90) {
1032
+ processParams.push(`q_${quality}`); // JPG质量参数
1033
+ }
1034
+ // 过滤掉空的参数
1035
+ const filteredParams = processParams.filter((param) => param && param.trim() !== '');
1036
+ const process = filteredParams.join(',');
1037
+ console.log('process', process);
1038
+ // 生成截图文件名
1039
+ const snapshotKey = this.generateSnapshotKey(key, time, format);
1040
+ console.log('snapshotKey', snapshotKey);
1041
+ // 使用 ali-oss 直接处理,而不是构建URL
1042
+ const result = await this.executeOssProcessWithClient(vendor, bucket, key, process, snapshotKey);
1043
+ console.log('Snapshot generated successfully', {
1044
+ snapshotKey,
1045
+ process,
1046
+ time: timeInMs,
1047
+ format,
1048
+ dimensions: `${width}x${height}`,
1049
+ result: result,
1050
+ });
1051
+ // 返回处理后的文件路径,而不是URL
1052
+ return result?.res?.statusCode === 200 ? snapshotKey : '';
1053
+ }
1054
+ catch (error) {
1055
+ this.logger.error('Failed to generate snapshot', {
1056
+ vendor,
1057
+ bucket,
1058
+ key,
1059
+ options,
1060
+ error: (error instanceof Error ? error.message : String(error)),
1061
+ });
1062
+ throw new Error(`Snapshot generation failed: ${(error instanceof Error ? error.message : String(error))}`);
1063
+ }
1064
+ }
1065
+ /**
1066
+ * 验证截图参数
1067
+ */
1068
+ validateSnapshotOptions(options) {
1069
+ const { time, width, height, format, quality } = options;
1070
+ // 验证时间格式
1071
+ if (time && !this.isValidTimeFormat(time)) {
1072
+ throw new Error(`Invalid time format: ${time}. Expected format: HH:mm:ss or HH:mm:ss.SSS`);
1073
+ }
1074
+ // 验证尺寸
1075
+ if (width && (width < 0 || width > 4096)) {
1076
+ throw new Error(`Invalid width: ${width}. Must be between 0 and 4096`);
1077
+ }
1078
+ if (height && (height < 0 || height > 4096)) {
1079
+ throw new Error(`Invalid height: ${height}. Must be between 0 and 4096`);
1080
+ }
1081
+ // 验证格式
1082
+ if (format && !['jpg', 'png'].includes(format)) {
1083
+ throw new Error(`Invalid format: ${format}. Supported formats: jpg, png`);
1084
+ }
1085
+ // 验证质量(仅JPG格式)
1086
+ if (format === 'jpg' && quality && (quality < 1 || quality > 100)) {
1087
+ throw new Error(`Invalid quality: ${quality}. Must be between 1 and 100`);
1088
+ }
1089
+ }
1090
+ /**
1091
+ * 验证时间格式
1092
+ */
1093
+ isValidTimeFormat(time) {
1094
+ // 支持格式:HH:mm:ss 或 HH:mm:ss.SSS
1095
+ const timeRegex = /^(\d{2}):(\d{2}):(\d{2})(\.\d{3})?$/;
1096
+ if (!timeRegex.test(time)) {
1097
+ return false;
1098
+ }
1099
+ const match = time.match(timeRegex);
1100
+ if (!match)
1101
+ return false;
1102
+ const [, hours, minutes, seconds] = match;
1103
+ const h = parseInt(hours, 10);
1104
+ const m = parseInt(minutes, 10);
1105
+ const s = parseInt(seconds, 10);
1106
+ return h >= 0 && h <= 23 && m >= 0 && m <= 59 && s >= 0 && s <= 59;
1107
+ }
1108
+ /**
1109
+ * 将时间格式转换为毫秒
1110
+ */
1111
+ convertTimeToMilliseconds(time) {
1112
+ const timeRegex = /^(\d{2}):(\d{2}):(\d{2})(\.\d{3})?$/;
1113
+ const match = time.match(timeRegex);
1114
+ if (!match) {
1115
+ throw new Error(`Invalid time format: ${time}`);
1116
+ }
1117
+ const [, hours, minutes, seconds, milliseconds] = match;
1118
+ const h = parseInt(hours, 10);
1119
+ const m = parseInt(minutes, 10);
1120
+ const s = parseInt(seconds, 10);
1121
+ const ms = milliseconds ? parseInt(milliseconds.slice(1), 10) : 0;
1122
+ return (h * 3600 + m * 60 + s) * 1000 + ms;
1123
+ }
1124
+ /**
1125
+ * 生成截图文件名
1126
+ */
1127
+ generateSnapshotKey(originalKey, time, format) {
1128
+ const pathParts = originalKey.split('/');
1129
+ const fileName = pathParts.pop() || '';
1130
+ const basePath = pathParts.join('/');
1131
+ // 移除原文件扩展名
1132
+ const nameWithoutExt = fileName.replace(/\.[^/.]+$/, '');
1133
+ // 清理时间字符串,移除冒号和点号
1134
+ const cleanTime = time.replace(/[:.]/g, '');
1135
+ // 生成截图文件名
1136
+ const snapshotFileName = `${nameWithoutExt}_snapshot_${cleanTime}.${format}`;
1137
+ return basePath ? `${basePath}/${snapshotFileName}` : snapshotFileName;
1138
+ }
1139
+ /**
1140
+ * 获取视频头图(第一帧)
1141
+ */
1142
+ async getVideoThumbnail(vendor, bucket, key, options = {}) {
1143
+ const defaultOptions = {
1144
+ time: '00:00:00',
1145
+ format: 'jpg',
1146
+ quality: 85,
1147
+ };
1148
+ return this.takeSnapshot(vendor, bucket, key, {
1149
+ ...defaultOptions,
1150
+ ...options,
1151
+ });
1152
+ }
1153
+ /**
1154
+ * 批量截图 - 按时间间隔截取多个帧
1155
+ */
1156
+ async takeMultipleSnapshots(vendor, bucket, key, options = {}) {
1157
+ const { startTime = '00:00:00', endTime = '00:01:00', // 默认1分钟
1158
+ interval = 5, // 默认5秒间隔
1159
+ count = 12, // 默认12张
1160
+ width = 640, height = 360, format = 'jpg', quality = 85, } = options;
1161
+ try {
1162
+ const startMs = this.convertTimeToMilliseconds(startTime);
1163
+ const endMs = this.convertTimeToMilliseconds(endTime);
1164
+ if (startMs >= endMs) {
1165
+ throw new Error('Start time must be less than end time');
1166
+ }
1167
+ const duration = endMs - startMs;
1168
+ const actualInterval = Math.max(interval * 1000, duration / count);
1169
+ const actualCount = Math.min(count, Math.floor(duration / actualInterval));
1170
+ const snapshotUrls = [];
1171
+ const snapshotOptions = {
1172
+ width,
1173
+ height,
1174
+ format,
1175
+ quality,
1176
+ };
1177
+ for (let i = 0; i < actualCount; i++) {
1178
+ const timeMs = startMs + i * actualInterval;
1179
+ const timeStr = this.convertMillisecondsToTime(timeMs);
1180
+ const url = await this.takeSnapshot(vendor, bucket, key, {
1181
+ ...snapshotOptions,
1182
+ time: timeStr,
1183
+ });
1184
+ snapshotUrls.push(url);
1185
+ }
1186
+ this.logger.info('Multiple snapshots generated', {
1187
+ vendor,
1188
+ bucket,
1189
+ key,
1190
+ count: actualCount,
1191
+ interval: actualInterval / 1000,
1192
+ timeRange: `${startTime} - ${endTime}`,
1193
+ });
1194
+ return snapshotUrls;
1195
+ }
1196
+ catch (error) {
1197
+ this.logger.error('Failed to generate multiple snapshots', {
1198
+ vendor,
1199
+ bucket,
1200
+ key,
1201
+ options,
1202
+ error: (error instanceof Error ? error.message : String(error)),
1203
+ });
1204
+ throw new Error(`Multiple snapshots generation failed: ${(error instanceof Error ? error.message : String(error))}`);
1205
+ }
1206
+ }
1207
+ /**
1208
+ * 将毫秒转换为时间格式
1209
+ */
1210
+ convertMillisecondsToTime(ms) {
1211
+ const totalSeconds = Math.floor(ms / 1000);
1212
+ const hours = Math.floor(totalSeconds / 3600);
1213
+ const minutes = Math.floor((totalSeconds % 3600) / 60);
1214
+ const seconds = totalSeconds % 60;
1215
+ const milliseconds = ms % 1000;
1216
+ const timeStr = [
1217
+ hours.toString().padStart(2, '0'),
1218
+ minutes.toString().padStart(2, '0'),
1219
+ seconds.toString().padStart(2, '0'),
1220
+ ].join(':');
1221
+ return milliseconds > 0
1222
+ ? `${timeStr}.${milliseconds.toString().padStart(3, '0')}`
1223
+ : timeStr;
1224
+ }
1225
+ /**
1226
+ * 从视频中提取音频(使用 IMM 服务)
1227
+ */
1228
+ async extractAudioFromVideo(vendor, bucket, key, options) {
1229
+ try {
1230
+ this.logger.info('Extracting audio from video using IMM service', {
1231
+ vendor,
1232
+ bucket,
1233
+ key,
1234
+ options,
1235
+ });
1236
+ // 使用 IMM 服务提取音频
1237
+ const result = await this.aliyunImm.extractAudioFromVideo(vendor, bucket, key, options);
1238
+ this.logger.info('Audio extract task created successfully', {
1239
+ taskId: result.taskId,
1240
+ });
1241
+ return result;
1242
+ }
1243
+ catch (error) {
1244
+ this.logger.error('Failed to extract audio from video', {
1245
+ vendor,
1246
+ bucket,
1247
+ key,
1248
+ options,
1249
+ error: (error instanceof Error ? error.message : String(error)),
1250
+ });
1251
+ throw error;
1252
+ }
1253
+ }
1254
+ /**
1255
+ * 查询转码任务状态(使用 IMM 服务)
1256
+ */
1257
+ async getTranscodeTaskStatus(vendor, bucket, taskId) {
1258
+ try {
1259
+ this.logger.info('Querying transcode task status using IMM service', { taskId });
1260
+ // 使用 IMM 服务获取任务状态
1261
+ const status = await this.aliyunImm.getTask(vendor, bucket, taskId);
1262
+ this.logger.info('Task status retrieved successfully using IMM', {
1263
+ taskId,
1264
+ status: status.status,
1265
+ progress: status.progress,
1266
+ });
1267
+ return status;
1268
+ }
1269
+ catch (error) {
1270
+ this.logger.error('Failed to get transcode task status using IMM', {
1271
+ taskId,
1272
+ error: (error instanceof Error ? error.message : String(error)),
1273
+ });
1274
+ throw error;
1275
+ }
1276
+ }
1277
+ /**
1278
+ * 取消转码任务
1279
+ */
1280
+ async cancelTranscodeTask(vendor, taskId) {
1281
+ try {
1282
+ this.logger.info('Cancelling transcode task', { taskId });
1283
+ // 实际实现需要调用 IMM 的取消任务接口
1284
+ // const response = await this.immClient.cancelTask(taskId);
1285
+ return true;
1286
+ }
1287
+ catch (error) {
1288
+ this.logger.error('Failed to cancel transcode task', {
1289
+ taskId,
1290
+ error: (error instanceof Error ? error.message : String(error)),
1291
+ });
1292
+ return false;
1293
+ }
1294
+ }
1295
+ /**
1296
+ * 验证雪碧图参数
1297
+ */
1298
+ validateSpriteOptions(options) {
1299
+ const { width, height, interval, columns, lines, startTime, format, scaleType, padding, margin, maxFrames, percentWidth, percentHeight, } = options;
1300
+ // 验证尺寸
1301
+ if (width && (width < 0 || width > 4096)) {
1302
+ throw new Error(`Invalid width: ${width}. Must be between 0 and 4096`);
1303
+ }
1304
+ if (height && (height < 0 || height > 4096)) {
1305
+ throw new Error(`Invalid height: ${height}. Must be between 0 and 4096`);
1306
+ }
1307
+ // 验证间隔
1308
+ if (interval && (interval < 0 || interval > 3600)) {
1309
+ // 最大间隔1小时
1310
+ throw new Error(`Invalid interval: ${interval}. Must be between 0 and 3600`);
1311
+ }
1312
+ // 验证布局
1313
+ if (columns && (columns < 0 || columns > 100)) {
1314
+ // 最大列数100
1315
+ throw new Error(`Invalid columns: ${columns}. Must be between 0 and 100`);
1316
+ }
1317
+ if (lines && (lines < 0 || lines > 100)) {
1318
+ // 最大行数100
1319
+ throw new Error(`Invalid lines: ${lines}. Must be between 0 and 100`);
1320
+ }
1321
+ // 验证缩放方式
1322
+ if (scaleType &&
1323
+ !['crop', 'stretch', 'fill', 'fit'].includes(scaleType)) {
1324
+ throw new Error(`Invalid scaleType: ${scaleType}. Supported: crop, stretch, fill, fit`);
1325
+ }
1326
+ // 验证百分比尺寸
1327
+ if (percentWidth && (percentWidth <= 0 || percentWidth > 200)) {
1328
+ throw new Error(`Invalid percentWidth: ${percentWidth}. Must be between 0 and 200`);
1329
+ }
1330
+ if (percentHeight && (percentHeight <= 0 || percentHeight > 200)) {
1331
+ throw new Error(`Invalid percentHeight: ${percentHeight}. Must be between 0 and 200`);
1332
+ }
1333
+ // 验证起始时间
1334
+ if (startTime && !this.isValidTimeFormat(startTime)) {
1335
+ throw new Error(`Invalid startTime: ${startTime}. Expected format: HH:mm:ss or HH:mm:ss.SSS`);
1336
+ }
1337
+ // 验证格式
1338
+ if (format && !['jpg', 'png'].includes(format)) {
1339
+ throw new Error(`Invalid format: ${format}. Supported formats: jpg, png`);
1340
+ }
1341
+ // 验证最大帧数
1342
+ if (maxFrames && (maxFrames <= 0 || maxFrames > 1000)) {
1343
+ // 最大帧数1000
1344
+ throw new Error(`Invalid maxFrames: ${maxFrames}. Must be between 0 and 1000`);
1345
+ }
1346
+ }
1347
+ /**
1348
+ * 生成雪碧图文件名
1349
+ */
1350
+ generateSpriteKey(originalKey, format, startTime) {
1351
+ const pathParts = originalKey.split('/');
1352
+ const fileName = pathParts.pop() || '';
1353
+ const basePath = pathParts.join('/');
1354
+ // 移除原文件扩展名
1355
+ const nameWithoutExt = fileName.replace(/\.[^/.]+$/, '');
1356
+ // 清理时间字符串,移除冒号和点号
1357
+ const cleanStartTime = startTime.replace(/[:.]/g, '');
1358
+ // 生成雪碧图文件名
1359
+ const spriteFileName = `${nameWithoutExt}_sprite_${cleanStartTime}.${format}`;
1360
+ return basePath ? `${basePath}/${spriteFileName}` : spriteFileName;
1361
+ }
1362
+ };
1363
+ exports.AliyunOssTranscodeClient = AliyunOssTranscodeClient;
1364
+ exports.AliyunOssTranscodeClient = AliyunOssTranscodeClient = __decorate([
1365
+ (0, common_1.Injectable)(),
1366
+ __param(1, (0, common_1.Inject)(nest_winston_1.WINSTON_MODULE_PROVIDER)),
1367
+ __metadata("design:paramtypes", [config_1.ConfigService,
1368
+ winston_1.Logger,
1369
+ aliyun_imm_client_1.AliyunImmClient,
1370
+ axios_1.HttpService])
1371
+ ], AliyunOssTranscodeClient);
1372
+ //# sourceMappingURL=aliyun-oss-transcode.client.js.map