video-generator.controller.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. "use strict";
  2. /**
  3. * 视频生成模块 - API 路由控制器
  4. */
  5. var __importDefault = (this && this.__importDefault) || function (mod) {
  6. return (mod && mod.__esModule) ? mod : { "default": mod };
  7. };
  8. Object.defineProperty(exports, "__esModule", { value: true });
  9. const router_1 = __importDefault(require("@koa/router"));
  10. const video_generator_service_1 = require("./video-generator.service");
  11. const router = new router_1.default();
  12. // ============ 视频项目管理 ============
  13. /**
  14. * GET /api/video/projects
  15. * 获取视频项目列表
  16. */
  17. router.get('/projects', async (ctx) => {
  18. const query = {
  19. userId: ctx.query.userId ? Number(ctx.query.userId) : undefined,
  20. status: ctx.query.status,
  21. page: ctx.query.page ? Number(ctx.query.page) : 1,
  22. pageSize: ctx.query.pageSize ? Number(ctx.query.pageSize) : 10,
  23. };
  24. const result = await (0, video_generator_service_1.getVideoProjects)(query);
  25. ctx.body = { success: true, data: result };
  26. });
  27. /**
  28. * POST /api/video/projects
  29. * 创建视频项目
  30. */
  31. router.post('/projects', async (ctx) => {
  32. const body = ctx.request.body;
  33. const userId = ctx.state.user?.id;
  34. const project = await (0, video_generator_service_1.createVideoProject)(body, userId);
  35. ctx.body = { success: true, data: project };
  36. });
  37. /**
  38. * GET /api/video/projects/:id
  39. * 获取视频项目详情
  40. */
  41. router.get('/projects/:id', async (ctx) => {
  42. const id = Number(ctx.params.id);
  43. const project = await (0, video_generator_service_1.getVideoProject)(id);
  44. if (!project) {
  45. ctx.status = 404;
  46. ctx.body = { success: false, error: '项目不存在' };
  47. return;
  48. }
  49. ctx.body = { success: true, data: project };
  50. });
  51. /**
  52. * PUT /api/video/projects/:id
  53. * 更新视频项目
  54. */
  55. router.put('/projects/:id', async (ctx) => {
  56. const id = Number(ctx.params.id);
  57. const body = ctx.request.body;
  58. const project = await (0, video_generator_service_1.updateVideoProject)(id, body);
  59. if (!project) {
  60. ctx.status = 404;
  61. ctx.body = { success: false, error: '项目不存在' };
  62. return;
  63. }
  64. ctx.body = { success: true, data: project };
  65. });
  66. /**
  67. * DELETE /api/video/projects/:id
  68. * 删除视频项目
  69. */
  70. router.delete('/projects/:id', async (ctx) => {
  71. const id = Number(ctx.params.id);
  72. const success = await (0, video_generator_service_1.deleteVideoProject)(id);
  73. if (!success) {
  74. ctx.status = 404;
  75. ctx.body = { success: false, error: '项目不存在' };
  76. return;
  77. }
  78. ctx.body = { success: true };
  79. });
  80. // ============ 视频生成 ============
  81. /**
  82. * POST /api/video/projects/:id/generate
  83. * 开始生成视频
  84. */
  85. router.post('/projects/:id/generate', async (ctx) => {
  86. const id = Number(ctx.params.id);
  87. const result = await (0, video_generator_service_1.generateVideoForProject)(id);
  88. if (!result.success) {
  89. ctx.status = 400;
  90. ctx.body = { success: false, error: result.error };
  91. return;
  92. }
  93. ctx.body = {
  94. success: true,
  95. data: {
  96. outputUrl: result.outputUrl,
  97. duration: result.duration,
  98. fileSize: result.fileSize,
  99. },
  100. };
  101. });
  102. /**
  103. * GET /api/video/projects/:id/status
  104. * 获取生成状态
  105. */
  106. router.get('/projects/:id/status', async (ctx) => {
  107. const id = Number(ctx.params.id);
  108. const status = await (0, video_generator_service_1.getGenerateProgress)(id);
  109. ctx.body = { success: true, data: status };
  110. });
  111. // ============ 素材管理 ============
  112. /**
  113. * GET /api/video/materials
  114. * 获取素材列表
  115. */
  116. router.get('/materials', async (ctx) => {
  117. const query = {
  118. userId: ctx.query.userId ? Number(ctx.query.userId) : undefined,
  119. type: ctx.query.type,
  120. category: ctx.query.category,
  121. page: ctx.query.page ? Number(ctx.query.page) : 1,
  122. pageSize: ctx.query.pageSize ? Number(ctx.query.pageSize) : 20,
  123. };
  124. const result = await (0, video_generator_service_1.getMaterials)(query);
  125. ctx.body = { success: true, data: result };
  126. });
  127. /**
  128. * POST /api/video/materials/upload
  129. * 上传素材(处理 multipart/form-data 文件上传)
  130. */
  131. router.post('/materials/upload', async (ctx) => {
  132. const userId = ctx.state.user?.id;
  133. // 处理 multipart form data
  134. const body = ctx.request.body;
  135. const files = ctx.request.files;
  136. // 获取上传的文件
  137. const file = files?.file;
  138. let materialUrl = '';
  139. if (file) {
  140. // 文件已上传,url 就是文件的路径
  141. materialUrl = `/uploads/materials/${file.newFilename || file.filename}`;
  142. }
  143. else if (body.url) {
  144. // 如果没有文件,使用传入的url
  145. materialUrl = body.url;
  146. }
  147. else {
  148. ctx.status = 400;
  149. ctx.body = { success: false, error: 'No file uploaded' };
  150. return;
  151. }
  152. const material = await (0, video_generator_service_1.uploadMaterial)({
  153. type: body.type || 'image',
  154. name: body.name || file?.newFilename || 'unnamed',
  155. url: materialUrl,
  156. thumbnail: body.thumbnail,
  157. tags: body.tags ? JSON.parse(body.tags) : [],
  158. category: body.category,
  159. duration: body.duration ? Number(body.duration) : undefined,
  160. size: body.size ? Number(body.size) : undefined,
  161. width: body.width ? Number(body.width) : undefined,
  162. height: body.height ? Number(body.height) : undefined,
  163. }, userId);
  164. ctx.body = { success: true, data: material };
  165. });
  166. /**
  167. * DELETE /api/video/materials/:id
  168. * 删除素材
  169. */
  170. router.delete('/materials/:id', async (ctx) => {
  171. const id = Number(ctx.params.id);
  172. const success = await (0, video_generator_service_1.deleteMaterial)(id);
  173. if (!success) {
  174. ctx.status = 404;
  175. ctx.body = { success: false, error: '素材不存在' };
  176. return;
  177. }
  178. ctx.body = { success: true };
  179. });
  180. // ============ 快捷入口 ============
  181. /**
  182. * POST /api/video/books/:bookId/generate
  183. * 从书籍生成视频项目
  184. */
  185. router.post('/books/:bookId/generate', async (ctx) => {
  186. const bookId = Number(ctx.params.bookId);
  187. const userId = ctx.state.user?.id;
  188. const project = await (0, video_generator_service_1.createVideoProjectFromBook)(bookId, userId);
  189. if (!project) {
  190. ctx.status = 404;
  191. ctx.body = { success: false, error: '书籍不存在' };
  192. return;
  193. }
  194. ctx.body = { success: true, data: project };
  195. });
  196. exports.default = router;